1use super::v4::{
20 Instruction as NewInstruction, PalletInfo as NewPalletInfo,
21 QueryResponseInfo as NewQueryResponseInfo, Response as NewResponse, Xcm as NewXcm,
22};
23use crate::{utils::decode_xcm_instructions, DoubleEncoded};
24use alloc::{vec, vec::Vec};
25use bounded_collections::{parameter_types, BoundedVec};
26use codec::{
27 self, Decode, DecodeWithMemTracking, Encode, Error as CodecError, Input as CodecInput,
28 MaxEncodedLen,
29};
30use core::{fmt::Debug, result};
31use derive_where::derive_where;
32use scale_info::TypeInfo;
33
34mod junction;
35pub(crate) mod junctions;
36mod multiasset;
37mod multilocation;
38mod traits;
39
40pub use junction::{BodyId, BodyPart, Junction, NetworkId};
41pub use junctions::Junctions;
42pub use multiasset::{
43 AssetId, AssetInstance, Fungibility, MultiAsset, MultiAssetFilter, MultiAssets,
44 WildFungibility, WildMultiAsset, MAX_ITEMS_IN_MULTIASSETS,
45};
46pub use multilocation::{
47 Ancestor, AncestorThen, InteriorMultiLocation, Location, MultiLocation, Parent, ParentThen,
48};
49pub use traits::{
50 send_xcm, validate_send, Error, ExecuteXcm, GetWeight, Outcome, PreparedMessage, Result,
51 SendError, SendResult, SendXcm, Weight, XcmHash,
52};
53
54pub const VERSION: super::Version = 3;
56
57pub type QueryId = u64;
59
60#[derive(Default, DecodeWithMemTracking, Encode, TypeInfo)]
61#[derive_where(Clone, Eq, PartialEq, Debug)]
62#[codec(encode_bound())]
63#[scale_info(bounds(), skip_type_params(Call))]
64#[scale_info(replace_segment("staging_xcm", "xcm"))]
65#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
66pub struct Xcm<Call>(pub Vec<Instruction<Call>>);
67
68impl<Call> Decode for Xcm<Call> {
69 fn decode<I: CodecInput>(input: &mut I) -> core::result::Result<Self, CodecError> {
70 Ok(Xcm(decode_xcm_instructions(input)?))
71 }
72}
73
74impl<Call> Xcm<Call> {
75 pub fn new() -> Self {
77 Self(vec![])
78 }
79
80 pub fn is_empty(&self) -> bool {
82 self.0.is_empty()
83 }
84
85 pub fn len(&self) -> usize {
87 self.0.len()
88 }
89
90 pub fn inner(&self) -> &[Instruction<Call>] {
92 &self.0
93 }
94
95 pub fn inner_mut(&mut self) -> &mut Vec<Instruction<Call>> {
97 &mut self.0
98 }
99
100 pub fn into_inner(self) -> Vec<Instruction<Call>> {
102 self.0
103 }
104
105 pub fn iter(&self) -> impl Iterator<Item = &Instruction<Call>> {
107 self.0.iter()
108 }
109
110 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Instruction<Call>> {
112 self.0.iter_mut()
113 }
114
115 pub fn into_iter(self) -> impl Iterator<Item = Instruction<Call>> {
117 self.0.into_iter()
118 }
119
120 pub fn or_else(self, f: impl FnOnce() -> Self) -> Self {
123 if self.0.is_empty() {
124 f()
125 } else {
126 self
127 }
128 }
129
130 pub fn first(&self) -> Option<&Instruction<Call>> {
132 self.0.first()
133 }
134
135 pub fn last(&self) -> Option<&Instruction<Call>> {
137 self.0.last()
138 }
139
140 pub fn only(&self) -> Option<&Instruction<Call>> {
142 if self.0.len() == 1 {
143 self.0.first()
144 } else {
145 None
146 }
147 }
148
149 pub fn into_only(mut self) -> core::result::Result<Instruction<Call>, Self> {
152 if self.0.len() == 1 {
153 self.0.pop().ok_or(self)
154 } else {
155 Err(self)
156 }
157 }
158}
159
160impl<Call> From<Vec<Instruction<Call>>> for Xcm<Call> {
161 fn from(c: Vec<Instruction<Call>>) -> Self {
162 Self(c)
163 }
164}
165
166impl<Call> From<Xcm<Call>> for Vec<Instruction<Call>> {
167 fn from(c: Xcm<Call>) -> Self {
168 c.0
169 }
170}
171
172pub mod prelude {
174 mod contents {
175 pub use super::super::{
176 send_xcm, validate_send, Ancestor, AncestorThen,
177 AssetId::{self, *},
178 AssetInstance::{self, *},
179 BodyId, BodyPart, Error as XcmError, ExecuteXcm,
180 Fungibility::{self, *},
181 GetWeight,
182 Instruction::*,
183 InteriorMultiLocation,
184 Junction::{self, *},
185 Junctions::{self, *},
186 Location, MaybeErrorCode, MultiAsset,
187 MultiAssetFilter::{self, *},
188 MultiAssets, MultiLocation,
189 NetworkId::{self, *},
190 OriginKind, Outcome, PalletInfo, Parent, ParentThen, PreparedMessage, QueryId,
191 QueryResponseInfo, Response, Result as XcmResult, SendError, SendResult, SendXcm,
192 Weight,
193 WeightLimit::{self, *},
194 WildFungibility::{self, Fungible as WildFungible, NonFungible as WildNonFungible},
195 WildMultiAsset::{self, *},
196 XcmContext, XcmHash, XcmWeightInfo, VERSION as XCM_VERSION,
197 };
198 }
199 pub use super::{Instruction, Xcm};
200 pub use contents::*;
201 pub mod opaque {
202 pub use super::{
203 super::opaque::{Instruction, Xcm},
204 contents::*,
205 };
206 }
207}
208
209parameter_types! {
210 #[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
211 pub MaxPalletNameLen: u32 = 48;
212 #[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
215 pub MaxDispatchErrorLen: u32 = 128;
216 #[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
217 pub MaxPalletsInfo: u32 = 64;
218}
219
220#[derive(
221 Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo, MaxEncodedLen,
222)]
223#[scale_info(replace_segment("staging_xcm", "xcm"))]
224#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
225pub struct PalletInfo {
226 #[codec(compact)]
227 pub index: u32,
228 pub name: BoundedVec<u8, MaxPalletNameLen>,
229 pub module_name: BoundedVec<u8, MaxPalletNameLen>,
230 #[codec(compact)]
231 pub major: u32,
232 #[codec(compact)]
233 pub minor: u32,
234 #[codec(compact)]
235 pub patch: u32,
236}
237
238impl PalletInfo {
239 pub fn new(
240 index: u32,
241 name: Vec<u8>,
242 module_name: Vec<u8>,
243 major: u32,
244 minor: u32,
245 patch: u32,
246 ) -> result::Result<Self, Error> {
247 let name = BoundedVec::try_from(name).map_err(|_| Error::Overflow)?;
248 let module_name = BoundedVec::try_from(module_name).map_err(|_| Error::Overflow)?;
249
250 Ok(Self { index, name, module_name, major, minor, patch })
251 }
252}
253
254impl TryInto<NewPalletInfo> for PalletInfo {
255 type Error = ();
256
257 fn try_into(self) -> result::Result<NewPalletInfo, Self::Error> {
258 NewPalletInfo::new(
259 self.index,
260 self.name.into_inner(),
261 self.module_name.into_inner(),
262 self.major,
263 self.minor,
264 self.patch,
265 )
266 .map_err(|_| ())
267 }
268}
269
270#[derive(
271 Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo, MaxEncodedLen,
272)]
273#[scale_info(replace_segment("staging_xcm", "xcm"))]
274#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
275pub enum MaybeErrorCode {
276 Success,
277 Error(BoundedVec<u8, MaxDispatchErrorLen>),
278 TruncatedError(BoundedVec<u8, MaxDispatchErrorLen>),
279}
280
281impl From<Vec<u8>> for MaybeErrorCode {
282 fn from(v: Vec<u8>) -> Self {
283 match BoundedVec::try_from(v) {
284 Ok(error) => MaybeErrorCode::Error(error),
285 Err(error) => MaybeErrorCode::TruncatedError(BoundedVec::truncate_from(error)),
286 }
287 }
288}
289
290impl Default for MaybeErrorCode {
291 fn default() -> MaybeErrorCode {
292 MaybeErrorCode::Success
293 }
294}
295
296#[derive(
298 Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo, MaxEncodedLen,
299)]
300#[scale_info(replace_segment("staging_xcm", "xcm"))]
301#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
302pub enum Response {
303 Null,
305 Assets(MultiAssets),
307 ExecutionResult(Option<(u32, Error)>),
309 Version(super::Version),
311 PalletsInfo(BoundedVec<PalletInfo, MaxPalletsInfo>),
313 DispatchResult(MaybeErrorCode),
315}
316
317impl Default for Response {
318 fn default() -> Self {
319 Self::Null
320 }
321}
322
323impl TryFrom<NewResponse> for Response {
324 type Error = ();
325
326 fn try_from(new: NewResponse) -> result::Result<Self, Self::Error> {
327 use NewResponse::*;
328 Ok(match new {
329 Null => Self::Null,
330 Assets(assets) => Self::Assets(assets.try_into()?),
331 ExecutionResult(result) =>
332 Self::ExecutionResult(result.map(|(num, old_error)| (num, old_error.into()))),
333 Version(version) => Self::Version(version),
334 PalletsInfo(pallet_info) => {
335 let inner = pallet_info
336 .into_iter()
337 .map(TryInto::try_into)
338 .collect::<result::Result<Vec<_>, _>>()?;
339 Self::PalletsInfo(
340 BoundedVec::<PalletInfo, MaxPalletsInfo>::try_from(inner).map_err(|_| ())?,
341 )
342 },
343 DispatchResult(maybe_error) =>
344 Self::DispatchResult(maybe_error.try_into().map_err(|_| ())?),
345 })
346 }
347}
348
349#[derive(Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo)]
351#[scale_info(replace_segment("staging_xcm", "xcm"))]
352#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
353pub struct QueryResponseInfo {
354 pub destination: MultiLocation,
356 #[codec(compact)]
358 pub query_id: QueryId,
359 pub max_weight: Weight,
361}
362
363impl TryFrom<NewQueryResponseInfo> for QueryResponseInfo {
364 type Error = ();
365
366 fn try_from(new: NewQueryResponseInfo) -> result::Result<Self, Self::Error> {
367 Ok(Self {
368 destination: new.destination.try_into()?,
369 query_id: new.query_id,
370 max_weight: new.max_weight,
371 })
372 }
373}
374
375#[derive(Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo)]
377#[scale_info(replace_segment("staging_xcm", "xcm"))]
378#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
379pub enum WeightLimit {
380 Unlimited,
382 Limited(Weight),
384}
385
386impl From<Option<Weight>> for WeightLimit {
387 fn from(x: Option<Weight>) -> Self {
388 match x {
389 Some(w) => WeightLimit::Limited(w),
390 None => WeightLimit::Unlimited,
391 }
392 }
393}
394
395impl From<WeightLimit> for Option<Weight> {
396 fn from(x: WeightLimit) -> Self {
397 match x {
398 WeightLimit::Limited(w) => Some(w),
399 WeightLimit::Unlimited => None,
400 }
401 }
402}
403
404#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo)]
406#[scale_info(replace_segment("staging_xcm", "xcm"))]
407#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
408pub enum OriginKind {
409 Native,
414
415 SovereignAccount,
418
419 Superuser,
422
423 Xcm,
427}
428
429#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)]
431pub struct XcmContext {
432 pub origin: Option<MultiLocation>,
434 pub message_id: XcmHash,
437 pub topic: Option<[u8; 32]>,
439}
440
441impl XcmContext {
442 #[deprecated = "Use `with_message_id` instead."]
445 pub fn with_message_hash(message_id: XcmHash) -> XcmContext {
446 XcmContext { origin: None, message_id, topic: None }
447 }
448
449 pub fn with_message_id(message_id: XcmHash) -> XcmContext {
452 XcmContext { origin: None, message_id, topic: None }
453 }
454}
455
456#[derive(
465 Encode,
466 Decode,
467 DecodeWithMemTracking,
468 TypeInfo,
469 xcm_procedural::XcmWeightInfoTrait,
470 xcm_procedural::Builder,
471)]
472#[derive_where(Clone, Eq, PartialEq, Debug)]
473#[codec(encode_bound())]
474#[codec(decode_bound())]
475#[codec(decode_with_mem_tracking_bound())]
476#[scale_info(bounds(), skip_type_params(Call))]
477#[scale_info(replace_segment("staging_xcm", "xcm"))]
478#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
479pub enum Instruction<Call> {
480 #[builder(loads_holding)]
489 WithdrawAsset(MultiAssets),
490
491 #[builder(loads_holding)]
503 ReserveAssetDeposited(MultiAssets),
504
505 #[builder(loads_holding)]
517 ReceiveTeleportedAsset(MultiAssets),
518
519 QueryResponse {
537 #[codec(compact)]
538 query_id: QueryId,
539 response: Response,
540 max_weight: Weight,
541 querier: Option<MultiLocation>,
542 },
543
544 TransferAsset { assets: MultiAssets, beneficiary: MultiLocation },
556
557 TransferReserveAsset { assets: MultiAssets, dest: MultiLocation, xcm: Xcm<()> },
576
577 Transact { origin_kind: OriginKind, require_weight_at_most: Weight, call: DoubleEncoded<Call> },
593
594 HrmpNewChannelOpenRequest {
606 #[codec(compact)]
607 sender: u32,
608 #[codec(compact)]
609 max_message_size: u32,
610 #[codec(compact)]
611 max_capacity: u32,
612 },
613
614 HrmpChannelAccepted {
624 #[codec(compact)]
627 recipient: u32,
628 },
629
630 HrmpChannelClosing {
641 #[codec(compact)]
642 initiator: u32,
643 #[codec(compact)]
644 sender: u32,
645 #[codec(compact)]
646 recipient: u32,
647 },
648
649 ClearOrigin,
661
662 DescendOrigin(InteriorMultiLocation),
668
669 ReportError(QueryResponseInfo),
679
680 DepositAsset { assets: MultiAssetFilter, beneficiary: MultiLocation },
690
691 DepositReserveAsset { assets: MultiAssetFilter, dest: MultiLocation, xcm: Xcm<()> },
708
709 ExchangeAsset { give: MultiAssetFilter, want: MultiAssets, maximal: bool },
725
726 InitiateReserveWithdraw { assets: MultiAssetFilter, reserve: MultiLocation, xcm: Xcm<()> },
741
742 InitiateTeleport { assets: MultiAssetFilter, dest: MultiLocation, xcm: Xcm<()> },
757
758 ReportHolding { response_info: QueryResponseInfo, assets: MultiAssetFilter },
771
772 #[builder(pays_fees)]
784 BuyExecution { fees: MultiAsset, weight_limit: WeightLimit },
785
786 RefundSurplus,
792
793 SetErrorHandler(Xcm<Call>),
808
809 SetAppendix(Xcm<Call>),
824
825 ClearError,
831
832 #[builder(loads_holding)]
843 ClaimAsset { assets: MultiAssets, ticket: MultiLocation },
844
845 Trap(#[codec(compact)] u64),
852
853 SubscribeVersion {
866 #[codec(compact)]
867 query_id: QueryId,
868 max_response_weight: Weight,
869 },
870
871 UnsubscribeVersion,
877
878 BurnAsset(MultiAssets),
888
889 ExpectAsset(MultiAssets),
896
897 ExpectOrigin(Option<MultiLocation>),
904
905 ExpectError(Option<(u32, Error)>),
912
913 ExpectTransactStatus(MaybeErrorCode),
922
923 QueryPallet { module_name: Vec<u8>, response_info: QueryResponseInfo },
938
939 ExpectPallet {
958 #[codec(compact)]
959 index: u32,
960 name: Vec<u8>,
961 module_name: Vec<u8>,
962 #[codec(compact)]
963 crate_major: u32,
964 #[codec(compact)]
965 min_crate_minor: u32,
966 },
967
968 ReportTransactStatus(QueryResponseInfo),
980
981 ClearTransactStatus,
989
990 UniversalOrigin(Junction),
1004
1005 ExportMessage { network: NetworkId, destination: InteriorMultiLocation, xcm: Xcm<()> },
1025
1026 LockAsset { asset: MultiAsset, unlocker: MultiLocation },
1041
1042 UnlockAsset { asset: MultiAsset, target: MultiLocation },
1054
1055 NoteUnlockable { asset: MultiAsset, owner: MultiLocation },
1069
1070 RequestUnlock { asset: MultiAsset, locker: MultiLocation },
1083
1084 SetFeesMode { jit_withdraw: bool },
1093
1094 SetTopic([u8; 32]),
1106
1107 ClearTopic,
1113
1114 AliasOrigin(MultiLocation),
1120
1121 UnpaidExecution { weight_limit: WeightLimit, check_origin: Option<MultiLocation> },
1132}
1133
1134impl<Call> Xcm<Call> {
1135 pub fn into<C>(self) -> Xcm<C> {
1136 Xcm::from(self)
1137 }
1138 pub fn from<C>(xcm: Xcm<C>) -> Self {
1139 Self(xcm.0.into_iter().map(Instruction::<Call>::from).collect())
1140 }
1141}
1142
1143impl<Call> Instruction<Call> {
1144 pub fn into<C>(self) -> Instruction<C> {
1145 Instruction::from(self)
1146 }
1147 pub fn from<C>(xcm: Instruction<C>) -> Self {
1148 use Instruction::*;
1149 match xcm {
1150 WithdrawAsset(assets) => WithdrawAsset(assets),
1151 ReserveAssetDeposited(assets) => ReserveAssetDeposited(assets),
1152 ReceiveTeleportedAsset(assets) => ReceiveTeleportedAsset(assets),
1153 QueryResponse { query_id, response, max_weight, querier } =>
1154 QueryResponse { query_id, response, max_weight, querier },
1155 TransferAsset { assets, beneficiary } => TransferAsset { assets, beneficiary },
1156 TransferReserveAsset { assets, dest, xcm } =>
1157 TransferReserveAsset { assets, dest, xcm },
1158 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
1159 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
1160 HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient },
1161 HrmpChannelClosing { initiator, sender, recipient } =>
1162 HrmpChannelClosing { initiator, sender, recipient },
1163 Transact { origin_kind, require_weight_at_most, call } =>
1164 Transact { origin_kind, require_weight_at_most, call: call.into() },
1165 ReportError(response_info) => ReportError(response_info),
1166 DepositAsset { assets, beneficiary } => DepositAsset { assets, beneficiary },
1167 DepositReserveAsset { assets, dest, xcm } => DepositReserveAsset { assets, dest, xcm },
1168 ExchangeAsset { give, want, maximal } => ExchangeAsset { give, want, maximal },
1169 InitiateReserveWithdraw { assets, reserve, xcm } =>
1170 InitiateReserveWithdraw { assets, reserve, xcm },
1171 InitiateTeleport { assets, dest, xcm } => InitiateTeleport { assets, dest, xcm },
1172 ReportHolding { response_info, assets } => ReportHolding { response_info, assets },
1173 BuyExecution { fees, weight_limit } => BuyExecution { fees, weight_limit },
1174 ClearOrigin => ClearOrigin,
1175 DescendOrigin(who) => DescendOrigin(who),
1176 RefundSurplus => RefundSurplus,
1177 SetErrorHandler(xcm) => SetErrorHandler(xcm.into()),
1178 SetAppendix(xcm) => SetAppendix(xcm.into()),
1179 ClearError => ClearError,
1180 ClaimAsset { assets, ticket } => ClaimAsset { assets, ticket },
1181 Trap(code) => Trap(code),
1182 SubscribeVersion { query_id, max_response_weight } =>
1183 SubscribeVersion { query_id, max_response_weight },
1184 UnsubscribeVersion => UnsubscribeVersion,
1185 BurnAsset(assets) => BurnAsset(assets),
1186 ExpectAsset(assets) => ExpectAsset(assets),
1187 ExpectOrigin(origin) => ExpectOrigin(origin),
1188 ExpectError(error) => ExpectError(error),
1189 ExpectTransactStatus(transact_status) => ExpectTransactStatus(transact_status),
1190 QueryPallet { module_name, response_info } =>
1191 QueryPallet { module_name, response_info },
1192 ExpectPallet { index, name, module_name, crate_major, min_crate_minor } =>
1193 ExpectPallet { index, name, module_name, crate_major, min_crate_minor },
1194 ReportTransactStatus(response_info) => ReportTransactStatus(response_info),
1195 ClearTransactStatus => ClearTransactStatus,
1196 UniversalOrigin(j) => UniversalOrigin(j),
1197 ExportMessage { network, destination, xcm } =>
1198 ExportMessage { network, destination, xcm },
1199 LockAsset { asset, unlocker } => LockAsset { asset, unlocker },
1200 UnlockAsset { asset, target } => UnlockAsset { asset, target },
1201 NoteUnlockable { asset, owner } => NoteUnlockable { asset, owner },
1202 RequestUnlock { asset, locker } => RequestUnlock { asset, locker },
1203 SetFeesMode { jit_withdraw } => SetFeesMode { jit_withdraw },
1204 SetTopic(topic) => SetTopic(topic),
1205 ClearTopic => ClearTopic,
1206 AliasOrigin(location) => AliasOrigin(location),
1207 UnpaidExecution { weight_limit, check_origin } =>
1208 UnpaidExecution { weight_limit, check_origin },
1209 }
1210 }
1211}
1212
1213impl<Call, W: XcmWeightInfo<Call>> GetWeight<W> for Instruction<Call> {
1215 fn weight(&self) -> Weight {
1216 use Instruction::*;
1217 match self {
1218 WithdrawAsset(assets) => W::withdraw_asset(assets),
1219 ReserveAssetDeposited(assets) => W::reserve_asset_deposited(assets),
1220 ReceiveTeleportedAsset(assets) => W::receive_teleported_asset(assets),
1221 QueryResponse { query_id, response, max_weight, querier } =>
1222 W::query_response(query_id, response, max_weight, querier),
1223 TransferAsset { assets, beneficiary } => W::transfer_asset(assets, beneficiary),
1224 TransferReserveAsset { assets, dest, xcm } =>
1225 W::transfer_reserve_asset(&assets, dest, xcm),
1226 Transact { origin_kind, require_weight_at_most, call } =>
1227 W::transact(origin_kind, require_weight_at_most, call),
1228 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
1229 W::hrmp_new_channel_open_request(sender, max_message_size, max_capacity),
1230 HrmpChannelAccepted { recipient } => W::hrmp_channel_accepted(recipient),
1231 HrmpChannelClosing { initiator, sender, recipient } =>
1232 W::hrmp_channel_closing(initiator, sender, recipient),
1233 ClearOrigin => W::clear_origin(),
1234 DescendOrigin(who) => W::descend_origin(who),
1235 ReportError(response_info) => W::report_error(&response_info),
1236 DepositAsset { assets, beneficiary } => W::deposit_asset(assets, beneficiary),
1237 DepositReserveAsset { assets, dest, xcm } =>
1238 W::deposit_reserve_asset(assets, dest, xcm),
1239 ExchangeAsset { give, want, maximal } => W::exchange_asset(give, want, maximal),
1240 InitiateReserveWithdraw { assets, reserve, xcm } =>
1241 W::initiate_reserve_withdraw(assets, reserve, xcm),
1242 InitiateTeleport { assets, dest, xcm } => W::initiate_teleport(assets, dest, xcm),
1243 ReportHolding { response_info, assets } => W::report_holding(&response_info, &assets),
1244 BuyExecution { fees, weight_limit } => W::buy_execution(fees, weight_limit),
1245 RefundSurplus => W::refund_surplus(),
1246 SetErrorHandler(xcm) => W::set_error_handler(xcm),
1247 SetAppendix(xcm) => W::set_appendix(xcm),
1248 ClearError => W::clear_error(),
1249 ClaimAsset { assets, ticket } => W::claim_asset(assets, ticket),
1250 Trap(code) => W::trap(code),
1251 SubscribeVersion { query_id, max_response_weight } =>
1252 W::subscribe_version(query_id, max_response_weight),
1253 UnsubscribeVersion => W::unsubscribe_version(),
1254 BurnAsset(assets) => W::burn_asset(assets),
1255 ExpectAsset(assets) => W::expect_asset(assets),
1256 ExpectOrigin(origin) => W::expect_origin(origin),
1257 ExpectError(error) => W::expect_error(error),
1258 ExpectTransactStatus(transact_status) => W::expect_transact_status(transact_status),
1259 QueryPallet { module_name, response_info } =>
1260 W::query_pallet(module_name, response_info),
1261 ExpectPallet { index, name, module_name, crate_major, min_crate_minor } =>
1262 W::expect_pallet(index, name, module_name, crate_major, min_crate_minor),
1263 ReportTransactStatus(response_info) => W::report_transact_status(response_info),
1264 ClearTransactStatus => W::clear_transact_status(),
1265 UniversalOrigin(j) => W::universal_origin(j),
1266 ExportMessage { network, destination, xcm } =>
1267 W::export_message(network, destination, xcm),
1268 LockAsset { asset, unlocker } => W::lock_asset(asset, unlocker),
1269 UnlockAsset { asset, target } => W::unlock_asset(asset, target),
1270 NoteUnlockable { asset, owner } => W::note_unlockable(asset, owner),
1271 RequestUnlock { asset, locker } => W::request_unlock(asset, locker),
1272 SetFeesMode { jit_withdraw } => W::set_fees_mode(jit_withdraw),
1273 SetTopic(topic) => W::set_topic(topic),
1274 ClearTopic => W::clear_topic(),
1275 AliasOrigin(location) => W::alias_origin(location),
1276 UnpaidExecution { weight_limit, check_origin } =>
1277 W::unpaid_execution(weight_limit, check_origin),
1278 }
1279 }
1280}
1281
1282pub mod opaque {
1283 pub type Xcm = super::Xcm<()>;
1286
1287 pub type Instruction = super::Instruction<()>;
1290}
1291
1292impl<Call> TryFrom<NewXcm<Call>> for Xcm<Call> {
1294 type Error = ();
1295 fn try_from(new_xcm: NewXcm<Call>) -> result::Result<Self, Self::Error> {
1296 Ok(Xcm(new_xcm.0.into_iter().map(TryInto::try_into).collect::<result::Result<_, _>>()?))
1297 }
1298}
1299
1300impl<Call> TryFrom<NewInstruction<Call>> for Instruction<Call> {
1302 type Error = ();
1303 fn try_from(new_instruction: NewInstruction<Call>) -> result::Result<Self, Self::Error> {
1304 use NewInstruction::*;
1305 Ok(match new_instruction {
1306 WithdrawAsset(assets) => Self::WithdrawAsset(assets.try_into()?),
1307 ReserveAssetDeposited(assets) => Self::ReserveAssetDeposited(assets.try_into()?),
1308 ReceiveTeleportedAsset(assets) => Self::ReceiveTeleportedAsset(assets.try_into()?),
1309 QueryResponse { query_id, response, max_weight, querier: Some(querier) } =>
1310 Self::QueryResponse {
1311 query_id,
1312 querier: querier.try_into()?,
1313 response: response.try_into()?,
1314 max_weight,
1315 },
1316 QueryResponse { query_id, response, max_weight, querier: None } =>
1317 Self::QueryResponse {
1318 query_id,
1319 querier: None,
1320 response: response.try_into()?,
1321 max_weight,
1322 },
1323 TransferAsset { assets, beneficiary } => Self::TransferAsset {
1324 assets: assets.try_into()?,
1325 beneficiary: beneficiary.try_into()?,
1326 },
1327 TransferReserveAsset { assets, dest, xcm } => Self::TransferReserveAsset {
1328 assets: assets.try_into()?,
1329 dest: dest.try_into()?,
1330 xcm: xcm.try_into()?,
1331 },
1332 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
1333 Self::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
1334 HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient },
1335 HrmpChannelClosing { initiator, sender, recipient } =>
1336 Self::HrmpChannelClosing { initiator, sender, recipient },
1337 Transact { origin_kind, require_weight_at_most, call } =>
1338 Self::Transact { origin_kind, require_weight_at_most, call: call.into() },
1339 ReportError(response_info) => Self::ReportError(QueryResponseInfo {
1340 query_id: response_info.query_id,
1341 destination: response_info.destination.try_into().map_err(|_| ())?,
1342 max_weight: response_info.max_weight,
1343 }),
1344 DepositAsset { assets, beneficiary } => {
1345 let beneficiary = beneficiary.try_into()?;
1346 let assets = assets.try_into()?;
1347 Self::DepositAsset { assets, beneficiary }
1348 },
1349 DepositReserveAsset { assets, dest, xcm } => {
1350 let dest = dest.try_into()?;
1351 let xcm = xcm.try_into()?;
1352 let assets = assets.try_into()?;
1353 Self::DepositReserveAsset { assets, dest, xcm }
1354 },
1355 ExchangeAsset { give, want, maximal } => {
1356 let give = give.try_into()?;
1357 let want = want.try_into()?;
1358 Self::ExchangeAsset { give, want, maximal }
1359 },
1360 InitiateReserveWithdraw { assets, reserve, xcm } => {
1361 let assets = assets.try_into()?;
1363 let reserve = reserve.try_into()?;
1364 let xcm = xcm.try_into()?;
1365 Self::InitiateReserveWithdraw { assets, reserve, xcm }
1366 },
1367 InitiateTeleport { assets, dest, xcm } => {
1368 let assets = assets.try_into()?;
1370 let dest = dest.try_into()?;
1371 let xcm = xcm.try_into()?;
1372 Self::InitiateTeleport { assets, dest, xcm }
1373 },
1374 ReportHolding { response_info, assets } => {
1375 let response_info = QueryResponseInfo {
1376 destination: response_info.destination.try_into().map_err(|_| ())?,
1377 query_id: response_info.query_id,
1378 max_weight: response_info.max_weight,
1379 };
1380 Self::ReportHolding { response_info, assets: assets.try_into()? }
1381 },
1382 BuyExecution { fees, weight_limit } => {
1383 let fees = fees.try_into()?;
1384 let weight_limit = weight_limit.into();
1385 Self::BuyExecution { fees, weight_limit }
1386 },
1387 ClearOrigin => Self::ClearOrigin,
1388 DescendOrigin(who) => Self::DescendOrigin(who.try_into()?),
1389 RefundSurplus => Self::RefundSurplus,
1390 SetErrorHandler(xcm) => Self::SetErrorHandler(xcm.try_into()?),
1391 SetAppendix(xcm) => Self::SetAppendix(xcm.try_into()?),
1392 ClearError => Self::ClearError,
1393 ClaimAsset { assets, ticket } => {
1394 let assets = assets.try_into()?;
1395 let ticket = ticket.try_into()?;
1396 Self::ClaimAsset { assets, ticket }
1397 },
1398 Trap(code) => Self::Trap(code),
1399 SubscribeVersion { query_id, max_response_weight } =>
1400 Self::SubscribeVersion { query_id, max_response_weight },
1401 UnsubscribeVersion => Self::UnsubscribeVersion,
1402 BurnAsset(assets) => Self::BurnAsset(assets.try_into()?),
1403 ExpectAsset(assets) => Self::ExpectAsset(assets.try_into()?),
1404 ExpectOrigin(maybe_origin) =>
1405 Self::ExpectOrigin(maybe_origin.map(|origin| origin.try_into()).transpose()?),
1406 ExpectError(maybe_error) => Self::ExpectError(maybe_error),
1407 ExpectTransactStatus(maybe_error_code) => Self::ExpectTransactStatus(maybe_error_code),
1408 QueryPallet { module_name, response_info } =>
1409 Self::QueryPallet { module_name, response_info: response_info.try_into()? },
1410 ExpectPallet { index, name, module_name, crate_major, min_crate_minor } =>
1411 Self::ExpectPallet { index, name, module_name, crate_major, min_crate_minor },
1412 ReportTransactStatus(response_info) =>
1413 Self::ReportTransactStatus(response_info.try_into()?),
1414 ClearTransactStatus => Self::ClearTransactStatus,
1415 UniversalOrigin(junction) => Self::UniversalOrigin(junction.try_into()?),
1416 ExportMessage { network, destination, xcm } => Self::ExportMessage {
1417 network: network.into(),
1418 destination: destination.try_into()?,
1419 xcm: xcm.try_into()?,
1420 },
1421 LockAsset { asset, unlocker } =>
1422 Self::LockAsset { asset: asset.try_into()?, unlocker: unlocker.try_into()? },
1423 UnlockAsset { asset, target } =>
1424 Self::UnlockAsset { asset: asset.try_into()?, target: target.try_into()? },
1425 NoteUnlockable { asset, owner } =>
1426 Self::NoteUnlockable { asset: asset.try_into()?, owner: owner.try_into()? },
1427 RequestUnlock { asset, locker } =>
1428 Self::RequestUnlock { asset: asset.try_into()?, locker: locker.try_into()? },
1429 SetFeesMode { jit_withdraw } => Self::SetFeesMode { jit_withdraw },
1430 SetTopic(topic) => Self::SetTopic(topic),
1431 ClearTopic => Self::ClearTopic,
1432 AliasOrigin(location) => Self::AliasOrigin(location.try_into()?),
1433 UnpaidExecution { weight_limit, check_origin } => Self::UnpaidExecution {
1434 weight_limit,
1435 check_origin: check_origin.map(|origin| origin.try_into()).transpose()?,
1436 },
1437 })
1438 }
1439}
1440
1441#[cfg(test)]
1442mod tests {
1443 use super::{prelude::*, *};
1444 use crate::MAX_INSTRUCTIONS_TO_DECODE;
1445
1446 #[test]
1447 fn decoding_respects_limit() {
1448 let max_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize]);
1449 let encoded = max_xcm.encode();
1450 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_ok());
1451
1452 let big_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize + 1]);
1453 let encoded = big_xcm.encode();
1454 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1455
1456 let nested_xcm = Xcm::<()>(vec![
1457 DepositReserveAsset {
1458 assets: All.into(),
1459 dest: Here.into(),
1460 xcm: max_xcm,
1461 };
1462 (MAX_INSTRUCTIONS_TO_DECODE / 2) as usize
1463 ]);
1464 let encoded = nested_xcm.encode();
1465 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1466
1467 let even_more_nested_xcm = Xcm::<()>(vec![SetAppendix(nested_xcm); 64]);
1468 let encoded = even_more_nested_xcm.encode();
1469 assert_eq!(encoded.len(), 342530);
1470 assert_eq!(MAX_INSTRUCTIONS_TO_DECODE, 100, "precondition");
1472 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1473 }
1474}