1pub use super::v3::GetWeight;
20use super::{
21 v3::{
22 Instruction as OldInstruction, PalletInfo as OldPalletInfo,
23 QueryResponseInfo as OldQueryResponseInfo, Response as OldResponse, Xcm as OldXcm,
24 },
25 v5::{
26 Instruction as NewInstruction, PalletInfo as NewPalletInfo,
27 QueryResponseInfo as NewQueryResponseInfo, Response as NewResponse, Xcm as NewXcm,
28 },
29};
30use crate::{utils::decode_xcm_instructions, DoubleEncoded};
31use alloc::{vec, vec::Vec};
32use bounded_collections::{parameter_types, BoundedVec};
33use codec::{
34 self, Decode, DecodeWithMemTracking, Encode, Error as CodecError, Input as CodecInput,
35 MaxEncodedLen,
36};
37use core::{fmt::Debug, result};
38use derive_where::derive_where;
39use frame_support::dispatch::GetDispatchInfo;
40use scale_info::TypeInfo;
41
42mod asset;
43mod junction;
44pub(crate) mod junctions;
45mod location;
46mod traits;
47
48pub use asset::{
49 Asset, AssetFilter, AssetId, AssetInstance, Assets, Fungibility, WildAsset, WildFungibility,
50 MAX_ITEMS_IN_ASSETS,
51};
52pub use junction::{BodyId, BodyPart, Junction, NetworkId};
53pub use junctions::Junctions;
54pub use location::{Ancestor, AncestorThen, InteriorLocation, Location, Parent, ParentThen};
55pub use traits::{
56 send_xcm, validate_send, Error, ExecuteXcm, Outcome, PreparedMessage, Reanchorable, Result,
57 SendError, SendResult, SendXcm, Weight, XcmHash,
58};
59pub use super::v3::{MaxDispatchErrorLen, MaybeErrorCode, OriginKind, WeightLimit};
61
62pub const VERSION: super::Version = 4;
64
65pub type QueryId = u64;
67
68#[derive(Default, Encode, DecodeWithMemTracking, TypeInfo)]
69#[derive_where(Clone, Eq, PartialEq, Debug)]
70#[codec(encode_bound())]
71#[codec(decode_with_mem_tracking_bound(Call: Decode))]
72#[scale_info(bounds(), skip_type_params(Call))]
73pub struct Xcm<Call>(pub Vec<Instruction<Call>>);
74
75impl<Call> Decode for Xcm<Call>
76where
77 Call: Decode,
78{
79 fn decode<I: CodecInput>(input: &mut I) -> core::result::Result<Self, CodecError> {
80 Ok(Xcm(decode_xcm_instructions(input)?))
81 }
82}
83
84impl<Call> Xcm<Call> {
85 pub fn new() -> Self {
87 Self(vec![])
88 }
89
90 pub fn is_empty(&self) -> bool {
92 self.0.is_empty()
93 }
94
95 pub fn len(&self) -> usize {
97 self.0.len()
98 }
99
100 pub fn inner(&self) -> &[Instruction<Call>] {
102 &self.0
103 }
104
105 pub fn inner_mut(&mut self) -> &mut Vec<Instruction<Call>> {
107 &mut self.0
108 }
109
110 pub fn into_inner(self) -> Vec<Instruction<Call>> {
112 self.0
113 }
114
115 pub fn iter(&self) -> impl Iterator<Item = &Instruction<Call>> {
117 self.0.iter()
118 }
119
120 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Instruction<Call>> {
122 self.0.iter_mut()
123 }
124
125 pub fn into_iter(self) -> impl Iterator<Item = Instruction<Call>> {
127 self.0.into_iter()
128 }
129
130 pub fn or_else(self, f: impl FnOnce() -> Self) -> Self {
133 if self.0.is_empty() {
134 f()
135 } else {
136 self
137 }
138 }
139
140 pub fn first(&self) -> Option<&Instruction<Call>> {
142 self.0.first()
143 }
144
145 pub fn last(&self) -> Option<&Instruction<Call>> {
147 self.0.last()
148 }
149
150 pub fn only(&self) -> Option<&Instruction<Call>> {
152 if self.0.len() == 1 {
153 self.0.first()
154 } else {
155 None
156 }
157 }
158
159 pub fn into_only(mut self) -> core::result::Result<Instruction<Call>, Self> {
162 if self.0.len() == 1 {
163 self.0.pop().ok_or(self)
164 } else {
165 Err(self)
166 }
167 }
168}
169
170impl<Call> From<Vec<Instruction<Call>>> for Xcm<Call> {
171 fn from(c: Vec<Instruction<Call>>) -> Self {
172 Self(c)
173 }
174}
175
176impl<Call> From<Xcm<Call>> for Vec<Instruction<Call>> {
177 fn from(c: Xcm<Call>) -> Self {
178 c.0
179 }
180}
181
182pub mod prelude {
184 mod contents {
185 pub use super::super::{
186 send_xcm, validate_send, Ancestor, AncestorThen, Asset,
187 AssetFilter::{self, *},
188 AssetId,
189 AssetInstance::{self, *},
190 Assets, BodyId, BodyPart, Error as XcmError, ExecuteXcm,
191 Fungibility::{self, *},
192 Instruction::*,
193 InteriorLocation,
194 Junction::{self, *},
195 Junctions::{self, Here},
196 Location, MaybeErrorCode,
197 NetworkId::{self, *},
198 OriginKind, Outcome, PalletInfo, Parent, ParentThen, PreparedMessage, QueryId,
199 QueryResponseInfo, Reanchorable, Response, Result as XcmResult, SendError, SendResult,
200 SendXcm, Weight,
201 WeightLimit::{self, *},
202 WildAsset::{self, *},
203 WildFungibility::{self, Fungible as WildFungible, NonFungible as WildNonFungible},
204 XcmContext, XcmHash, XcmWeightInfo, VERSION as XCM_VERSION,
205 };
206 }
207 pub use super::{Instruction, Xcm};
208 pub use contents::*;
209 pub mod opaque {
210 pub use super::{
211 super::opaque::{Instruction, Xcm},
212 contents::*,
213 };
214 }
215}
216
217parameter_types! {
218 pub MaxPalletNameLen: u32 = 48;
219 pub MaxPalletsInfo: u32 = 64;
220}
221
222#[derive(
223 Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo, MaxEncodedLen,
224)]
225pub struct PalletInfo {
226 #[codec(compact)]
227 pub index: u32,
228 pub name: BoundedVec<u8, MaxPalletNameLen>,
229 pub module_name: BoundedVec<u8, MaxPalletNameLen>,
230 #[codec(compact)]
231 pub major: u32,
232 #[codec(compact)]
233 pub minor: u32,
234 #[codec(compact)]
235 pub patch: u32,
236}
237
238impl TryInto<OldPalletInfo> for PalletInfo {
239 type Error = ();
240
241 fn try_into(self) -> result::Result<OldPalletInfo, Self::Error> {
242 OldPalletInfo::new(
243 self.index,
244 self.name.into_inner(),
245 self.module_name.into_inner(),
246 self.major,
247 self.minor,
248 self.patch,
249 )
250 .map_err(|_| ())
251 }
252}
253
254impl TryInto<NewPalletInfo> for PalletInfo {
255 type Error = ();
256
257 fn try_into(self) -> result::Result<NewPalletInfo, Self::Error> {
258 NewPalletInfo::new(
259 self.index,
260 self.name.into_inner(),
261 self.module_name.into_inner(),
262 self.major,
263 self.minor,
264 self.patch,
265 )
266 .map_err(|_| ())
267 }
268}
269
270impl PalletInfo {
271 pub fn new(
272 index: u32,
273 name: Vec<u8>,
274 module_name: Vec<u8>,
275 major: u32,
276 minor: u32,
277 patch: u32,
278 ) -> result::Result<Self, Error> {
279 let name = BoundedVec::try_from(name).map_err(|_| Error::Overflow)?;
280 let module_name = BoundedVec::try_from(module_name).map_err(|_| Error::Overflow)?;
281
282 Ok(Self { index, name, module_name, major, minor, patch })
283 }
284}
285
286#[derive(
288 Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo, MaxEncodedLen,
289)]
290pub enum Response {
291 Null,
293 Assets(Assets),
295 ExecutionResult(Option<(u32, Error)>),
297 Version(super::Version),
299 PalletsInfo(BoundedVec<PalletInfo, MaxPalletsInfo>),
301 DispatchResult(MaybeErrorCode),
303}
304
305impl Default for Response {
306 fn default() -> Self {
307 Self::Null
308 }
309}
310
311impl TryFrom<OldResponse> for Response {
312 type Error = ();
313
314 fn try_from(old: OldResponse) -> result::Result<Self, Self::Error> {
315 use OldResponse::*;
316 Ok(match old {
317 Null => Self::Null,
318 Assets(assets) => Self::Assets(assets.try_into()?),
319 ExecutionResult(result) => {
320 Self::ExecutionResult(result.map(|(num, old_error)| (num, old_error.into())))
321 },
322 Version(version) => Self::Version(version),
323 PalletsInfo(pallet_info) => {
324 let inner = pallet_info
325 .into_iter()
326 .map(TryInto::try_into)
327 .collect::<result::Result<Vec<_>, _>>()?;
328 Self::PalletsInfo(
329 BoundedVec::<PalletInfo, MaxPalletsInfo>::try_from(inner).map_err(|_| ())?,
330 )
331 },
332 DispatchResult(maybe_error) => Self::DispatchResult(maybe_error),
333 })
334 }
335}
336
337impl TryFrom<NewResponse> for Response {
338 type Error = ();
339
340 fn try_from(new: NewResponse) -> result::Result<Self, Self::Error> {
341 use NewResponse::*;
342 Ok(match new {
343 Null => Self::Null,
344 Assets(assets) => Self::Assets(assets.try_into()?),
345 ExecutionResult(result) => Self::ExecutionResult(
346 result
347 .map(|(num, new_error)| (num, new_error.try_into()))
348 .map(|(num, result)| result.map(|inner| (num, inner)))
349 .transpose()?,
350 ),
351 Version(version) => Self::Version(version),
352 PalletsInfo(pallet_info) => {
353 let inner = pallet_info
354 .into_iter()
355 .map(TryInto::try_into)
356 .collect::<result::Result<Vec<_>, _>>()?;
357 Self::PalletsInfo(
358 BoundedVec::<PalletInfo, MaxPalletsInfo>::try_from(inner).map_err(|_| ())?,
359 )
360 },
361 DispatchResult(maybe_error) => {
362 Self::DispatchResult(maybe_error.try_into().map_err(|_| ())?)
363 },
364 })
365 }
366}
367
368#[derive(Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo)]
370pub struct QueryResponseInfo {
371 pub destination: Location,
373 #[codec(compact)]
375 pub query_id: QueryId,
376 pub max_weight: Weight,
378}
379
380impl TryFrom<NewQueryResponseInfo> for QueryResponseInfo {
381 type Error = ();
382
383 fn try_from(new: NewQueryResponseInfo) -> result::Result<Self, Self::Error> {
384 Ok(Self {
385 destination: new.destination.try_into()?,
386 query_id: new.query_id,
387 max_weight: new.max_weight,
388 })
389 }
390}
391
392impl TryFrom<OldQueryResponseInfo> for QueryResponseInfo {
393 type Error = ();
394
395 fn try_from(old: OldQueryResponseInfo) -> result::Result<Self, Self::Error> {
396 Ok(Self {
397 destination: old.destination.try_into()?,
398 query_id: old.query_id,
399 max_weight: old.max_weight,
400 })
401 }
402}
403
404#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)]
406pub struct XcmContext {
407 pub origin: Option<Location>,
409 pub message_id: XcmHash,
412 pub topic: Option<[u8; 32]>,
414}
415
416impl XcmContext {
417 pub fn with_message_id(message_id: XcmHash) -> XcmContext {
420 XcmContext { origin: None, message_id, topic: None }
421 }
422}
423
424#[derive(
433 Encode,
434 Decode,
435 DecodeWithMemTracking,
436 TypeInfo,
437 xcm_procedural::XcmWeightInfoTrait,
438 xcm_procedural::Builder,
439)]
440#[derive_where(Clone, Eq, PartialEq, Debug)]
441#[codec(encode_bound())]
442#[codec(decode_bound(Call: Decode))]
443#[codec(decode_with_mem_tracking_bound(Call: Decode))]
444#[scale_info(bounds(), skip_type_params(Call))]
445pub enum Instruction<Call> {
446 #[builder(loads_holding)]
455 WithdrawAsset(Assets),
456
457 #[builder(loads_holding)]
469 ReserveAssetDeposited(Assets),
470
471 #[builder(loads_holding)]
483 ReceiveTeleportedAsset(Assets),
484
485 QueryResponse {
503 #[codec(compact)]
504 query_id: QueryId,
505 response: Response,
506 max_weight: Weight,
507 querier: Option<Location>,
508 },
509
510 TransferAsset { assets: Assets, beneficiary: Location },
522
523 TransferReserveAsset { assets: Assets, dest: Location, xcm: Xcm<()> },
542
543 Transact { origin_kind: OriginKind, require_weight_at_most: Weight, call: DoubleEncoded<Call> },
559
560 HrmpNewChannelOpenRequest {
572 #[codec(compact)]
573 sender: u32,
574 #[codec(compact)]
575 max_message_size: u32,
576 #[codec(compact)]
577 max_capacity: u32,
578 },
579
580 HrmpChannelAccepted {
590 #[codec(compact)]
593 recipient: u32,
594 },
595
596 HrmpChannelClosing {
607 #[codec(compact)]
608 initiator: u32,
609 #[codec(compact)]
610 sender: u32,
611 #[codec(compact)]
612 recipient: u32,
613 },
614
615 ClearOrigin,
627
628 DescendOrigin(InteriorLocation),
634
635 ReportError(QueryResponseInfo),
645
646 DepositAsset { assets: AssetFilter, beneficiary: Location },
656
657 DepositReserveAsset { assets: AssetFilter, dest: Location, xcm: Xcm<()> },
674
675 ExchangeAsset { give: AssetFilter, want: Assets, maximal: bool },
691
692 InitiateReserveWithdraw { assets: AssetFilter, reserve: Location, xcm: Xcm<()> },
707
708 InitiateTeleport { assets: AssetFilter, dest: Location, xcm: Xcm<()> },
723
724 ReportHolding { response_info: QueryResponseInfo, assets: AssetFilter },
737
738 #[builder(pays_fees)]
750 BuyExecution { fees: Asset, weight_limit: WeightLimit },
751
752 RefundSurplus,
758
759 SetErrorHandler(Xcm<Call>),
774
775 SetAppendix(Xcm<Call>),
790
791 ClearError,
797
798 #[builder(loads_holding)]
809 ClaimAsset { assets: Assets, ticket: Location },
810
811 Trap(#[codec(compact)] u64),
818
819 SubscribeVersion {
832 #[codec(compact)]
833 query_id: QueryId,
834 max_response_weight: Weight,
835 },
836
837 UnsubscribeVersion,
843
844 BurnAsset(Assets),
854
855 ExpectAsset(Assets),
862
863 ExpectOrigin(Option<Location>),
870
871 ExpectError(Option<(u32, Error)>),
878
879 ExpectTransactStatus(MaybeErrorCode),
888
889 QueryPallet { module_name: Vec<u8>, response_info: QueryResponseInfo },
904
905 ExpectPallet {
924 #[codec(compact)]
925 index: u32,
926 name: Vec<u8>,
927 module_name: Vec<u8>,
928 #[codec(compact)]
929 crate_major: u32,
930 #[codec(compact)]
931 min_crate_minor: u32,
932 },
933
934 ReportTransactStatus(QueryResponseInfo),
946
947 ClearTransactStatus,
955
956 UniversalOrigin(Junction),
970
971 ExportMessage { network: NetworkId, destination: InteriorLocation, xcm: Xcm<()> },
991
992 LockAsset { asset: Asset, unlocker: Location },
1007
1008 UnlockAsset { asset: Asset, target: Location },
1020
1021 NoteUnlockable { asset: Asset, owner: Location },
1035
1036 RequestUnlock { asset: Asset, locker: Location },
1049
1050 SetFeesMode { jit_withdraw: bool },
1059
1060 SetTopic([u8; 32]),
1072
1073 ClearTopic,
1079
1080 AliasOrigin(Location),
1086
1087 UnpaidExecution { weight_limit: WeightLimit, check_origin: Option<Location> },
1098}
1099
1100impl<Call> Xcm<Call> {
1101 pub fn into<C>(self) -> Xcm<C> {
1102 Xcm::from(self)
1103 }
1104 pub fn from<C>(xcm: Xcm<C>) -> Self {
1105 Self(xcm.0.into_iter().map(Instruction::<Call>::from).collect())
1106 }
1107}
1108
1109impl<Call> Instruction<Call> {
1110 pub fn into<C>(self) -> Instruction<C> {
1111 Instruction::from(self)
1112 }
1113 pub fn from<C>(xcm: Instruction<C>) -> Self {
1114 use Instruction::*;
1115 match xcm {
1116 WithdrawAsset(assets) => WithdrawAsset(assets),
1117 ReserveAssetDeposited(assets) => ReserveAssetDeposited(assets),
1118 ReceiveTeleportedAsset(assets) => ReceiveTeleportedAsset(assets),
1119 QueryResponse { query_id, response, max_weight, querier } => {
1120 QueryResponse { query_id, response, max_weight, querier }
1121 },
1122 TransferAsset { assets, beneficiary } => TransferAsset { assets, beneficiary },
1123 TransferReserveAsset { assets, dest, xcm } => {
1124 TransferReserveAsset { assets, dest, xcm }
1125 },
1126 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => {
1127 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity }
1128 },
1129 HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient },
1130 HrmpChannelClosing { initiator, sender, recipient } => {
1131 HrmpChannelClosing { initiator, sender, recipient }
1132 },
1133 Transact { origin_kind, require_weight_at_most, call } => {
1134 Transact { origin_kind, require_weight_at_most, call: call.transmute_encoded() }
1135 },
1136 ReportError(response_info) => ReportError(response_info),
1137 DepositAsset { assets, beneficiary } => DepositAsset { assets, beneficiary },
1138 DepositReserveAsset { assets, dest, xcm } => DepositReserveAsset { assets, dest, xcm },
1139 ExchangeAsset { give, want, maximal } => ExchangeAsset { give, want, maximal },
1140 InitiateReserveWithdraw { assets, reserve, xcm } => {
1141 InitiateReserveWithdraw { assets, reserve, xcm }
1142 },
1143 InitiateTeleport { assets, dest, xcm } => InitiateTeleport { assets, dest, xcm },
1144 ReportHolding { response_info, assets } => ReportHolding { response_info, assets },
1145 BuyExecution { fees, weight_limit } => BuyExecution { fees, weight_limit },
1146 ClearOrigin => ClearOrigin,
1147 DescendOrigin(who) => DescendOrigin(who),
1148 RefundSurplus => RefundSurplus,
1149 SetErrorHandler(xcm) => SetErrorHandler(xcm.into()),
1150 SetAppendix(xcm) => SetAppendix(xcm.into()),
1151 ClearError => ClearError,
1152 ClaimAsset { assets, ticket } => ClaimAsset { assets, ticket },
1153 Trap(code) => Trap(code),
1154 SubscribeVersion { query_id, max_response_weight } => {
1155 SubscribeVersion { query_id, max_response_weight }
1156 },
1157 UnsubscribeVersion => UnsubscribeVersion,
1158 BurnAsset(assets) => BurnAsset(assets),
1159 ExpectAsset(assets) => ExpectAsset(assets),
1160 ExpectOrigin(origin) => ExpectOrigin(origin),
1161 ExpectError(error) => ExpectError(error),
1162 ExpectTransactStatus(transact_status) => ExpectTransactStatus(transact_status),
1163 QueryPallet { module_name, response_info } => {
1164 QueryPallet { module_name, response_info }
1165 },
1166 ExpectPallet { index, name, module_name, crate_major, min_crate_minor } => {
1167 ExpectPallet { index, name, module_name, crate_major, min_crate_minor }
1168 },
1169 ReportTransactStatus(response_info) => ReportTransactStatus(response_info),
1170 ClearTransactStatus => ClearTransactStatus,
1171 UniversalOrigin(j) => UniversalOrigin(j),
1172 ExportMessage { network, destination, xcm } => {
1173 ExportMessage { network, destination, xcm }
1174 },
1175 LockAsset { asset, unlocker } => LockAsset { asset, unlocker },
1176 UnlockAsset { asset, target } => UnlockAsset { asset, target },
1177 NoteUnlockable { asset, owner } => NoteUnlockable { asset, owner },
1178 RequestUnlock { asset, locker } => RequestUnlock { asset, locker },
1179 SetFeesMode { jit_withdraw } => SetFeesMode { jit_withdraw },
1180 SetTopic(topic) => SetTopic(topic),
1181 ClearTopic => ClearTopic,
1182 AliasOrigin(location) => AliasOrigin(location),
1183 UnpaidExecution { weight_limit, check_origin } => {
1184 UnpaidExecution { weight_limit, check_origin }
1185 },
1186 }
1187 }
1188}
1189
1190impl<Call, W: XcmWeightInfo<Call>> GetWeight<W> for Instruction<Call> {
1192 fn weight(&self) -> Weight {
1193 use Instruction::*;
1194 match self {
1195 WithdrawAsset(assets) => W::withdraw_asset(assets),
1196 ReserveAssetDeposited(assets) => W::reserve_asset_deposited(assets),
1197 ReceiveTeleportedAsset(assets) => W::receive_teleported_asset(assets),
1198 QueryResponse { query_id, response, max_weight, querier } => {
1199 W::query_response(query_id, response, max_weight, querier)
1200 },
1201 TransferAsset { assets, beneficiary } => W::transfer_asset(assets, beneficiary),
1202 TransferReserveAsset { assets, dest, xcm } => {
1203 W::transfer_reserve_asset(&assets, dest, xcm)
1204 },
1205 Transact { origin_kind, require_weight_at_most, call } => {
1206 W::transact(origin_kind, require_weight_at_most, call)
1207 },
1208 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => {
1209 W::hrmp_new_channel_open_request(sender, max_message_size, max_capacity)
1210 },
1211 HrmpChannelAccepted { recipient } => W::hrmp_channel_accepted(recipient),
1212 HrmpChannelClosing { initiator, sender, recipient } => {
1213 W::hrmp_channel_closing(initiator, sender, recipient)
1214 },
1215 ClearOrigin => W::clear_origin(),
1216 DescendOrigin(who) => W::descend_origin(who),
1217 ReportError(response_info) => W::report_error(&response_info),
1218 DepositAsset { assets, beneficiary } => W::deposit_asset(assets, beneficiary),
1219 DepositReserveAsset { assets, dest, xcm } => {
1220 W::deposit_reserve_asset(assets, dest, xcm)
1221 },
1222 ExchangeAsset { give, want, maximal } => W::exchange_asset(give, want, maximal),
1223 InitiateReserveWithdraw { assets, reserve, xcm } => {
1224 W::initiate_reserve_withdraw(assets, reserve, xcm)
1225 },
1226 InitiateTeleport { assets, dest, xcm } => W::initiate_teleport(assets, dest, xcm),
1227 ReportHolding { response_info, assets } => W::report_holding(&response_info, &assets),
1228 BuyExecution { fees, weight_limit } => W::buy_execution(fees, weight_limit),
1229 RefundSurplus => W::refund_surplus(),
1230 SetErrorHandler(xcm) => W::set_error_handler(xcm),
1231 SetAppendix(xcm) => W::set_appendix(xcm),
1232 ClearError => W::clear_error(),
1233 ClaimAsset { assets, ticket } => W::claim_asset(assets, ticket),
1234 Trap(code) => W::trap(code),
1235 SubscribeVersion { query_id, max_response_weight } => {
1236 W::subscribe_version(query_id, max_response_weight)
1237 },
1238 UnsubscribeVersion => W::unsubscribe_version(),
1239 BurnAsset(assets) => W::burn_asset(assets),
1240 ExpectAsset(assets) => W::expect_asset(assets),
1241 ExpectOrigin(origin) => W::expect_origin(origin),
1242 ExpectError(error) => W::expect_error(error),
1243 ExpectTransactStatus(transact_status) => W::expect_transact_status(transact_status),
1244 QueryPallet { module_name, response_info } => {
1245 W::query_pallet(module_name, response_info)
1246 },
1247 ExpectPallet { index, name, module_name, crate_major, min_crate_minor } => {
1248 W::expect_pallet(index, name, module_name, crate_major, min_crate_minor)
1249 },
1250 ReportTransactStatus(response_info) => W::report_transact_status(response_info),
1251 ClearTransactStatus => W::clear_transact_status(),
1252 UniversalOrigin(j) => W::universal_origin(j),
1253 ExportMessage { network, destination, xcm } => {
1254 W::export_message(network, destination, xcm)
1255 },
1256 LockAsset { asset, unlocker } => W::lock_asset(asset, unlocker),
1257 UnlockAsset { asset, target } => W::unlock_asset(asset, target),
1258 NoteUnlockable { asset, owner } => W::note_unlockable(asset, owner),
1259 RequestUnlock { asset, locker } => W::request_unlock(asset, locker),
1260 SetFeesMode { jit_withdraw } => W::set_fees_mode(jit_withdraw),
1261 SetTopic(topic) => W::set_topic(topic),
1262 ClearTopic => W::clear_topic(),
1263 AliasOrigin(location) => W::alias_origin(location),
1264 UnpaidExecution { weight_limit, check_origin } => {
1265 W::unpaid_execution(weight_limit, check_origin)
1266 },
1267 }
1268 }
1269}
1270
1271pub mod opaque {
1272 pub type Xcm = super::Xcm<()>;
1275
1276 pub type Instruction = super::Instruction<()>;
1279}
1280
1281impl<Call> TryFrom<OldXcm<Call>> for Xcm<Call> {
1283 type Error = ();
1284 fn try_from(old_xcm: OldXcm<Call>) -> result::Result<Self, Self::Error> {
1285 Ok(Xcm(old_xcm.0.into_iter().map(TryInto::try_into).collect::<result::Result<_, _>>()?))
1286 }
1287}
1288
1289impl<Call: Decode + GetDispatchInfo> TryFrom<NewXcm<Call>> for Xcm<Call> {
1291 type Error = ();
1292 fn try_from(new_xcm: NewXcm<Call>) -> result::Result<Self, Self::Error> {
1293 Ok(Xcm(new_xcm.0.into_iter().map(TryInto::try_into).collect::<result::Result<_, _>>()?))
1294 }
1295}
1296
1297impl<Call: Decode + GetDispatchInfo> TryFrom<NewInstruction<Call>> for Instruction<Call> {
1299 type Error = ();
1300 fn try_from(new_instruction: NewInstruction<Call>) -> result::Result<Self, Self::Error> {
1301 use NewInstruction::*;
1302 Ok(match new_instruction {
1303 WithdrawAsset(assets) => Self::WithdrawAsset(assets.try_into()?),
1304 ReserveAssetDeposited(assets) => Self::ReserveAssetDeposited(assets.try_into()?),
1305 ReceiveTeleportedAsset(assets) => Self::ReceiveTeleportedAsset(assets.try_into()?),
1306 QueryResponse { query_id, response, max_weight, querier: Some(querier) } => {
1307 Self::QueryResponse {
1308 query_id,
1309 querier: querier.try_into()?,
1310 response: response.try_into()?,
1311 max_weight,
1312 }
1313 },
1314 QueryResponse { query_id, response, max_weight, querier: None } => {
1315 Self::QueryResponse {
1316 query_id,
1317 querier: None,
1318 response: response.try_into()?,
1319 max_weight,
1320 }
1321 },
1322 TransferAsset { assets, beneficiary } => Self::TransferAsset {
1323 assets: assets.try_into()?,
1324 beneficiary: beneficiary.try_into()?,
1325 },
1326 TransferReserveAsset { assets, dest, xcm } => Self::TransferReserveAsset {
1327 assets: assets.try_into()?,
1328 dest: dest.try_into()?,
1329 xcm: xcm.try_into()?,
1330 },
1331 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => {
1332 Self::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity }
1333 },
1334 HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient },
1335 HrmpChannelClosing { initiator, sender, recipient } => {
1336 Self::HrmpChannelClosing { initiator, sender, recipient }
1337 },
1338 Transact { origin_kind, mut call, fallback_max_weight } => {
1339 let require_weight_at_most = match call.ensure_decoded() {
1342 Ok(decoded) => decoded.get_dispatch_info().call_weight,
1343 Err(error) => {
1344 let fallback_weight = fallback_max_weight.unwrap_or(Weight::MAX);
1345 tracing::debug!(
1346 target: "xcm::versions::v5Tov4",
1347 ?error,
1348 ?fallback_weight,
1349 "Couldn't decode call in Transact"
1350 );
1351 fallback_weight
1352 },
1353 };
1354 Self::Transact { origin_kind, require_weight_at_most, call }
1355 },
1356 ReportError(response_info) => Self::ReportError(QueryResponseInfo {
1357 query_id: response_info.query_id,
1358 destination: response_info.destination.try_into().map_err(|_| ())?,
1359 max_weight: response_info.max_weight,
1360 }),
1361 DepositAsset { assets, beneficiary } => {
1362 let beneficiary = beneficiary.try_into()?;
1363 let assets = assets.try_into()?;
1364 Self::DepositAsset { assets, beneficiary }
1365 },
1366 DepositReserveAsset { assets, dest, xcm } => {
1367 let dest = dest.try_into()?;
1368 let xcm = xcm.try_into()?;
1369 let assets = assets.try_into()?;
1370 Self::DepositReserveAsset { assets, dest, xcm }
1371 },
1372 ExchangeAsset { give, want, maximal } => {
1373 let give = give.try_into()?;
1374 let want = want.try_into()?;
1375 Self::ExchangeAsset { give, want, maximal }
1376 },
1377 InitiateReserveWithdraw { assets, reserve, xcm } => {
1378 let assets = assets.try_into()?;
1380 let reserve = reserve.try_into()?;
1381 let xcm = xcm.try_into()?;
1382 Self::InitiateReserveWithdraw { assets, reserve, xcm }
1383 },
1384 InitiateTeleport { assets, dest, xcm } => {
1385 let assets = assets.try_into()?;
1387 let dest = dest.try_into()?;
1388 let xcm = xcm.try_into()?;
1389 Self::InitiateTeleport { assets, dest, xcm }
1390 },
1391 ReportHolding { response_info, assets } => {
1392 let response_info = QueryResponseInfo {
1393 destination: response_info.destination.try_into().map_err(|_| ())?,
1394 query_id: response_info.query_id,
1395 max_weight: response_info.max_weight,
1396 };
1397 Self::ReportHolding { response_info, assets: assets.try_into()? }
1398 },
1399 BuyExecution { fees, weight_limit } => {
1400 let fees = fees.try_into()?;
1401 let weight_limit = weight_limit.into();
1402 Self::BuyExecution { fees, weight_limit }
1403 },
1404 ClearOrigin => Self::ClearOrigin,
1405 DescendOrigin(who) => Self::DescendOrigin(who.try_into()?),
1406 RefundSurplus => Self::RefundSurplus,
1407 SetErrorHandler(xcm) => Self::SetErrorHandler(xcm.try_into()?),
1408 SetAppendix(xcm) => Self::SetAppendix(xcm.try_into()?),
1409 ClearError => Self::ClearError,
1410 ClaimAsset { assets, ticket } => {
1411 let assets = assets.try_into()?;
1412 let ticket = ticket.try_into()?;
1413 Self::ClaimAsset { assets, ticket }
1414 },
1415 Trap(code) => Self::Trap(code),
1416 SubscribeVersion { query_id, max_response_weight } => {
1417 Self::SubscribeVersion { query_id, max_response_weight }
1418 },
1419 UnsubscribeVersion => Self::UnsubscribeVersion,
1420 BurnAsset(assets) => Self::BurnAsset(assets.try_into()?),
1421 ExpectAsset(assets) => Self::ExpectAsset(assets.try_into()?),
1422 ExpectOrigin(maybe_origin) => {
1423 Self::ExpectOrigin(maybe_origin.map(|origin| origin.try_into()).transpose()?)
1424 },
1425 ExpectError(maybe_error) => Self::ExpectError(
1426 maybe_error
1427 .map(|(num, new_error)| (num, new_error.try_into()))
1428 .map(|(num, result)| result.map(|inner| (num, inner)))
1429 .transpose()?,
1430 ),
1431 ExpectTransactStatus(maybe_error_code) => Self::ExpectTransactStatus(maybe_error_code),
1432 QueryPallet { module_name, response_info } => {
1433 Self::QueryPallet { module_name, response_info: response_info.try_into()? }
1434 },
1435 ExpectPallet { index, name, module_name, crate_major, min_crate_minor } => {
1436 Self::ExpectPallet { index, name, module_name, crate_major, min_crate_minor }
1437 },
1438 ReportTransactStatus(response_info) => {
1439 Self::ReportTransactStatus(response_info.try_into()?)
1440 },
1441 ClearTransactStatus => Self::ClearTransactStatus,
1442 UniversalOrigin(junction) => Self::UniversalOrigin(junction.try_into()?),
1443 ExportMessage { network, destination, xcm } => Self::ExportMessage {
1444 network: network.into(),
1445 destination: destination.try_into()?,
1446 xcm: xcm.try_into()?,
1447 },
1448 LockAsset { asset, unlocker } => {
1449 Self::LockAsset { asset: asset.try_into()?, unlocker: unlocker.try_into()? }
1450 },
1451 UnlockAsset { asset, target } => {
1452 Self::UnlockAsset { asset: asset.try_into()?, target: target.try_into()? }
1453 },
1454 NoteUnlockable { asset, owner } => {
1455 Self::NoteUnlockable { asset: asset.try_into()?, owner: owner.try_into()? }
1456 },
1457 RequestUnlock { asset, locker } => {
1458 Self::RequestUnlock { asset: asset.try_into()?, locker: locker.try_into()? }
1459 },
1460 SetFeesMode { jit_withdraw } => Self::SetFeesMode { jit_withdraw },
1461 SetTopic(topic) => Self::SetTopic(topic),
1462 ClearTopic => Self::ClearTopic,
1463 AliasOrigin(location) => Self::AliasOrigin(location.try_into()?),
1464 UnpaidExecution { weight_limit, check_origin } => Self::UnpaidExecution {
1465 weight_limit,
1466 check_origin: check_origin.map(|origin| origin.try_into()).transpose()?,
1467 },
1468 InitiateTransfer { .. } |
1469 PayFees { .. } |
1470 SetHints { .. } |
1471 ExecuteWithOrigin { .. } => {
1472 tracing::debug!(target: "xcm::versions::v5tov4", ?new_instruction, "not supported by v4");
1473 return Err(());
1474 },
1475 })
1476 }
1477}
1478
1479impl<Call> TryFrom<OldInstruction<Call>> for Instruction<Call> {
1481 type Error = ();
1482 fn try_from(old_instruction: OldInstruction<Call>) -> result::Result<Self, Self::Error> {
1483 use OldInstruction::*;
1484 Ok(match old_instruction {
1485 WithdrawAsset(assets) => Self::WithdrawAsset(assets.try_into()?),
1486 ReserveAssetDeposited(assets) => Self::ReserveAssetDeposited(assets.try_into()?),
1487 ReceiveTeleportedAsset(assets) => Self::ReceiveTeleportedAsset(assets.try_into()?),
1488 QueryResponse { query_id, response, max_weight, querier: Some(querier) } => {
1489 Self::QueryResponse {
1490 query_id,
1491 querier: querier.try_into()?,
1492 response: response.try_into()?,
1493 max_weight,
1494 }
1495 },
1496 QueryResponse { query_id, response, max_weight, querier: None } => {
1497 Self::QueryResponse {
1498 query_id,
1499 querier: None,
1500 response: response.try_into()?,
1501 max_weight,
1502 }
1503 },
1504 TransferAsset { assets, beneficiary } => Self::TransferAsset {
1505 assets: assets.try_into()?,
1506 beneficiary: beneficiary.try_into()?,
1507 },
1508 TransferReserveAsset { assets, dest, xcm } => Self::TransferReserveAsset {
1509 assets: assets.try_into()?,
1510 dest: dest.try_into()?,
1511 xcm: xcm.try_into()?,
1512 },
1513 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => {
1514 Self::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity }
1515 },
1516 HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient },
1517 HrmpChannelClosing { initiator, sender, recipient } => {
1518 Self::HrmpChannelClosing { initiator, sender, recipient }
1519 },
1520 Transact { origin_kind, require_weight_at_most, call } => {
1521 Self::Transact { origin_kind, require_weight_at_most, call: call.into() }
1522 },
1523 ReportError(response_info) => Self::ReportError(QueryResponseInfo {
1524 query_id: response_info.query_id,
1525 destination: response_info.destination.try_into().map_err(|_| ())?,
1526 max_weight: response_info.max_weight,
1527 }),
1528 DepositAsset { assets, beneficiary } => {
1529 let beneficiary = beneficiary.try_into()?;
1530 let assets = assets.try_into()?;
1531 Self::DepositAsset { assets, beneficiary }
1532 },
1533 DepositReserveAsset { assets, dest, xcm } => {
1534 let dest = dest.try_into()?;
1535 let xcm = xcm.try_into()?;
1536 let assets = assets.try_into()?;
1537 Self::DepositReserveAsset { assets, dest, xcm }
1538 },
1539 ExchangeAsset { give, want, maximal } => {
1540 let give = give.try_into()?;
1541 let want = want.try_into()?;
1542 Self::ExchangeAsset { give, want, maximal }
1543 },
1544 InitiateReserveWithdraw { assets, reserve, xcm } => {
1545 let assets = assets.try_into()?;
1546 let reserve = reserve.try_into()?;
1547 let xcm = xcm.try_into()?;
1548 Self::InitiateReserveWithdraw { assets, reserve, xcm }
1549 },
1550 InitiateTeleport { assets, dest, xcm } => {
1551 let assets = assets.try_into()?;
1552 let dest = dest.try_into()?;
1553 let xcm = xcm.try_into()?;
1554 Self::InitiateTeleport { assets, dest, xcm }
1555 },
1556 ReportHolding { response_info, assets } => {
1557 let response_info = QueryResponseInfo {
1558 destination: response_info.destination.try_into().map_err(|_| ())?,
1559 query_id: response_info.query_id,
1560 max_weight: response_info.max_weight,
1561 };
1562 Self::ReportHolding { response_info, assets: assets.try_into()? }
1563 },
1564 BuyExecution { fees, weight_limit } => {
1565 let fees = fees.try_into()?;
1566 let weight_limit = weight_limit.into();
1567 Self::BuyExecution { fees, weight_limit }
1568 },
1569 ClearOrigin => Self::ClearOrigin,
1570 DescendOrigin(who) => Self::DescendOrigin(who.try_into()?),
1571 RefundSurplus => Self::RefundSurplus,
1572 SetErrorHandler(xcm) => Self::SetErrorHandler(xcm.try_into()?),
1573 SetAppendix(xcm) => Self::SetAppendix(xcm.try_into()?),
1574 ClearError => Self::ClearError,
1575 ClaimAsset { assets, ticket } => {
1576 let assets = assets.try_into()?;
1577 let ticket = ticket.try_into()?;
1578 Self::ClaimAsset { assets, ticket }
1579 },
1580 Trap(code) => Self::Trap(code),
1581 SubscribeVersion { query_id, max_response_weight } => {
1582 Self::SubscribeVersion { query_id, max_response_weight }
1583 },
1584 UnsubscribeVersion => Self::UnsubscribeVersion,
1585 BurnAsset(assets) => Self::BurnAsset(assets.try_into()?),
1586 ExpectAsset(assets) => Self::ExpectAsset(assets.try_into()?),
1587 ExpectOrigin(maybe_location) => Self::ExpectOrigin(
1588 maybe_location.map(|location| location.try_into()).transpose().map_err(|_| ())?,
1589 ),
1590 ExpectError(maybe_error) => Self::ExpectError(
1591 maybe_error.map(|error| error.try_into()).transpose().map_err(|_| ())?,
1592 ),
1593 ExpectTransactStatus(maybe_error_code) => Self::ExpectTransactStatus(maybe_error_code),
1594 QueryPallet { module_name, response_info } => Self::QueryPallet {
1595 module_name,
1596 response_info: response_info.try_into().map_err(|_| ())?,
1597 },
1598 ExpectPallet { index, name, module_name, crate_major, min_crate_minor } => {
1599 Self::ExpectPallet { index, name, module_name, crate_major, min_crate_minor }
1600 },
1601 ReportTransactStatus(response_info) => {
1602 Self::ReportTransactStatus(response_info.try_into().map_err(|_| ())?)
1603 },
1604 ClearTransactStatus => Self::ClearTransactStatus,
1605 UniversalOrigin(junction) => {
1606 Self::UniversalOrigin(junction.try_into().map_err(|_| ())?)
1607 },
1608 ExportMessage { network, destination, xcm } => Self::ExportMessage {
1609 network: network.into(),
1610 destination: destination.try_into().map_err(|_| ())?,
1611 xcm: xcm.try_into().map_err(|_| ())?,
1612 },
1613 LockAsset { asset, unlocker } => Self::LockAsset {
1614 asset: asset.try_into().map_err(|_| ())?,
1615 unlocker: unlocker.try_into().map_err(|_| ())?,
1616 },
1617 UnlockAsset { asset, target } => Self::UnlockAsset {
1618 asset: asset.try_into().map_err(|_| ())?,
1619 target: target.try_into().map_err(|_| ())?,
1620 },
1621 NoteUnlockable { asset, owner } => Self::NoteUnlockable {
1622 asset: asset.try_into().map_err(|_| ())?,
1623 owner: owner.try_into().map_err(|_| ())?,
1624 },
1625 RequestUnlock { asset, locker } => Self::RequestUnlock {
1626 asset: asset.try_into().map_err(|_| ())?,
1627 locker: locker.try_into().map_err(|_| ())?,
1628 },
1629 SetFeesMode { jit_withdraw } => Self::SetFeesMode { jit_withdraw },
1630 SetTopic(topic) => Self::SetTopic(topic),
1631 ClearTopic => Self::ClearTopic,
1632 AliasOrigin(location) => Self::AliasOrigin(location.try_into().map_err(|_| ())?),
1633 UnpaidExecution { weight_limit, check_origin } => Self::UnpaidExecution {
1634 weight_limit,
1635 check_origin: check_origin
1636 .map(|location| location.try_into())
1637 .transpose()
1638 .map_err(|_| ())?,
1639 },
1640 })
1641 }
1642}
1643
1644#[cfg(test)]
1645mod tests {
1646 use super::{prelude::*, *};
1647 use crate::{
1648 v3::{
1649 Junctions::Here as OldHere, MultiAssetFilter as OldMultiAssetFilter,
1650 WildMultiAsset as OldWildMultiAsset,
1651 },
1652 MAX_INSTRUCTIONS_TO_DECODE,
1653 };
1654
1655 #[test]
1656 fn basic_roundtrip_works() {
1657 let xcm = Xcm::<()>(vec![TransferAsset {
1658 assets: (Here, 1u128).into(),
1659 beneficiary: Here.into(),
1660 }]);
1661 let old_xcm = OldXcm::<()>(vec![OldInstruction::TransferAsset {
1662 assets: (OldHere, 1u128).into(),
1663 beneficiary: OldHere.into(),
1664 }]);
1665 assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
1666 let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
1667 assert_eq!(new_xcm, xcm);
1668 }
1669
1670 #[test]
1671 fn teleport_roundtrip_works() {
1672 let xcm = Xcm::<()>(vec![
1673 ReceiveTeleportedAsset((Here, 1u128).into()),
1674 ClearOrigin,
1675 DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Here.into() },
1676 ]);
1677 let old_xcm: OldXcm<()> = OldXcm::<()>(vec![
1678 OldInstruction::ReceiveTeleportedAsset((OldHere, 1u128).into()),
1679 OldInstruction::ClearOrigin,
1680 OldInstruction::DepositAsset {
1681 assets: crate::v3::MultiAssetFilter::Wild(crate::v3::WildMultiAsset::AllCounted(1)),
1682 beneficiary: OldHere.into(),
1683 },
1684 ]);
1685 assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
1686 let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
1687 assert_eq!(new_xcm, xcm);
1688 }
1689
1690 #[test]
1691 fn reserve_deposit_roundtrip_works() {
1692 let xcm = Xcm::<()>(vec![
1693 ReserveAssetDeposited((Here, 1u128).into()),
1694 ClearOrigin,
1695 BuyExecution {
1696 fees: (Here, 1u128).into(),
1697 weight_limit: Some(Weight::from_parts(1, 1)).into(),
1698 },
1699 DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Here.into() },
1700 ]);
1701 let old_xcm = OldXcm::<()>(vec![
1702 OldInstruction::ReserveAssetDeposited((OldHere, 1u128).into()),
1703 OldInstruction::ClearOrigin,
1704 OldInstruction::BuyExecution {
1705 fees: (OldHere, 1u128).into(),
1706 weight_limit: WeightLimit::Limited(Weight::from_parts(1, 1)),
1707 },
1708 OldInstruction::DepositAsset {
1709 assets: crate::v3::MultiAssetFilter::Wild(crate::v3::WildMultiAsset::AllCounted(1)),
1710 beneficiary: OldHere.into(),
1711 },
1712 ]);
1713 assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
1714 let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
1715 assert_eq!(new_xcm, xcm);
1716 }
1717
1718 #[test]
1719 fn deposit_asset_roundtrip_works() {
1720 let xcm = Xcm::<()>(vec![
1721 WithdrawAsset((Here, 1u128).into()),
1722 DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Here.into() },
1723 ]);
1724 let old_xcm = OldXcm::<()>(vec![
1725 OldInstruction::WithdrawAsset((OldHere, 1u128).into()),
1726 OldInstruction::DepositAsset {
1727 assets: OldMultiAssetFilter::Wild(OldWildMultiAsset::AllCounted(1)),
1728 beneficiary: OldHere.into(),
1729 },
1730 ]);
1731 assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
1732 let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
1733 assert_eq!(new_xcm, xcm);
1734 }
1735
1736 #[test]
1737 fn deposit_reserve_asset_roundtrip_works() {
1738 let xcm = Xcm::<()>(vec![
1739 WithdrawAsset((Here, 1u128).into()),
1740 DepositReserveAsset {
1741 assets: Wild(AllCounted(1)),
1742 dest: Here.into(),
1743 xcm: Xcm::<()>(vec![]),
1744 },
1745 ]);
1746 let old_xcm = OldXcm::<()>(vec![
1747 OldInstruction::WithdrawAsset((OldHere, 1u128).into()),
1748 OldInstruction::DepositReserveAsset {
1749 assets: OldMultiAssetFilter::Wild(OldWildMultiAsset::AllCounted(1)),
1750 dest: OldHere.into(),
1751 xcm: OldXcm::<()>(vec![]),
1752 },
1753 ]);
1754 assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
1755 let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
1756 assert_eq!(new_xcm, xcm);
1757 }
1758
1759 #[test]
1760 fn decoding_respects_limit() {
1761 let max_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize]);
1762 let encoded = max_xcm.encode();
1763 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_ok());
1764
1765 let big_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize + 1]);
1766 let encoded = big_xcm.encode();
1767 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1768
1769 let nested_xcm = Xcm::<()>(vec![
1770 DepositReserveAsset {
1771 assets: All.into(),
1772 dest: Here.into(),
1773 xcm: max_xcm,
1774 };
1775 (MAX_INSTRUCTIONS_TO_DECODE / 2) as usize
1776 ]);
1777 let encoded = nested_xcm.encode();
1778 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1779
1780 let even_more_nested_xcm = Xcm::<()>(vec![SetAppendix(nested_xcm); 64]);
1781 let encoded = even_more_nested_xcm.encode();
1782 assert_eq!(encoded.len(), 342530);
1783 assert_eq!(MAX_INSTRUCTIONS_TO_DECODE, 100, "precondition");
1785 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1786 }
1787}