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 },
334 Version(version) => Self::Version(version),
335 PalletsInfo(pallet_info) => {
336 let inner = pallet_info
337 .into_iter()
338 .map(TryInto::try_into)
339 .collect::<result::Result<Vec<_>, _>>()?;
340 Self::PalletsInfo(
341 BoundedVec::<PalletInfo, MaxPalletsInfo>::try_from(inner).map_err(|_| ())?,
342 )
343 },
344 DispatchResult(maybe_error) => {
345 Self::DispatchResult(maybe_error.try_into().map_err(|_| ())?)
346 },
347 })
348 }
349}
350
351#[derive(Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo)]
353#[scale_info(replace_segment("staging_xcm", "xcm"))]
354#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
355pub struct QueryResponseInfo {
356 pub destination: MultiLocation,
358 #[codec(compact)]
360 pub query_id: QueryId,
361 pub max_weight: Weight,
363}
364
365impl TryFrom<NewQueryResponseInfo> for QueryResponseInfo {
366 type Error = ();
367
368 fn try_from(new: NewQueryResponseInfo) -> result::Result<Self, Self::Error> {
369 Ok(Self {
370 destination: new.destination.try_into()?,
371 query_id: new.query_id,
372 max_weight: new.max_weight,
373 })
374 }
375}
376
377#[derive(Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo)]
379#[scale_info(replace_segment("staging_xcm", "xcm"))]
380#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
381pub enum WeightLimit {
382 Unlimited,
384 Limited(Weight),
386}
387
388impl From<Option<Weight>> for WeightLimit {
389 fn from(x: Option<Weight>) -> Self {
390 match x {
391 Some(w) => WeightLimit::Limited(w),
392 None => WeightLimit::Unlimited,
393 }
394 }
395}
396
397impl From<WeightLimit> for Option<Weight> {
398 fn from(x: WeightLimit) -> Self {
399 match x {
400 WeightLimit::Limited(w) => Some(w),
401 WeightLimit::Unlimited => None,
402 }
403 }
404}
405
406#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo)]
408#[scale_info(replace_segment("staging_xcm", "xcm"))]
409#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
410pub enum OriginKind {
411 Native,
416
417 SovereignAccount,
420
421 Superuser,
424
425 Xcm,
429}
430
431#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)]
433pub struct XcmContext {
434 pub origin: Option<MultiLocation>,
436 pub message_id: XcmHash,
439 pub topic: Option<[u8; 32]>,
441}
442
443impl XcmContext {
444 #[deprecated = "Use `with_message_id` instead."]
447 pub fn with_message_hash(message_id: XcmHash) -> XcmContext {
448 XcmContext { origin: None, message_id, topic: None }
449 }
450
451 pub fn with_message_id(message_id: XcmHash) -> XcmContext {
454 XcmContext { origin: None, message_id, topic: None }
455 }
456}
457
458#[derive(
467 Encode,
468 Decode,
469 DecodeWithMemTracking,
470 TypeInfo,
471 xcm_procedural::XcmWeightInfoTrait,
472 xcm_procedural::Builder,
473)]
474#[derive_where(Clone, Eq, PartialEq, Debug)]
475#[codec(encode_bound())]
476#[codec(decode_bound())]
477#[codec(decode_with_mem_tracking_bound())]
478#[scale_info(bounds(), skip_type_params(Call))]
479#[scale_info(replace_segment("staging_xcm", "xcm"))]
480#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
481pub enum Instruction<Call> {
482 #[builder(loads_holding)]
491 WithdrawAsset(MultiAssets),
492
493 #[builder(loads_holding)]
505 ReserveAssetDeposited(MultiAssets),
506
507 #[builder(loads_holding)]
519 ReceiveTeleportedAsset(MultiAssets),
520
521 QueryResponse {
539 #[codec(compact)]
540 query_id: QueryId,
541 response: Response,
542 max_weight: Weight,
543 querier: Option<MultiLocation>,
544 },
545
546 TransferAsset { assets: MultiAssets, beneficiary: MultiLocation },
558
559 TransferReserveAsset { assets: MultiAssets, dest: MultiLocation, xcm: Xcm<()> },
578
579 Transact { origin_kind: OriginKind, require_weight_at_most: Weight, call: DoubleEncoded<Call> },
595
596 HrmpNewChannelOpenRequest {
608 #[codec(compact)]
609 sender: u32,
610 #[codec(compact)]
611 max_message_size: u32,
612 #[codec(compact)]
613 max_capacity: u32,
614 },
615
616 HrmpChannelAccepted {
626 #[codec(compact)]
629 recipient: u32,
630 },
631
632 HrmpChannelClosing {
643 #[codec(compact)]
644 initiator: u32,
645 #[codec(compact)]
646 sender: u32,
647 #[codec(compact)]
648 recipient: u32,
649 },
650
651 ClearOrigin,
663
664 DescendOrigin(InteriorMultiLocation),
670
671 ReportError(QueryResponseInfo),
681
682 DepositAsset { assets: MultiAssetFilter, beneficiary: MultiLocation },
692
693 DepositReserveAsset { assets: MultiAssetFilter, dest: MultiLocation, xcm: Xcm<()> },
710
711 ExchangeAsset { give: MultiAssetFilter, want: MultiAssets, maximal: bool },
727
728 InitiateReserveWithdraw { assets: MultiAssetFilter, reserve: MultiLocation, xcm: Xcm<()> },
743
744 InitiateTeleport { assets: MultiAssetFilter, dest: MultiLocation, xcm: Xcm<()> },
759
760 ReportHolding { response_info: QueryResponseInfo, assets: MultiAssetFilter },
773
774 #[builder(pays_fees)]
786 BuyExecution { fees: MultiAsset, weight_limit: WeightLimit },
787
788 RefundSurplus,
794
795 SetErrorHandler(Xcm<Call>),
810
811 SetAppendix(Xcm<Call>),
826
827 ClearError,
833
834 #[builder(loads_holding)]
845 ClaimAsset { assets: MultiAssets, ticket: MultiLocation },
846
847 Trap(#[codec(compact)] u64),
854
855 SubscribeVersion {
868 #[codec(compact)]
869 query_id: QueryId,
870 max_response_weight: Weight,
871 },
872
873 UnsubscribeVersion,
879
880 BurnAsset(MultiAssets),
890
891 ExpectAsset(MultiAssets),
898
899 ExpectOrigin(Option<MultiLocation>),
906
907 ExpectError(Option<(u32, Error)>),
914
915 ExpectTransactStatus(MaybeErrorCode),
924
925 QueryPallet { module_name: Vec<u8>, response_info: QueryResponseInfo },
940
941 ExpectPallet {
960 #[codec(compact)]
961 index: u32,
962 name: Vec<u8>,
963 module_name: Vec<u8>,
964 #[codec(compact)]
965 crate_major: u32,
966 #[codec(compact)]
967 min_crate_minor: u32,
968 },
969
970 ReportTransactStatus(QueryResponseInfo),
982
983 ClearTransactStatus,
991
992 UniversalOrigin(Junction),
1006
1007 ExportMessage { network: NetworkId, destination: InteriorMultiLocation, xcm: Xcm<()> },
1027
1028 LockAsset { asset: MultiAsset, unlocker: MultiLocation },
1043
1044 UnlockAsset { asset: MultiAsset, target: MultiLocation },
1056
1057 NoteUnlockable { asset: MultiAsset, owner: MultiLocation },
1071
1072 RequestUnlock { asset: MultiAsset, locker: MultiLocation },
1085
1086 SetFeesMode { jit_withdraw: bool },
1095
1096 SetTopic([u8; 32]),
1108
1109 ClearTopic,
1115
1116 AliasOrigin(MultiLocation),
1122
1123 UnpaidExecution { weight_limit: WeightLimit, check_origin: Option<MultiLocation> },
1134}
1135
1136impl<Call> Xcm<Call> {
1137 pub fn into<C>(self) -> Xcm<C> {
1138 Xcm::from(self)
1139 }
1140 pub fn from<C>(xcm: Xcm<C>) -> Self {
1141 Self(xcm.0.into_iter().map(Instruction::<Call>::from).collect())
1142 }
1143}
1144
1145impl<Call> Instruction<Call> {
1146 pub fn into<C>(self) -> Instruction<C> {
1147 Instruction::from(self)
1148 }
1149 pub fn from<C>(xcm: Instruction<C>) -> Self {
1150 use Instruction::*;
1151 match xcm {
1152 WithdrawAsset(assets) => WithdrawAsset(assets),
1153 ReserveAssetDeposited(assets) => ReserveAssetDeposited(assets),
1154 ReceiveTeleportedAsset(assets) => ReceiveTeleportedAsset(assets),
1155 QueryResponse { query_id, response, max_weight, querier } => {
1156 QueryResponse { query_id, response, max_weight, querier }
1157 },
1158 TransferAsset { assets, beneficiary } => TransferAsset { assets, beneficiary },
1159 TransferReserveAsset { assets, dest, xcm } => {
1160 TransferReserveAsset { assets, dest, xcm }
1161 },
1162 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => {
1163 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity }
1164 },
1165 HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient },
1166 HrmpChannelClosing { initiator, sender, recipient } => {
1167 HrmpChannelClosing { initiator, sender, recipient }
1168 },
1169 Transact { origin_kind, require_weight_at_most, call } => {
1170 Transact { origin_kind, require_weight_at_most, call: call.into() }
1171 },
1172 ReportError(response_info) => ReportError(response_info),
1173 DepositAsset { assets, beneficiary } => DepositAsset { assets, beneficiary },
1174 DepositReserveAsset { assets, dest, xcm } => DepositReserveAsset { assets, dest, xcm },
1175 ExchangeAsset { give, want, maximal } => ExchangeAsset { give, want, maximal },
1176 InitiateReserveWithdraw { assets, reserve, xcm } => {
1177 InitiateReserveWithdraw { assets, reserve, xcm }
1178 },
1179 InitiateTeleport { assets, dest, xcm } => InitiateTeleport { assets, dest, xcm },
1180 ReportHolding { response_info, assets } => ReportHolding { response_info, assets },
1181 BuyExecution { fees, weight_limit } => BuyExecution { fees, weight_limit },
1182 ClearOrigin => ClearOrigin,
1183 DescendOrigin(who) => DescendOrigin(who),
1184 RefundSurplus => RefundSurplus,
1185 SetErrorHandler(xcm) => SetErrorHandler(xcm.into()),
1186 SetAppendix(xcm) => SetAppendix(xcm.into()),
1187 ClearError => ClearError,
1188 ClaimAsset { assets, ticket } => ClaimAsset { assets, ticket },
1189 Trap(code) => Trap(code),
1190 SubscribeVersion { query_id, max_response_weight } => {
1191 SubscribeVersion { query_id, max_response_weight }
1192 },
1193 UnsubscribeVersion => UnsubscribeVersion,
1194 BurnAsset(assets) => BurnAsset(assets),
1195 ExpectAsset(assets) => ExpectAsset(assets),
1196 ExpectOrigin(origin) => ExpectOrigin(origin),
1197 ExpectError(error) => ExpectError(error),
1198 ExpectTransactStatus(transact_status) => ExpectTransactStatus(transact_status),
1199 QueryPallet { module_name, response_info } => {
1200 QueryPallet { module_name, response_info }
1201 },
1202 ExpectPallet { index, name, module_name, crate_major, min_crate_minor } => {
1203 ExpectPallet { index, name, module_name, crate_major, min_crate_minor }
1204 },
1205 ReportTransactStatus(response_info) => ReportTransactStatus(response_info),
1206 ClearTransactStatus => ClearTransactStatus,
1207 UniversalOrigin(j) => UniversalOrigin(j),
1208 ExportMessage { network, destination, xcm } => {
1209 ExportMessage { network, destination, xcm }
1210 },
1211 LockAsset { asset, unlocker } => LockAsset { asset, unlocker },
1212 UnlockAsset { asset, target } => UnlockAsset { asset, target },
1213 NoteUnlockable { asset, owner } => NoteUnlockable { asset, owner },
1214 RequestUnlock { asset, locker } => RequestUnlock { asset, locker },
1215 SetFeesMode { jit_withdraw } => SetFeesMode { jit_withdraw },
1216 SetTopic(topic) => SetTopic(topic),
1217 ClearTopic => ClearTopic,
1218 AliasOrigin(location) => AliasOrigin(location),
1219 UnpaidExecution { weight_limit, check_origin } => {
1220 UnpaidExecution { weight_limit, check_origin }
1221 },
1222 }
1223 }
1224}
1225
1226impl<Call, W: XcmWeightInfo<Call>> GetWeight<W> for Instruction<Call> {
1228 fn weight(&self) -> Weight {
1229 use Instruction::*;
1230 match self {
1231 WithdrawAsset(assets) => W::withdraw_asset(assets),
1232 ReserveAssetDeposited(assets) => W::reserve_asset_deposited(assets),
1233 ReceiveTeleportedAsset(assets) => W::receive_teleported_asset(assets),
1234 QueryResponse { query_id, response, max_weight, querier } => {
1235 W::query_response(query_id, response, max_weight, querier)
1236 },
1237 TransferAsset { assets, beneficiary } => W::transfer_asset(assets, beneficiary),
1238 TransferReserveAsset { assets, dest, xcm } => {
1239 W::transfer_reserve_asset(&assets, dest, xcm)
1240 },
1241 Transact { origin_kind, require_weight_at_most, call } => {
1242 W::transact(origin_kind, require_weight_at_most, call)
1243 },
1244 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => {
1245 W::hrmp_new_channel_open_request(sender, max_message_size, max_capacity)
1246 },
1247 HrmpChannelAccepted { recipient } => W::hrmp_channel_accepted(recipient),
1248 HrmpChannelClosing { initiator, sender, recipient } => {
1249 W::hrmp_channel_closing(initiator, sender, recipient)
1250 },
1251 ClearOrigin => W::clear_origin(),
1252 DescendOrigin(who) => W::descend_origin(who),
1253 ReportError(response_info) => W::report_error(&response_info),
1254 DepositAsset { assets, beneficiary } => W::deposit_asset(assets, beneficiary),
1255 DepositReserveAsset { assets, dest, xcm } => {
1256 W::deposit_reserve_asset(assets, dest, xcm)
1257 },
1258 ExchangeAsset { give, want, maximal } => W::exchange_asset(give, want, maximal),
1259 InitiateReserveWithdraw { assets, reserve, xcm } => {
1260 W::initiate_reserve_withdraw(assets, reserve, xcm)
1261 },
1262 InitiateTeleport { assets, dest, xcm } => W::initiate_teleport(assets, dest, xcm),
1263 ReportHolding { response_info, assets } => W::report_holding(&response_info, &assets),
1264 BuyExecution { fees, weight_limit } => W::buy_execution(fees, weight_limit),
1265 RefundSurplus => W::refund_surplus(),
1266 SetErrorHandler(xcm) => W::set_error_handler(xcm),
1267 SetAppendix(xcm) => W::set_appendix(xcm),
1268 ClearError => W::clear_error(),
1269 ClaimAsset { assets, ticket } => W::claim_asset(assets, ticket),
1270 Trap(code) => W::trap(code),
1271 SubscribeVersion { query_id, max_response_weight } => {
1272 W::subscribe_version(query_id, max_response_weight)
1273 },
1274 UnsubscribeVersion => W::unsubscribe_version(),
1275 BurnAsset(assets) => W::burn_asset(assets),
1276 ExpectAsset(assets) => W::expect_asset(assets),
1277 ExpectOrigin(origin) => W::expect_origin(origin),
1278 ExpectError(error) => W::expect_error(error),
1279 ExpectTransactStatus(transact_status) => W::expect_transact_status(transact_status),
1280 QueryPallet { module_name, response_info } => {
1281 W::query_pallet(module_name, response_info)
1282 },
1283 ExpectPallet { index, name, module_name, crate_major, min_crate_minor } => {
1284 W::expect_pallet(index, name, module_name, crate_major, min_crate_minor)
1285 },
1286 ReportTransactStatus(response_info) => W::report_transact_status(response_info),
1287 ClearTransactStatus => W::clear_transact_status(),
1288 UniversalOrigin(j) => W::universal_origin(j),
1289 ExportMessage { network, destination, xcm } => {
1290 W::export_message(network, destination, xcm)
1291 },
1292 LockAsset { asset, unlocker } => W::lock_asset(asset, unlocker),
1293 UnlockAsset { asset, target } => W::unlock_asset(asset, target),
1294 NoteUnlockable { asset, owner } => W::note_unlockable(asset, owner),
1295 RequestUnlock { asset, locker } => W::request_unlock(asset, locker),
1296 SetFeesMode { jit_withdraw } => W::set_fees_mode(jit_withdraw),
1297 SetTopic(topic) => W::set_topic(topic),
1298 ClearTopic => W::clear_topic(),
1299 AliasOrigin(location) => W::alias_origin(location),
1300 UnpaidExecution { weight_limit, check_origin } => {
1301 W::unpaid_execution(weight_limit, check_origin)
1302 },
1303 }
1304 }
1305}
1306
1307pub mod opaque {
1308 pub type Xcm = super::Xcm<()>;
1311
1312 pub type Instruction = super::Instruction<()>;
1315}
1316
1317impl<Call> TryFrom<NewXcm<Call>> for Xcm<Call> {
1319 type Error = ();
1320 fn try_from(new_xcm: NewXcm<Call>) -> result::Result<Self, Self::Error> {
1321 Ok(Xcm(new_xcm.0.into_iter().map(TryInto::try_into).collect::<result::Result<_, _>>()?))
1322 }
1323}
1324
1325impl<Call> TryFrom<NewInstruction<Call>> for Instruction<Call> {
1327 type Error = ();
1328 fn try_from(new_instruction: NewInstruction<Call>) -> result::Result<Self, Self::Error> {
1329 use NewInstruction::*;
1330 Ok(match new_instruction {
1331 WithdrawAsset(assets) => Self::WithdrawAsset(assets.try_into()?),
1332 ReserveAssetDeposited(assets) => Self::ReserveAssetDeposited(assets.try_into()?),
1333 ReceiveTeleportedAsset(assets) => Self::ReceiveTeleportedAsset(assets.try_into()?),
1334 QueryResponse { query_id, response, max_weight, querier: Some(querier) } => {
1335 Self::QueryResponse {
1336 query_id,
1337 querier: querier.try_into()?,
1338 response: response.try_into()?,
1339 max_weight,
1340 }
1341 },
1342 QueryResponse { query_id, response, max_weight, querier: None } => {
1343 Self::QueryResponse {
1344 query_id,
1345 querier: None,
1346 response: response.try_into()?,
1347 max_weight,
1348 }
1349 },
1350 TransferAsset { assets, beneficiary } => Self::TransferAsset {
1351 assets: assets.try_into()?,
1352 beneficiary: beneficiary.try_into()?,
1353 },
1354 TransferReserveAsset { assets, dest, xcm } => Self::TransferReserveAsset {
1355 assets: assets.try_into()?,
1356 dest: dest.try_into()?,
1357 xcm: xcm.try_into()?,
1358 },
1359 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => {
1360 Self::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity }
1361 },
1362 HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient },
1363 HrmpChannelClosing { initiator, sender, recipient } => {
1364 Self::HrmpChannelClosing { initiator, sender, recipient }
1365 },
1366 Transact { origin_kind, require_weight_at_most, call } => {
1367 Self::Transact { origin_kind, require_weight_at_most, call: call.into() }
1368 },
1369 ReportError(response_info) => Self::ReportError(QueryResponseInfo {
1370 query_id: response_info.query_id,
1371 destination: response_info.destination.try_into().map_err(|_| ())?,
1372 max_weight: response_info.max_weight,
1373 }),
1374 DepositAsset { assets, beneficiary } => {
1375 let beneficiary = beneficiary.try_into()?;
1376 let assets = assets.try_into()?;
1377 Self::DepositAsset { assets, beneficiary }
1378 },
1379 DepositReserveAsset { assets, dest, xcm } => {
1380 let dest = dest.try_into()?;
1381 let xcm = xcm.try_into()?;
1382 let assets = assets.try_into()?;
1383 Self::DepositReserveAsset { assets, dest, xcm }
1384 },
1385 ExchangeAsset { give, want, maximal } => {
1386 let give = give.try_into()?;
1387 let want = want.try_into()?;
1388 Self::ExchangeAsset { give, want, maximal }
1389 },
1390 InitiateReserveWithdraw { assets, reserve, xcm } => {
1391 let assets = assets.try_into()?;
1393 let reserve = reserve.try_into()?;
1394 let xcm = xcm.try_into()?;
1395 Self::InitiateReserveWithdraw { assets, reserve, xcm }
1396 },
1397 InitiateTeleport { assets, dest, xcm } => {
1398 let assets = assets.try_into()?;
1400 let dest = dest.try_into()?;
1401 let xcm = xcm.try_into()?;
1402 Self::InitiateTeleport { assets, dest, xcm }
1403 },
1404 ReportHolding { response_info, assets } => {
1405 let response_info = QueryResponseInfo {
1406 destination: response_info.destination.try_into().map_err(|_| ())?,
1407 query_id: response_info.query_id,
1408 max_weight: response_info.max_weight,
1409 };
1410 Self::ReportHolding { response_info, assets: assets.try_into()? }
1411 },
1412 BuyExecution { fees, weight_limit } => {
1413 let fees = fees.try_into()?;
1414 let weight_limit = weight_limit.into();
1415 Self::BuyExecution { fees, weight_limit }
1416 },
1417 ClearOrigin => Self::ClearOrigin,
1418 DescendOrigin(who) => Self::DescendOrigin(who.try_into()?),
1419 RefundSurplus => Self::RefundSurplus,
1420 SetErrorHandler(xcm) => Self::SetErrorHandler(xcm.try_into()?),
1421 SetAppendix(xcm) => Self::SetAppendix(xcm.try_into()?),
1422 ClearError => Self::ClearError,
1423 ClaimAsset { assets, ticket } => {
1424 let assets = assets.try_into()?;
1425 let ticket = ticket.try_into()?;
1426 Self::ClaimAsset { assets, ticket }
1427 },
1428 Trap(code) => Self::Trap(code),
1429 SubscribeVersion { query_id, max_response_weight } => {
1430 Self::SubscribeVersion { query_id, max_response_weight }
1431 },
1432 UnsubscribeVersion => Self::UnsubscribeVersion,
1433 BurnAsset(assets) => Self::BurnAsset(assets.try_into()?),
1434 ExpectAsset(assets) => Self::ExpectAsset(assets.try_into()?),
1435 ExpectOrigin(maybe_origin) => {
1436 Self::ExpectOrigin(maybe_origin.map(|origin| origin.try_into()).transpose()?)
1437 },
1438 ExpectError(maybe_error) => Self::ExpectError(maybe_error),
1439 ExpectTransactStatus(maybe_error_code) => Self::ExpectTransactStatus(maybe_error_code),
1440 QueryPallet { module_name, response_info } => {
1441 Self::QueryPallet { module_name, response_info: response_info.try_into()? }
1442 },
1443 ExpectPallet { index, name, module_name, crate_major, min_crate_minor } => {
1444 Self::ExpectPallet { index, name, module_name, crate_major, min_crate_minor }
1445 },
1446 ReportTransactStatus(response_info) => {
1447 Self::ReportTransactStatus(response_info.try_into()?)
1448 },
1449 ClearTransactStatus => Self::ClearTransactStatus,
1450 UniversalOrigin(junction) => Self::UniversalOrigin(junction.try_into()?),
1451 ExportMessage { network, destination, xcm } => Self::ExportMessage {
1452 network: network.into(),
1453 destination: destination.try_into()?,
1454 xcm: xcm.try_into()?,
1455 },
1456 LockAsset { asset, unlocker } => {
1457 Self::LockAsset { asset: asset.try_into()?, unlocker: unlocker.try_into()? }
1458 },
1459 UnlockAsset { asset, target } => {
1460 Self::UnlockAsset { asset: asset.try_into()?, target: target.try_into()? }
1461 },
1462 NoteUnlockable { asset, owner } => {
1463 Self::NoteUnlockable { asset: asset.try_into()?, owner: owner.try_into()? }
1464 },
1465 RequestUnlock { asset, locker } => {
1466 Self::RequestUnlock { asset: asset.try_into()?, locker: locker.try_into()? }
1467 },
1468 SetFeesMode { jit_withdraw } => Self::SetFeesMode { jit_withdraw },
1469 SetTopic(topic) => Self::SetTopic(topic),
1470 ClearTopic => Self::ClearTopic,
1471 AliasOrigin(location) => Self::AliasOrigin(location.try_into()?),
1472 UnpaidExecution { weight_limit, check_origin } => Self::UnpaidExecution {
1473 weight_limit,
1474 check_origin: check_origin.map(|origin| origin.try_into()).transpose()?,
1475 },
1476 })
1477 }
1478}
1479
1480#[cfg(test)]
1481mod tests {
1482 use super::{prelude::*, *};
1483 use crate::MAX_INSTRUCTIONS_TO_DECODE;
1484
1485 #[test]
1486 fn decoding_respects_limit() {
1487 let max_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize]);
1488 let encoded = max_xcm.encode();
1489 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_ok());
1490
1491 let big_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize + 1]);
1492 let encoded = big_xcm.encode();
1493 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1494
1495 let nested_xcm = Xcm::<()>(vec![
1496 DepositReserveAsset {
1497 assets: All.into(),
1498 dest: Here.into(),
1499 xcm: max_xcm,
1500 };
1501 (MAX_INSTRUCTIONS_TO_DECODE / 2) as usize
1502 ]);
1503 let encoded = nested_xcm.encode();
1504 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1505
1506 let even_more_nested_xcm = Xcm::<()>(vec![SetAppendix(nested_xcm); 64]);
1507 let encoded = even_more_nested_xcm.encode();
1508 assert_eq!(encoded.len(), 342530);
1509 assert_eq!(MAX_INSTRUCTIONS_TO_DECODE, 100, "precondition");
1511 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1512 }
1513}