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_bound())]
72#[scale_info(bounds(), skip_type_params(Call))]
73pub struct Xcm<Call>(pub Vec<Instruction<Call>>);
74
75impl<Call> Decode for Xcm<Call> {
76 fn decode<I: CodecInput>(input: &mut I) -> core::result::Result<Self, CodecError> {
77 Ok(Xcm(decode_xcm_instructions(input)?))
78 }
79}
80
81impl<Call> Xcm<Call> {
82 pub fn new() -> Self {
84 Self(vec![])
85 }
86
87 pub fn is_empty(&self) -> bool {
89 self.0.is_empty()
90 }
91
92 pub fn len(&self) -> usize {
94 self.0.len()
95 }
96
97 pub fn inner(&self) -> &[Instruction<Call>] {
99 &self.0
100 }
101
102 pub fn inner_mut(&mut self) -> &mut Vec<Instruction<Call>> {
104 &mut self.0
105 }
106
107 pub fn into_inner(self) -> Vec<Instruction<Call>> {
109 self.0
110 }
111
112 pub fn iter(&self) -> impl Iterator<Item = &Instruction<Call>> {
114 self.0.iter()
115 }
116
117 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Instruction<Call>> {
119 self.0.iter_mut()
120 }
121
122 pub fn into_iter(self) -> impl Iterator<Item = Instruction<Call>> {
124 self.0.into_iter()
125 }
126
127 pub fn or_else(self, f: impl FnOnce() -> Self) -> Self {
130 if self.0.is_empty() {
131 f()
132 } else {
133 self
134 }
135 }
136
137 pub fn first(&self) -> Option<&Instruction<Call>> {
139 self.0.first()
140 }
141
142 pub fn last(&self) -> Option<&Instruction<Call>> {
144 self.0.last()
145 }
146
147 pub fn only(&self) -> Option<&Instruction<Call>> {
149 if self.0.len() == 1 {
150 self.0.first()
151 } else {
152 None
153 }
154 }
155
156 pub fn into_only(mut self) -> core::result::Result<Instruction<Call>, Self> {
159 if self.0.len() == 1 {
160 self.0.pop().ok_or(self)
161 } else {
162 Err(self)
163 }
164 }
165}
166
167impl<Call> From<Vec<Instruction<Call>>> for Xcm<Call> {
168 fn from(c: Vec<Instruction<Call>>) -> Self {
169 Self(c)
170 }
171}
172
173impl<Call> From<Xcm<Call>> for Vec<Instruction<Call>> {
174 fn from(c: Xcm<Call>) -> Self {
175 c.0
176 }
177}
178
179pub mod prelude {
181 mod contents {
182 pub use super::super::{
183 send_xcm, validate_send, Ancestor, AncestorThen, Asset,
184 AssetFilter::{self, *},
185 AssetId,
186 AssetInstance::{self, *},
187 Assets, BodyId, BodyPart, Error as XcmError, ExecuteXcm,
188 Fungibility::{self, *},
189 Instruction::*,
190 InteriorLocation,
191 Junction::{self, *},
192 Junctions::{self, Here},
193 Location, MaybeErrorCode,
194 NetworkId::{self, *},
195 OriginKind, Outcome, PalletInfo, Parent, ParentThen, PreparedMessage, QueryId,
196 QueryResponseInfo, Reanchorable, Response, Result as XcmResult, SendError, SendResult,
197 SendXcm, Weight,
198 WeightLimit::{self, *},
199 WildAsset::{self, *},
200 WildFungibility::{self, Fungible as WildFungible, NonFungible as WildNonFungible},
201 XcmContext, XcmHash, XcmWeightInfo, VERSION as XCM_VERSION,
202 };
203 }
204 pub use super::{Instruction, Xcm};
205 pub use contents::*;
206 pub mod opaque {
207 pub use super::{
208 super::opaque::{Instruction, Xcm},
209 contents::*,
210 };
211 }
212}
213
214parameter_types! {
215 pub MaxPalletNameLen: u32 = 48;
216 pub MaxPalletsInfo: u32 = 64;
217}
218
219#[derive(
220 Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo, MaxEncodedLen,
221)]
222pub struct PalletInfo {
223 #[codec(compact)]
224 pub index: u32,
225 pub name: BoundedVec<u8, MaxPalletNameLen>,
226 pub module_name: BoundedVec<u8, MaxPalletNameLen>,
227 #[codec(compact)]
228 pub major: u32,
229 #[codec(compact)]
230 pub minor: u32,
231 #[codec(compact)]
232 pub patch: u32,
233}
234
235impl TryInto<OldPalletInfo> for PalletInfo {
236 type Error = ();
237
238 fn try_into(self) -> result::Result<OldPalletInfo, Self::Error> {
239 OldPalletInfo::new(
240 self.index,
241 self.name.into_inner(),
242 self.module_name.into_inner(),
243 self.major,
244 self.minor,
245 self.patch,
246 )
247 .map_err(|_| ())
248 }
249}
250
251impl TryInto<NewPalletInfo> for PalletInfo {
252 type Error = ();
253
254 fn try_into(self) -> result::Result<NewPalletInfo, Self::Error> {
255 NewPalletInfo::new(
256 self.index,
257 self.name.into_inner(),
258 self.module_name.into_inner(),
259 self.major,
260 self.minor,
261 self.patch,
262 )
263 .map_err(|_| ())
264 }
265}
266
267impl PalletInfo {
268 pub fn new(
269 index: u32,
270 name: Vec<u8>,
271 module_name: Vec<u8>,
272 major: u32,
273 minor: u32,
274 patch: u32,
275 ) -> result::Result<Self, Error> {
276 let name = BoundedVec::try_from(name).map_err(|_| Error::Overflow)?;
277 let module_name = BoundedVec::try_from(module_name).map_err(|_| Error::Overflow)?;
278
279 Ok(Self { index, name, module_name, major, minor, patch })
280 }
281}
282
283#[derive(
285 Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo, MaxEncodedLen,
286)]
287pub enum Response {
288 Null,
290 Assets(Assets),
292 ExecutionResult(Option<(u32, Error)>),
294 Version(super::Version),
296 PalletsInfo(BoundedVec<PalletInfo, MaxPalletsInfo>),
298 DispatchResult(MaybeErrorCode),
300}
301
302impl Default for Response {
303 fn default() -> Self {
304 Self::Null
305 }
306}
307
308impl TryFrom<OldResponse> for Response {
309 type Error = ();
310
311 fn try_from(old: OldResponse) -> result::Result<Self, Self::Error> {
312 use OldResponse::*;
313 Ok(match old {
314 Null => Self::Null,
315 Assets(assets) => Self::Assets(assets.try_into()?),
316 ExecutionResult(result) =>
317 Self::ExecutionResult(result.map(|(num, old_error)| (num, old_error.into()))),
318 Version(version) => Self::Version(version),
319 PalletsInfo(pallet_info) => {
320 let inner = pallet_info
321 .into_iter()
322 .map(TryInto::try_into)
323 .collect::<result::Result<Vec<_>, _>>()?;
324 Self::PalletsInfo(
325 BoundedVec::<PalletInfo, MaxPalletsInfo>::try_from(inner).map_err(|_| ())?,
326 )
327 },
328 DispatchResult(maybe_error) => Self::DispatchResult(maybe_error),
329 })
330 }
331}
332
333impl TryFrom<NewResponse> for Response {
334 type Error = ();
335
336 fn try_from(new: NewResponse) -> result::Result<Self, Self::Error> {
337 use NewResponse::*;
338 Ok(match new {
339 Null => Self::Null,
340 Assets(assets) => Self::Assets(assets.try_into()?),
341 ExecutionResult(result) => Self::ExecutionResult(
342 result
343 .map(|(num, new_error)| (num, new_error.try_into()))
344 .map(|(num, result)| result.map(|inner| (num, inner)))
345 .transpose()?,
346 ),
347 Version(version) => Self::Version(version),
348 PalletsInfo(pallet_info) => {
349 let inner = pallet_info
350 .into_iter()
351 .map(TryInto::try_into)
352 .collect::<result::Result<Vec<_>, _>>()?;
353 Self::PalletsInfo(
354 BoundedVec::<PalletInfo, MaxPalletsInfo>::try_from(inner).map_err(|_| ())?,
355 )
356 },
357 DispatchResult(maybe_error) =>
358 Self::DispatchResult(maybe_error.try_into().map_err(|_| ())?),
359 })
360 }
361}
362
363#[derive(Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo)]
365pub struct QueryResponseInfo {
366 pub destination: Location,
368 #[codec(compact)]
370 pub query_id: QueryId,
371 pub max_weight: Weight,
373}
374
375impl TryFrom<NewQueryResponseInfo> for QueryResponseInfo {
376 type Error = ();
377
378 fn try_from(new: NewQueryResponseInfo) -> result::Result<Self, Self::Error> {
379 Ok(Self {
380 destination: new.destination.try_into()?,
381 query_id: new.query_id,
382 max_weight: new.max_weight,
383 })
384 }
385}
386
387impl TryFrom<OldQueryResponseInfo> for QueryResponseInfo {
388 type Error = ();
389
390 fn try_from(old: OldQueryResponseInfo) -> result::Result<Self, Self::Error> {
391 Ok(Self {
392 destination: old.destination.try_into()?,
393 query_id: old.query_id,
394 max_weight: old.max_weight,
395 })
396 }
397}
398
399#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)]
401pub struct XcmContext {
402 pub origin: Option<Location>,
404 pub message_id: XcmHash,
407 pub topic: Option<[u8; 32]>,
409}
410
411impl XcmContext {
412 pub fn with_message_id(message_id: XcmHash) -> XcmContext {
415 XcmContext { origin: None, message_id, topic: None }
416 }
417}
418
419#[derive(
428 Encode,
429 Decode,
430 DecodeWithMemTracking,
431 TypeInfo,
432 xcm_procedural::XcmWeightInfoTrait,
433 xcm_procedural::Builder,
434)]
435#[derive_where(Clone, Eq, PartialEq, Debug)]
436#[codec(encode_bound())]
437#[codec(decode_bound())]
438#[codec(decode_with_mem_tracking_bound())]
439#[scale_info(bounds(), skip_type_params(Call))]
440pub enum Instruction<Call> {
441 #[builder(loads_holding)]
450 WithdrawAsset(Assets),
451
452 #[builder(loads_holding)]
464 ReserveAssetDeposited(Assets),
465
466 #[builder(loads_holding)]
478 ReceiveTeleportedAsset(Assets),
479
480 QueryResponse {
498 #[codec(compact)]
499 query_id: QueryId,
500 response: Response,
501 max_weight: Weight,
502 querier: Option<Location>,
503 },
504
505 TransferAsset { assets: Assets, beneficiary: Location },
517
518 TransferReserveAsset { assets: Assets, dest: Location, xcm: Xcm<()> },
537
538 Transact { origin_kind: OriginKind, require_weight_at_most: Weight, call: DoubleEncoded<Call> },
554
555 HrmpNewChannelOpenRequest {
567 #[codec(compact)]
568 sender: u32,
569 #[codec(compact)]
570 max_message_size: u32,
571 #[codec(compact)]
572 max_capacity: u32,
573 },
574
575 HrmpChannelAccepted {
585 #[codec(compact)]
588 recipient: u32,
589 },
590
591 HrmpChannelClosing {
602 #[codec(compact)]
603 initiator: u32,
604 #[codec(compact)]
605 sender: u32,
606 #[codec(compact)]
607 recipient: u32,
608 },
609
610 ClearOrigin,
622
623 DescendOrigin(InteriorLocation),
629
630 ReportError(QueryResponseInfo),
640
641 DepositAsset { assets: AssetFilter, beneficiary: Location },
651
652 DepositReserveAsset { assets: AssetFilter, dest: Location, xcm: Xcm<()> },
669
670 ExchangeAsset { give: AssetFilter, want: Assets, maximal: bool },
686
687 InitiateReserveWithdraw { assets: AssetFilter, reserve: Location, xcm: Xcm<()> },
702
703 InitiateTeleport { assets: AssetFilter, dest: Location, xcm: Xcm<()> },
718
719 ReportHolding { response_info: QueryResponseInfo, assets: AssetFilter },
732
733 #[builder(pays_fees)]
745 BuyExecution { fees: Asset, weight_limit: WeightLimit },
746
747 RefundSurplus,
753
754 SetErrorHandler(Xcm<Call>),
769
770 SetAppendix(Xcm<Call>),
785
786 ClearError,
792
793 #[builder(loads_holding)]
804 ClaimAsset { assets: Assets, ticket: Location },
805
806 Trap(#[codec(compact)] u64),
813
814 SubscribeVersion {
827 #[codec(compact)]
828 query_id: QueryId,
829 max_response_weight: Weight,
830 },
831
832 UnsubscribeVersion,
838
839 BurnAsset(Assets),
849
850 ExpectAsset(Assets),
857
858 ExpectOrigin(Option<Location>),
865
866 ExpectError(Option<(u32, Error)>),
873
874 ExpectTransactStatus(MaybeErrorCode),
883
884 QueryPallet { module_name: Vec<u8>, response_info: QueryResponseInfo },
899
900 ExpectPallet {
919 #[codec(compact)]
920 index: u32,
921 name: Vec<u8>,
922 module_name: Vec<u8>,
923 #[codec(compact)]
924 crate_major: u32,
925 #[codec(compact)]
926 min_crate_minor: u32,
927 },
928
929 ReportTransactStatus(QueryResponseInfo),
941
942 ClearTransactStatus,
950
951 UniversalOrigin(Junction),
965
966 ExportMessage { network: NetworkId, destination: InteriorLocation, xcm: Xcm<()> },
986
987 LockAsset { asset: Asset, unlocker: Location },
1002
1003 UnlockAsset { asset: Asset, target: Location },
1015
1016 NoteUnlockable { asset: Asset, owner: Location },
1030
1031 RequestUnlock { asset: Asset, locker: Location },
1044
1045 SetFeesMode { jit_withdraw: bool },
1054
1055 SetTopic([u8; 32]),
1067
1068 ClearTopic,
1074
1075 AliasOrigin(Location),
1081
1082 UnpaidExecution { weight_limit: WeightLimit, check_origin: Option<Location> },
1093}
1094
1095impl<Call> Xcm<Call> {
1096 pub fn into<C>(self) -> Xcm<C> {
1097 Xcm::from(self)
1098 }
1099 pub fn from<C>(xcm: Xcm<C>) -> Self {
1100 Self(xcm.0.into_iter().map(Instruction::<Call>::from).collect())
1101 }
1102}
1103
1104impl<Call> Instruction<Call> {
1105 pub fn into<C>(self) -> Instruction<C> {
1106 Instruction::from(self)
1107 }
1108 pub fn from<C>(xcm: Instruction<C>) -> Self {
1109 use Instruction::*;
1110 match xcm {
1111 WithdrawAsset(assets) => WithdrawAsset(assets),
1112 ReserveAssetDeposited(assets) => ReserveAssetDeposited(assets),
1113 ReceiveTeleportedAsset(assets) => ReceiveTeleportedAsset(assets),
1114 QueryResponse { query_id, response, max_weight, querier } =>
1115 QueryResponse { query_id, response, max_weight, querier },
1116 TransferAsset { assets, beneficiary } => TransferAsset { assets, beneficiary },
1117 TransferReserveAsset { assets, dest, xcm } =>
1118 TransferReserveAsset { assets, dest, xcm },
1119 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
1120 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
1121 HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient },
1122 HrmpChannelClosing { initiator, sender, recipient } =>
1123 HrmpChannelClosing { initiator, sender, recipient },
1124 Transact { origin_kind, require_weight_at_most, call } =>
1125 Transact { origin_kind, require_weight_at_most, call: call.into() },
1126 ReportError(response_info) => ReportError(response_info),
1127 DepositAsset { assets, beneficiary } => DepositAsset { assets, beneficiary },
1128 DepositReserveAsset { assets, dest, xcm } => DepositReserveAsset { assets, dest, xcm },
1129 ExchangeAsset { give, want, maximal } => ExchangeAsset { give, want, maximal },
1130 InitiateReserveWithdraw { assets, reserve, xcm } =>
1131 InitiateReserveWithdraw { assets, reserve, xcm },
1132 InitiateTeleport { assets, dest, xcm } => InitiateTeleport { assets, dest, xcm },
1133 ReportHolding { response_info, assets } => ReportHolding { response_info, assets },
1134 BuyExecution { fees, weight_limit } => BuyExecution { fees, weight_limit },
1135 ClearOrigin => ClearOrigin,
1136 DescendOrigin(who) => DescendOrigin(who),
1137 RefundSurplus => RefundSurplus,
1138 SetErrorHandler(xcm) => SetErrorHandler(xcm.into()),
1139 SetAppendix(xcm) => SetAppendix(xcm.into()),
1140 ClearError => ClearError,
1141 ClaimAsset { assets, ticket } => ClaimAsset { assets, ticket },
1142 Trap(code) => Trap(code),
1143 SubscribeVersion { query_id, max_response_weight } =>
1144 SubscribeVersion { query_id, max_response_weight },
1145 UnsubscribeVersion => UnsubscribeVersion,
1146 BurnAsset(assets) => BurnAsset(assets),
1147 ExpectAsset(assets) => ExpectAsset(assets),
1148 ExpectOrigin(origin) => ExpectOrigin(origin),
1149 ExpectError(error) => ExpectError(error),
1150 ExpectTransactStatus(transact_status) => ExpectTransactStatus(transact_status),
1151 QueryPallet { module_name, response_info } =>
1152 QueryPallet { module_name, response_info },
1153 ExpectPallet { index, name, module_name, crate_major, min_crate_minor } =>
1154 ExpectPallet { index, name, module_name, crate_major, min_crate_minor },
1155 ReportTransactStatus(response_info) => ReportTransactStatus(response_info),
1156 ClearTransactStatus => ClearTransactStatus,
1157 UniversalOrigin(j) => UniversalOrigin(j),
1158 ExportMessage { network, destination, xcm } =>
1159 ExportMessage { network, destination, xcm },
1160 LockAsset { asset, unlocker } => LockAsset { asset, unlocker },
1161 UnlockAsset { asset, target } => UnlockAsset { asset, target },
1162 NoteUnlockable { asset, owner } => NoteUnlockable { asset, owner },
1163 RequestUnlock { asset, locker } => RequestUnlock { asset, locker },
1164 SetFeesMode { jit_withdraw } => SetFeesMode { jit_withdraw },
1165 SetTopic(topic) => SetTopic(topic),
1166 ClearTopic => ClearTopic,
1167 AliasOrigin(location) => AliasOrigin(location),
1168 UnpaidExecution { weight_limit, check_origin } =>
1169 UnpaidExecution { weight_limit, check_origin },
1170 }
1171 }
1172}
1173
1174impl<Call, W: XcmWeightInfo<Call>> GetWeight<W> for Instruction<Call> {
1176 fn weight(&self) -> Weight {
1177 use Instruction::*;
1178 match self {
1179 WithdrawAsset(assets) => W::withdraw_asset(assets),
1180 ReserveAssetDeposited(assets) => W::reserve_asset_deposited(assets),
1181 ReceiveTeleportedAsset(assets) => W::receive_teleported_asset(assets),
1182 QueryResponse { query_id, response, max_weight, querier } =>
1183 W::query_response(query_id, response, max_weight, querier),
1184 TransferAsset { assets, beneficiary } => W::transfer_asset(assets, beneficiary),
1185 TransferReserveAsset { assets, dest, xcm } =>
1186 W::transfer_reserve_asset(&assets, dest, xcm),
1187 Transact { origin_kind, require_weight_at_most, call } =>
1188 W::transact(origin_kind, require_weight_at_most, call),
1189 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
1190 W::hrmp_new_channel_open_request(sender, max_message_size, max_capacity),
1191 HrmpChannelAccepted { recipient } => W::hrmp_channel_accepted(recipient),
1192 HrmpChannelClosing { initiator, sender, recipient } =>
1193 W::hrmp_channel_closing(initiator, sender, recipient),
1194 ClearOrigin => W::clear_origin(),
1195 DescendOrigin(who) => W::descend_origin(who),
1196 ReportError(response_info) => W::report_error(&response_info),
1197 DepositAsset { assets, beneficiary } => W::deposit_asset(assets, beneficiary),
1198 DepositReserveAsset { assets, dest, xcm } =>
1199 W::deposit_reserve_asset(assets, dest, xcm),
1200 ExchangeAsset { give, want, maximal } => W::exchange_asset(give, want, maximal),
1201 InitiateReserveWithdraw { assets, reserve, xcm } =>
1202 W::initiate_reserve_withdraw(assets, reserve, xcm),
1203 InitiateTeleport { assets, dest, xcm } => W::initiate_teleport(assets, dest, xcm),
1204 ReportHolding { response_info, assets } => W::report_holding(&response_info, &assets),
1205 BuyExecution { fees, weight_limit } => W::buy_execution(fees, weight_limit),
1206 RefundSurplus => W::refund_surplus(),
1207 SetErrorHandler(xcm) => W::set_error_handler(xcm),
1208 SetAppendix(xcm) => W::set_appendix(xcm),
1209 ClearError => W::clear_error(),
1210 ClaimAsset { assets, ticket } => W::claim_asset(assets, ticket),
1211 Trap(code) => W::trap(code),
1212 SubscribeVersion { query_id, max_response_weight } =>
1213 W::subscribe_version(query_id, max_response_weight),
1214 UnsubscribeVersion => W::unsubscribe_version(),
1215 BurnAsset(assets) => W::burn_asset(assets),
1216 ExpectAsset(assets) => W::expect_asset(assets),
1217 ExpectOrigin(origin) => W::expect_origin(origin),
1218 ExpectError(error) => W::expect_error(error),
1219 ExpectTransactStatus(transact_status) => W::expect_transact_status(transact_status),
1220 QueryPallet { module_name, response_info } =>
1221 W::query_pallet(module_name, response_info),
1222 ExpectPallet { index, name, module_name, crate_major, min_crate_minor } =>
1223 W::expect_pallet(index, name, module_name, crate_major, min_crate_minor),
1224 ReportTransactStatus(response_info) => W::report_transact_status(response_info),
1225 ClearTransactStatus => W::clear_transact_status(),
1226 UniversalOrigin(j) => W::universal_origin(j),
1227 ExportMessage { network, destination, xcm } =>
1228 W::export_message(network, destination, xcm),
1229 LockAsset { asset, unlocker } => W::lock_asset(asset, unlocker),
1230 UnlockAsset { asset, target } => W::unlock_asset(asset, target),
1231 NoteUnlockable { asset, owner } => W::note_unlockable(asset, owner),
1232 RequestUnlock { asset, locker } => W::request_unlock(asset, locker),
1233 SetFeesMode { jit_withdraw } => W::set_fees_mode(jit_withdraw),
1234 SetTopic(topic) => W::set_topic(topic),
1235 ClearTopic => W::clear_topic(),
1236 AliasOrigin(location) => W::alias_origin(location),
1237 UnpaidExecution { weight_limit, check_origin } =>
1238 W::unpaid_execution(weight_limit, check_origin),
1239 }
1240 }
1241}
1242
1243pub mod opaque {
1244 pub type Xcm = super::Xcm<()>;
1247
1248 pub type Instruction = super::Instruction<()>;
1251}
1252
1253impl<Call> TryFrom<OldXcm<Call>> for Xcm<Call> {
1255 type Error = ();
1256 fn try_from(old_xcm: OldXcm<Call>) -> result::Result<Self, Self::Error> {
1257 Ok(Xcm(old_xcm.0.into_iter().map(TryInto::try_into).collect::<result::Result<_, _>>()?))
1258 }
1259}
1260
1261impl<Call: Decode + GetDispatchInfo> TryFrom<NewXcm<Call>> for Xcm<Call> {
1263 type Error = ();
1264 fn try_from(new_xcm: NewXcm<Call>) -> result::Result<Self, Self::Error> {
1265 Ok(Xcm(new_xcm.0.into_iter().map(TryInto::try_into).collect::<result::Result<_, _>>()?))
1266 }
1267}
1268
1269impl<Call: Decode + GetDispatchInfo> TryFrom<NewInstruction<Call>> for Instruction<Call> {
1271 type Error = ();
1272 fn try_from(new_instruction: NewInstruction<Call>) -> result::Result<Self, Self::Error> {
1273 use NewInstruction::*;
1274 Ok(match new_instruction {
1275 WithdrawAsset(assets) => Self::WithdrawAsset(assets.try_into()?),
1276 ReserveAssetDeposited(assets) => Self::ReserveAssetDeposited(assets.try_into()?),
1277 ReceiveTeleportedAsset(assets) => Self::ReceiveTeleportedAsset(assets.try_into()?),
1278 QueryResponse { query_id, response, max_weight, querier: Some(querier) } =>
1279 Self::QueryResponse {
1280 query_id,
1281 querier: querier.try_into()?,
1282 response: response.try_into()?,
1283 max_weight,
1284 },
1285 QueryResponse { query_id, response, max_weight, querier: None } =>
1286 Self::QueryResponse {
1287 query_id,
1288 querier: None,
1289 response: response.try_into()?,
1290 max_weight,
1291 },
1292 TransferAsset { assets, beneficiary } => Self::TransferAsset {
1293 assets: assets.try_into()?,
1294 beneficiary: beneficiary.try_into()?,
1295 },
1296 TransferReserveAsset { assets, dest, xcm } => Self::TransferReserveAsset {
1297 assets: assets.try_into()?,
1298 dest: dest.try_into()?,
1299 xcm: xcm.try_into()?,
1300 },
1301 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
1302 Self::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
1303 HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient },
1304 HrmpChannelClosing { initiator, sender, recipient } =>
1305 Self::HrmpChannelClosing { initiator, sender, recipient },
1306 Transact { origin_kind, mut call, fallback_max_weight } => {
1307 let require_weight_at_most = match call.take_decoded() {
1310 Ok(decoded) => decoded.get_dispatch_info().call_weight,
1311 Err(error) => {
1312 let fallback_weight = fallback_max_weight.unwrap_or(Weight::MAX);
1313 tracing::debug!(
1314 target: "xcm::versions::v5Tov4",
1315 ?error,
1316 ?fallback_weight,
1317 "Couldn't decode call in Transact"
1318 );
1319 fallback_weight
1320 },
1321 };
1322 Self::Transact { origin_kind, require_weight_at_most, call: call.into() }
1323 },
1324 ReportError(response_info) => Self::ReportError(QueryResponseInfo {
1325 query_id: response_info.query_id,
1326 destination: response_info.destination.try_into().map_err(|_| ())?,
1327 max_weight: response_info.max_weight,
1328 }),
1329 DepositAsset { assets, beneficiary } => {
1330 let beneficiary = beneficiary.try_into()?;
1331 let assets = assets.try_into()?;
1332 Self::DepositAsset { assets, beneficiary }
1333 },
1334 DepositReserveAsset { assets, dest, xcm } => {
1335 let dest = dest.try_into()?;
1336 let xcm = xcm.try_into()?;
1337 let assets = assets.try_into()?;
1338 Self::DepositReserveAsset { assets, dest, xcm }
1339 },
1340 ExchangeAsset { give, want, maximal } => {
1341 let give = give.try_into()?;
1342 let want = want.try_into()?;
1343 Self::ExchangeAsset { give, want, maximal }
1344 },
1345 InitiateReserveWithdraw { assets, reserve, xcm } => {
1346 let assets = assets.try_into()?;
1348 let reserve = reserve.try_into()?;
1349 let xcm = xcm.try_into()?;
1350 Self::InitiateReserveWithdraw { assets, reserve, xcm }
1351 },
1352 InitiateTeleport { assets, dest, xcm } => {
1353 let assets = assets.try_into()?;
1355 let dest = dest.try_into()?;
1356 let xcm = xcm.try_into()?;
1357 Self::InitiateTeleport { assets, dest, xcm }
1358 },
1359 ReportHolding { response_info, assets } => {
1360 let response_info = QueryResponseInfo {
1361 destination: response_info.destination.try_into().map_err(|_| ())?,
1362 query_id: response_info.query_id,
1363 max_weight: response_info.max_weight,
1364 };
1365 Self::ReportHolding { response_info, assets: assets.try_into()? }
1366 },
1367 BuyExecution { fees, weight_limit } => {
1368 let fees = fees.try_into()?;
1369 let weight_limit = weight_limit.into();
1370 Self::BuyExecution { fees, weight_limit }
1371 },
1372 ClearOrigin => Self::ClearOrigin,
1373 DescendOrigin(who) => Self::DescendOrigin(who.try_into()?),
1374 RefundSurplus => Self::RefundSurplus,
1375 SetErrorHandler(xcm) => Self::SetErrorHandler(xcm.try_into()?),
1376 SetAppendix(xcm) => Self::SetAppendix(xcm.try_into()?),
1377 ClearError => Self::ClearError,
1378 ClaimAsset { assets, ticket } => {
1379 let assets = assets.try_into()?;
1380 let ticket = ticket.try_into()?;
1381 Self::ClaimAsset { assets, ticket }
1382 },
1383 Trap(code) => Self::Trap(code),
1384 SubscribeVersion { query_id, max_response_weight } =>
1385 Self::SubscribeVersion { query_id, max_response_weight },
1386 UnsubscribeVersion => Self::UnsubscribeVersion,
1387 BurnAsset(assets) => Self::BurnAsset(assets.try_into()?),
1388 ExpectAsset(assets) => Self::ExpectAsset(assets.try_into()?),
1389 ExpectOrigin(maybe_origin) =>
1390 Self::ExpectOrigin(maybe_origin.map(|origin| origin.try_into()).transpose()?),
1391 ExpectError(maybe_error) => Self::ExpectError(
1392 maybe_error
1393 .map(|(num, new_error)| (num, new_error.try_into()))
1394 .map(|(num, result)| result.map(|inner| (num, inner)))
1395 .transpose()?,
1396 ),
1397 ExpectTransactStatus(maybe_error_code) => Self::ExpectTransactStatus(maybe_error_code),
1398 QueryPallet { module_name, response_info } =>
1399 Self::QueryPallet { module_name, response_info: response_info.try_into()? },
1400 ExpectPallet { index, name, module_name, crate_major, min_crate_minor } =>
1401 Self::ExpectPallet { index, name, module_name, crate_major, min_crate_minor },
1402 ReportTransactStatus(response_info) =>
1403 Self::ReportTransactStatus(response_info.try_into()?),
1404 ClearTransactStatus => Self::ClearTransactStatus,
1405 UniversalOrigin(junction) => Self::UniversalOrigin(junction.try_into()?),
1406 ExportMessage { network, destination, xcm } => Self::ExportMessage {
1407 network: network.into(),
1408 destination: destination.try_into()?,
1409 xcm: xcm.try_into()?,
1410 },
1411 LockAsset { asset, unlocker } =>
1412 Self::LockAsset { asset: asset.try_into()?, unlocker: unlocker.try_into()? },
1413 UnlockAsset { asset, target } =>
1414 Self::UnlockAsset { asset: asset.try_into()?, target: target.try_into()? },
1415 NoteUnlockable { asset, owner } =>
1416 Self::NoteUnlockable { asset: asset.try_into()?, owner: owner.try_into()? },
1417 RequestUnlock { asset, locker } =>
1418 Self::RequestUnlock { asset: asset.try_into()?, locker: locker.try_into()? },
1419 SetFeesMode { jit_withdraw } => Self::SetFeesMode { jit_withdraw },
1420 SetTopic(topic) => Self::SetTopic(topic),
1421 ClearTopic => Self::ClearTopic,
1422 AliasOrigin(location) => Self::AliasOrigin(location.try_into()?),
1423 UnpaidExecution { weight_limit, check_origin } => Self::UnpaidExecution {
1424 weight_limit,
1425 check_origin: check_origin.map(|origin| origin.try_into()).transpose()?,
1426 },
1427 InitiateTransfer { .. } |
1428 PayFees { .. } |
1429 SetHints { .. } |
1430 ExecuteWithOrigin { .. } => {
1431 tracing::debug!(target: "xcm::versions::v5tov4", ?new_instruction, "not supported by v4");
1432 return Err(());
1433 },
1434 })
1435 }
1436}
1437
1438impl<Call> TryFrom<OldInstruction<Call>> for Instruction<Call> {
1440 type Error = ();
1441 fn try_from(old_instruction: OldInstruction<Call>) -> result::Result<Self, Self::Error> {
1442 use OldInstruction::*;
1443 Ok(match old_instruction {
1444 WithdrawAsset(assets) => Self::WithdrawAsset(assets.try_into()?),
1445 ReserveAssetDeposited(assets) => Self::ReserveAssetDeposited(assets.try_into()?),
1446 ReceiveTeleportedAsset(assets) => Self::ReceiveTeleportedAsset(assets.try_into()?),
1447 QueryResponse { query_id, response, max_weight, querier: Some(querier) } =>
1448 Self::QueryResponse {
1449 query_id,
1450 querier: querier.try_into()?,
1451 response: response.try_into()?,
1452 max_weight,
1453 },
1454 QueryResponse { query_id, response, max_weight, querier: None } =>
1455 Self::QueryResponse {
1456 query_id,
1457 querier: None,
1458 response: response.try_into()?,
1459 max_weight,
1460 },
1461 TransferAsset { assets, beneficiary } => Self::TransferAsset {
1462 assets: assets.try_into()?,
1463 beneficiary: beneficiary.try_into()?,
1464 },
1465 TransferReserveAsset { assets, dest, xcm } => Self::TransferReserveAsset {
1466 assets: assets.try_into()?,
1467 dest: dest.try_into()?,
1468 xcm: xcm.try_into()?,
1469 },
1470 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
1471 Self::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
1472 HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient },
1473 HrmpChannelClosing { initiator, sender, recipient } =>
1474 Self::HrmpChannelClosing { initiator, sender, recipient },
1475 Transact { origin_kind, require_weight_at_most, call } =>
1476 Self::Transact { origin_kind, require_weight_at_most, call: call.into() },
1477 ReportError(response_info) => Self::ReportError(QueryResponseInfo {
1478 query_id: response_info.query_id,
1479 destination: response_info.destination.try_into().map_err(|_| ())?,
1480 max_weight: response_info.max_weight,
1481 }),
1482 DepositAsset { assets, beneficiary } => {
1483 let beneficiary = beneficiary.try_into()?;
1484 let assets = assets.try_into()?;
1485 Self::DepositAsset { assets, beneficiary }
1486 },
1487 DepositReserveAsset { assets, dest, xcm } => {
1488 let dest = dest.try_into()?;
1489 let xcm = xcm.try_into()?;
1490 let assets = assets.try_into()?;
1491 Self::DepositReserveAsset { assets, dest, xcm }
1492 },
1493 ExchangeAsset { give, want, maximal } => {
1494 let give = give.try_into()?;
1495 let want = want.try_into()?;
1496 Self::ExchangeAsset { give, want, maximal }
1497 },
1498 InitiateReserveWithdraw { assets, reserve, xcm } => {
1499 let assets = assets.try_into()?;
1500 let reserve = reserve.try_into()?;
1501 let xcm = xcm.try_into()?;
1502 Self::InitiateReserveWithdraw { assets, reserve, xcm }
1503 },
1504 InitiateTeleport { assets, dest, xcm } => {
1505 let assets = assets.try_into()?;
1506 let dest = dest.try_into()?;
1507 let xcm = xcm.try_into()?;
1508 Self::InitiateTeleport { assets, dest, xcm }
1509 },
1510 ReportHolding { response_info, assets } => {
1511 let response_info = QueryResponseInfo {
1512 destination: response_info.destination.try_into().map_err(|_| ())?,
1513 query_id: response_info.query_id,
1514 max_weight: response_info.max_weight,
1515 };
1516 Self::ReportHolding { response_info, assets: assets.try_into()? }
1517 },
1518 BuyExecution { fees, weight_limit } => {
1519 let fees = fees.try_into()?;
1520 let weight_limit = weight_limit.into();
1521 Self::BuyExecution { fees, weight_limit }
1522 },
1523 ClearOrigin => Self::ClearOrigin,
1524 DescendOrigin(who) => Self::DescendOrigin(who.try_into()?),
1525 RefundSurplus => Self::RefundSurplus,
1526 SetErrorHandler(xcm) => Self::SetErrorHandler(xcm.try_into()?),
1527 SetAppendix(xcm) => Self::SetAppendix(xcm.try_into()?),
1528 ClearError => Self::ClearError,
1529 ClaimAsset { assets, ticket } => {
1530 let assets = assets.try_into()?;
1531 let ticket = ticket.try_into()?;
1532 Self::ClaimAsset { assets, ticket }
1533 },
1534 Trap(code) => Self::Trap(code),
1535 SubscribeVersion { query_id, max_response_weight } =>
1536 Self::SubscribeVersion { query_id, max_response_weight },
1537 UnsubscribeVersion => Self::UnsubscribeVersion,
1538 BurnAsset(assets) => Self::BurnAsset(assets.try_into()?),
1539 ExpectAsset(assets) => Self::ExpectAsset(assets.try_into()?),
1540 ExpectOrigin(maybe_location) => Self::ExpectOrigin(
1541 maybe_location.map(|location| location.try_into()).transpose().map_err(|_| ())?,
1542 ),
1543 ExpectError(maybe_error) => Self::ExpectError(
1544 maybe_error.map(|error| error.try_into()).transpose().map_err(|_| ())?,
1545 ),
1546 ExpectTransactStatus(maybe_error_code) => Self::ExpectTransactStatus(maybe_error_code),
1547 QueryPallet { module_name, response_info } => Self::QueryPallet {
1548 module_name,
1549 response_info: response_info.try_into().map_err(|_| ())?,
1550 },
1551 ExpectPallet { index, name, module_name, crate_major, min_crate_minor } =>
1552 Self::ExpectPallet { index, name, module_name, crate_major, min_crate_minor },
1553 ReportTransactStatus(response_info) =>
1554 Self::ReportTransactStatus(response_info.try_into().map_err(|_| ())?),
1555 ClearTransactStatus => Self::ClearTransactStatus,
1556 UniversalOrigin(junction) =>
1557 Self::UniversalOrigin(junction.try_into().map_err(|_| ())?),
1558 ExportMessage { network, destination, xcm } => Self::ExportMessage {
1559 network: network.into(),
1560 destination: destination.try_into().map_err(|_| ())?,
1561 xcm: xcm.try_into().map_err(|_| ())?,
1562 },
1563 LockAsset { asset, unlocker } => Self::LockAsset {
1564 asset: asset.try_into().map_err(|_| ())?,
1565 unlocker: unlocker.try_into().map_err(|_| ())?,
1566 },
1567 UnlockAsset { asset, target } => Self::UnlockAsset {
1568 asset: asset.try_into().map_err(|_| ())?,
1569 target: target.try_into().map_err(|_| ())?,
1570 },
1571 NoteUnlockable { asset, owner } => Self::NoteUnlockable {
1572 asset: asset.try_into().map_err(|_| ())?,
1573 owner: owner.try_into().map_err(|_| ())?,
1574 },
1575 RequestUnlock { asset, locker } => Self::RequestUnlock {
1576 asset: asset.try_into().map_err(|_| ())?,
1577 locker: locker.try_into().map_err(|_| ())?,
1578 },
1579 SetFeesMode { jit_withdraw } => Self::SetFeesMode { jit_withdraw },
1580 SetTopic(topic) => Self::SetTopic(topic),
1581 ClearTopic => Self::ClearTopic,
1582 AliasOrigin(location) => Self::AliasOrigin(location.try_into().map_err(|_| ())?),
1583 UnpaidExecution { weight_limit, check_origin } => Self::UnpaidExecution {
1584 weight_limit,
1585 check_origin: check_origin
1586 .map(|location| location.try_into())
1587 .transpose()
1588 .map_err(|_| ())?,
1589 },
1590 })
1591 }
1592}
1593
1594#[cfg(test)]
1595mod tests {
1596 use super::{prelude::*, *};
1597 use crate::{
1598 v3::{
1599 Junctions::Here as OldHere, MultiAssetFilter as OldMultiAssetFilter,
1600 WildMultiAsset as OldWildMultiAsset,
1601 },
1602 MAX_INSTRUCTIONS_TO_DECODE,
1603 };
1604
1605 #[test]
1606 fn basic_roundtrip_works() {
1607 let xcm = Xcm::<()>(vec![TransferAsset {
1608 assets: (Here, 1u128).into(),
1609 beneficiary: Here.into(),
1610 }]);
1611 let old_xcm = OldXcm::<()>(vec![OldInstruction::TransferAsset {
1612 assets: (OldHere, 1u128).into(),
1613 beneficiary: OldHere.into(),
1614 }]);
1615 assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
1616 let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
1617 assert_eq!(new_xcm, xcm);
1618 }
1619
1620 #[test]
1621 fn teleport_roundtrip_works() {
1622 let xcm = Xcm::<()>(vec![
1623 ReceiveTeleportedAsset((Here, 1u128).into()),
1624 ClearOrigin,
1625 DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Here.into() },
1626 ]);
1627 let old_xcm: OldXcm<()> = OldXcm::<()>(vec![
1628 OldInstruction::ReceiveTeleportedAsset((OldHere, 1u128).into()),
1629 OldInstruction::ClearOrigin,
1630 OldInstruction::DepositAsset {
1631 assets: crate::v3::MultiAssetFilter::Wild(crate::v3::WildMultiAsset::AllCounted(1)),
1632 beneficiary: OldHere.into(),
1633 },
1634 ]);
1635 assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
1636 let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
1637 assert_eq!(new_xcm, xcm);
1638 }
1639
1640 #[test]
1641 fn reserve_deposit_roundtrip_works() {
1642 let xcm = Xcm::<()>(vec![
1643 ReserveAssetDeposited((Here, 1u128).into()),
1644 ClearOrigin,
1645 BuyExecution {
1646 fees: (Here, 1u128).into(),
1647 weight_limit: Some(Weight::from_parts(1, 1)).into(),
1648 },
1649 DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Here.into() },
1650 ]);
1651 let old_xcm = OldXcm::<()>(vec![
1652 OldInstruction::ReserveAssetDeposited((OldHere, 1u128).into()),
1653 OldInstruction::ClearOrigin,
1654 OldInstruction::BuyExecution {
1655 fees: (OldHere, 1u128).into(),
1656 weight_limit: WeightLimit::Limited(Weight::from_parts(1, 1)),
1657 },
1658 OldInstruction::DepositAsset {
1659 assets: crate::v3::MultiAssetFilter::Wild(crate::v3::WildMultiAsset::AllCounted(1)),
1660 beneficiary: OldHere.into(),
1661 },
1662 ]);
1663 assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
1664 let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
1665 assert_eq!(new_xcm, xcm);
1666 }
1667
1668 #[test]
1669 fn deposit_asset_roundtrip_works() {
1670 let xcm = Xcm::<()>(vec![
1671 WithdrawAsset((Here, 1u128).into()),
1672 DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Here.into() },
1673 ]);
1674 let old_xcm = OldXcm::<()>(vec![
1675 OldInstruction::WithdrawAsset((OldHere, 1u128).into()),
1676 OldInstruction::DepositAsset {
1677 assets: OldMultiAssetFilter::Wild(OldWildMultiAsset::AllCounted(1)),
1678 beneficiary: OldHere.into(),
1679 },
1680 ]);
1681 assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
1682 let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
1683 assert_eq!(new_xcm, xcm);
1684 }
1685
1686 #[test]
1687 fn deposit_reserve_asset_roundtrip_works() {
1688 let xcm = Xcm::<()>(vec![
1689 WithdrawAsset((Here, 1u128).into()),
1690 DepositReserveAsset {
1691 assets: Wild(AllCounted(1)),
1692 dest: Here.into(),
1693 xcm: Xcm::<()>(vec![]),
1694 },
1695 ]);
1696 let old_xcm = OldXcm::<()>(vec![
1697 OldInstruction::WithdrawAsset((OldHere, 1u128).into()),
1698 OldInstruction::DepositReserveAsset {
1699 assets: OldMultiAssetFilter::Wild(OldWildMultiAsset::AllCounted(1)),
1700 dest: OldHere.into(),
1701 xcm: OldXcm::<()>(vec![]),
1702 },
1703 ]);
1704 assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
1705 let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
1706 assert_eq!(new_xcm, xcm);
1707 }
1708
1709 #[test]
1710 fn decoding_respects_limit() {
1711 let max_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize]);
1712 let encoded = max_xcm.encode();
1713 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_ok());
1714
1715 let big_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize + 1]);
1716 let encoded = big_xcm.encode();
1717 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1718
1719 let nested_xcm = Xcm::<()>(vec![
1720 DepositReserveAsset {
1721 assets: All.into(),
1722 dest: Here.into(),
1723 xcm: max_xcm,
1724 };
1725 (MAX_INSTRUCTIONS_TO_DECODE / 2) as usize
1726 ]);
1727 let encoded = nested_xcm.encode();
1728 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1729
1730 let even_more_nested_xcm = Xcm::<()>(vec![SetAppendix(nested_xcm); 64]);
1731 let encoded = even_more_nested_xcm.encode();
1732 assert_eq!(encoded.len(), 342530);
1733 assert_eq!(MAX_INSTRUCTIONS_TO_DECODE, 100, "precondition");
1735 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1736 }
1737}