1#[allow(deprecated)]
20use super::v2::{
21 Instruction as OldInstruction, OriginKind as OldOriginKind, Response as OldResponse,
22 WeightLimit as OldWeightLimit, Xcm as OldXcm,
23};
24use super::v4::{
25 Instruction as NewInstruction, PalletInfo as NewPalletInfo,
26 QueryResponseInfo as NewQueryResponseInfo, Response as NewResponse, Xcm as NewXcm,
27};
28use crate::DoubleEncoded;
29use alloc::{vec, vec::Vec};
30use bounded_collections::{parameter_types, BoundedVec};
31use codec::{
32 self, decode_vec_with_len, Compact, Decode, Encode, Error as CodecError, Input as CodecInput,
33 MaxEncodedLen,
34};
35use core::{fmt::Debug, result};
36use derivative::Derivative;
37use scale_info::TypeInfo;
38
39mod junction;
40pub(crate) mod junctions;
41mod multiasset;
42mod multilocation;
43mod traits;
44
45pub use junction::{BodyId, BodyPart, Junction, NetworkId};
46pub use junctions::Junctions;
47pub use multiasset::{
48 AssetId, AssetInstance, Fungibility, MultiAsset, MultiAssetFilter, MultiAssets,
49 WildFungibility, WildMultiAsset, MAX_ITEMS_IN_MULTIASSETS,
50};
51pub use multilocation::{
52 Ancestor, AncestorThen, InteriorMultiLocation, Location, MultiLocation, Parent, ParentThen,
53};
54pub use traits::{
55 send_xcm, validate_send, Error, ExecuteXcm, GetWeight, Outcome, PreparedMessage, Result,
56 SendError, SendResult, SendXcm, Weight, XcmHash,
57};
58
59#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
61#[scale_info(replace_segment("staging_xcm", "xcm"))]
62#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
63pub enum OriginKind {
64 Native,
69
70 SovereignAccount,
73
74 Superuser,
77
78 Xcm,
82}
83
84impl From<OldOriginKind> for OriginKind {
85 fn from(old: OldOriginKind) -> Self {
86 use OldOriginKind::*;
87 match old {
88 Native => Self::Native,
89 SovereignAccount => Self::SovereignAccount,
90 Superuser => Self::Superuser,
91 Xcm => Self::Xcm,
92 }
93 }
94}
95
96pub const VERSION: super::Version = 3;
98
99pub type QueryId = u64;
101
102#[derive(Derivative, Default, Encode, TypeInfo)]
103#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
104#[codec(encode_bound())]
105#[scale_info(bounds(), skip_type_params(Call))]
106#[scale_info(replace_segment("staging_xcm", "xcm"))]
107#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
108pub struct Xcm<Call>(pub Vec<Instruction<Call>>);
109
110pub const MAX_INSTRUCTIONS_TO_DECODE: u8 = 100;
114
115environmental::environmental!(instructions_count: u8);
116
117impl<Call> Decode for Xcm<Call> {
118 fn decode<I: CodecInput>(input: &mut I) -> core::result::Result<Self, CodecError> {
119 instructions_count::using_once(&mut 0, || {
120 let number_of_instructions: u32 = <Compact<u32>>::decode(input)?.into();
121 instructions_count::with(|count| {
122 *count = count.saturating_add(number_of_instructions as u8);
123 if *count > MAX_INSTRUCTIONS_TO_DECODE {
124 return Err(CodecError::from("Max instructions exceeded"))
125 }
126 Ok(())
127 })
128 .unwrap_or(Ok(()))?;
129 let decoded_instructions = decode_vec_with_len(input, number_of_instructions as usize)?;
130 Ok(Self(decoded_instructions))
131 })
132 }
133}
134
135impl<Call> Xcm<Call> {
136 pub fn new() -> Self {
138 Self(vec![])
139 }
140
141 pub fn is_empty(&self) -> bool {
143 self.0.is_empty()
144 }
145
146 pub fn len(&self) -> usize {
148 self.0.len()
149 }
150
151 pub fn inner(&self) -> &[Instruction<Call>] {
153 &self.0
154 }
155
156 pub fn inner_mut(&mut self) -> &mut Vec<Instruction<Call>> {
158 &mut self.0
159 }
160
161 pub fn into_inner(self) -> Vec<Instruction<Call>> {
163 self.0
164 }
165
166 pub fn iter(&self) -> impl Iterator<Item = &Instruction<Call>> {
168 self.0.iter()
169 }
170
171 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Instruction<Call>> {
173 self.0.iter_mut()
174 }
175
176 pub fn into_iter(self) -> impl Iterator<Item = Instruction<Call>> {
178 self.0.into_iter()
179 }
180
181 pub fn or_else(self, f: impl FnOnce() -> Self) -> Self {
184 if self.0.is_empty() {
185 f()
186 } else {
187 self
188 }
189 }
190
191 pub fn first(&self) -> Option<&Instruction<Call>> {
193 self.0.first()
194 }
195
196 pub fn last(&self) -> Option<&Instruction<Call>> {
198 self.0.last()
199 }
200
201 pub fn only(&self) -> Option<&Instruction<Call>> {
203 if self.0.len() == 1 {
204 self.0.first()
205 } else {
206 None
207 }
208 }
209
210 pub fn into_only(mut self) -> core::result::Result<Instruction<Call>, Self> {
213 if self.0.len() == 1 {
214 self.0.pop().ok_or(self)
215 } else {
216 Err(self)
217 }
218 }
219}
220
221impl<Call> From<Vec<Instruction<Call>>> for Xcm<Call> {
222 fn from(c: Vec<Instruction<Call>>) -> Self {
223 Self(c)
224 }
225}
226
227impl<Call> From<Xcm<Call>> for Vec<Instruction<Call>> {
228 fn from(c: Xcm<Call>) -> Self {
229 c.0
230 }
231}
232
233pub mod prelude {
235 mod contents {
236 pub use super::super::{
237 send_xcm, validate_send, Ancestor, AncestorThen,
238 AssetId::{self, *},
239 AssetInstance::{self, *},
240 BodyId, BodyPart, Error as XcmError, ExecuteXcm,
241 Fungibility::{self, *},
242 GetWeight,
243 Instruction::*,
244 InteriorMultiLocation,
245 Junction::{self, *},
246 Junctions::{self, *},
247 Location, MaybeErrorCode, MultiAsset,
248 MultiAssetFilter::{self, *},
249 MultiAssets, MultiLocation,
250 NetworkId::{self, *},
251 OriginKind, Outcome, PalletInfo, Parent, ParentThen, PreparedMessage, QueryId,
252 QueryResponseInfo, Response, Result as XcmResult, SendError, SendResult, SendXcm,
253 Weight,
254 WeightLimit::{self, *},
255 WildFungibility::{self, Fungible as WildFungible, NonFungible as WildNonFungible},
256 WildMultiAsset::{self, *},
257 XcmContext, XcmHash, XcmWeightInfo, VERSION as XCM_VERSION,
258 };
259 }
260 pub use super::{Instruction, Xcm};
261 pub use contents::*;
262 pub mod opaque {
263 pub use super::{
264 super::opaque::{Instruction, Xcm},
265 contents::*,
266 };
267 }
268}
269
270parameter_types! {
271 #[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
272 pub MaxPalletNameLen: u32 = 48;
273 #[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
276 pub MaxDispatchErrorLen: u32 = 128;
277 #[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
278 pub MaxPalletsInfo: u32 = 64;
279}
280
281#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
282#[scale_info(replace_segment("staging_xcm", "xcm"))]
283#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
284pub struct PalletInfo {
285 #[codec(compact)]
286 pub index: u32,
287 pub name: BoundedVec<u8, MaxPalletNameLen>,
288 pub module_name: BoundedVec<u8, MaxPalletNameLen>,
289 #[codec(compact)]
290 pub major: u32,
291 #[codec(compact)]
292 pub minor: u32,
293 #[codec(compact)]
294 pub patch: u32,
295}
296
297impl PalletInfo {
298 pub fn new(
299 index: u32,
300 name: Vec<u8>,
301 module_name: Vec<u8>,
302 major: u32,
303 minor: u32,
304 patch: u32,
305 ) -> result::Result<Self, Error> {
306 let name = BoundedVec::try_from(name).map_err(|_| Error::Overflow)?;
307 let module_name = BoundedVec::try_from(module_name).map_err(|_| Error::Overflow)?;
308
309 Ok(Self { index, name, module_name, major, minor, patch })
310 }
311}
312
313impl TryInto<NewPalletInfo> for PalletInfo {
314 type Error = ();
315
316 fn try_into(self) -> result::Result<NewPalletInfo, Self::Error> {
317 NewPalletInfo::new(
318 self.index,
319 self.name.into_inner(),
320 self.module_name.into_inner(),
321 self.major,
322 self.minor,
323 self.patch,
324 )
325 .map_err(|_| ())
326 }
327}
328
329#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
330#[scale_info(replace_segment("staging_xcm", "xcm"))]
331#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
332pub enum MaybeErrorCode {
333 Success,
334 Error(BoundedVec<u8, MaxDispatchErrorLen>),
335 TruncatedError(BoundedVec<u8, MaxDispatchErrorLen>),
336}
337
338impl From<Vec<u8>> for MaybeErrorCode {
339 fn from(v: Vec<u8>) -> Self {
340 match BoundedVec::try_from(v) {
341 Ok(error) => MaybeErrorCode::Error(error),
342 Err(error) => MaybeErrorCode::TruncatedError(BoundedVec::truncate_from(error)),
343 }
344 }
345}
346
347impl Default for MaybeErrorCode {
348 fn default() -> MaybeErrorCode {
349 MaybeErrorCode::Success
350 }
351}
352
353#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
355#[scale_info(replace_segment("staging_xcm", "xcm"))]
356#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
357pub enum Response {
358 Null,
360 Assets(MultiAssets),
362 ExecutionResult(Option<(u32, Error)>),
364 Version(super::Version),
366 PalletsInfo(BoundedVec<PalletInfo, MaxPalletsInfo>),
368 DispatchResult(MaybeErrorCode),
370}
371
372impl Default for Response {
373 fn default() -> Self {
374 Self::Null
375 }
376}
377
378impl TryFrom<NewResponse> for Response {
379 type Error = ();
380
381 fn try_from(new: NewResponse) -> result::Result<Self, Self::Error> {
382 use NewResponse::*;
383 Ok(match new {
384 Null => Self::Null,
385 Assets(assets) => Self::Assets(assets.try_into()?),
386 ExecutionResult(result) =>
387 Self::ExecutionResult(result.map(|(num, old_error)| (num, old_error.into()))),
388 Version(version) => Self::Version(version),
389 PalletsInfo(pallet_info) => {
390 let inner = pallet_info
391 .into_iter()
392 .map(TryInto::try_into)
393 .collect::<result::Result<Vec<_>, _>>()?;
394 Self::PalletsInfo(
395 BoundedVec::<PalletInfo, MaxPalletsInfo>::try_from(inner).map_err(|_| ())?,
396 )
397 },
398 DispatchResult(maybe_error) =>
399 Self::DispatchResult(maybe_error.try_into().map_err(|_| ())?),
400 })
401 }
402}
403
404#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
406#[scale_info(replace_segment("staging_xcm", "xcm"))]
407#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
408pub struct QueryResponseInfo {
409 pub destination: MultiLocation,
411 #[codec(compact)]
413 pub query_id: QueryId,
414 pub max_weight: Weight,
416}
417
418impl TryFrom<NewQueryResponseInfo> for QueryResponseInfo {
419 type Error = ();
420
421 fn try_from(new: NewQueryResponseInfo) -> result::Result<Self, Self::Error> {
422 Ok(Self {
423 destination: new.destination.try_into()?,
424 query_id: new.query_id,
425 max_weight: new.max_weight,
426 })
427 }
428}
429
430#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
432#[scale_info(replace_segment("staging_xcm", "xcm"))]
433#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
434pub enum WeightLimit {
435 Unlimited,
437 Limited(Weight),
439}
440
441impl From<Option<Weight>> for WeightLimit {
442 fn from(x: Option<Weight>) -> Self {
443 match x {
444 Some(w) => WeightLimit::Limited(w),
445 None => WeightLimit::Unlimited,
446 }
447 }
448}
449
450impl From<WeightLimit> for Option<Weight> {
451 fn from(x: WeightLimit) -> Self {
452 match x {
453 WeightLimit::Limited(w) => Some(w),
454 WeightLimit::Unlimited => None,
455 }
456 }
457}
458
459impl From<OldWeightLimit> for WeightLimit {
460 fn from(x: OldWeightLimit) -> Self {
461 use OldWeightLimit::*;
462 match x {
463 Limited(w) => Self::Limited(Weight::from_parts(w, DEFAULT_PROOF_SIZE)),
464 Unlimited => Self::Unlimited,
465 }
466 }
467}
468
469#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)]
471pub struct XcmContext {
472 pub origin: Option<MultiLocation>,
474 pub message_id: XcmHash,
477 pub topic: Option<[u8; 32]>,
479}
480
481impl XcmContext {
482 #[deprecated = "Use `with_message_id` instead."]
485 pub fn with_message_hash(message_id: XcmHash) -> XcmContext {
486 XcmContext { origin: None, message_id, topic: None }
487 }
488
489 pub fn with_message_id(message_id: XcmHash) -> XcmContext {
492 XcmContext { origin: None, message_id, topic: None }
493 }
494}
495
496#[derive(
505 Derivative,
506 Encode,
507 Decode,
508 TypeInfo,
509 xcm_procedural::XcmWeightInfoTrait,
510 xcm_procedural::Builder,
511)]
512#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
513#[codec(encode_bound())]
514#[codec(decode_bound())]
515#[scale_info(bounds(), skip_type_params(Call))]
516#[scale_info(replace_segment("staging_xcm", "xcm"))]
517#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
518pub enum Instruction<Call> {
519 #[builder(loads_holding)]
528 WithdrawAsset(MultiAssets),
529
530 #[builder(loads_holding)]
542 ReserveAssetDeposited(MultiAssets),
543
544 #[builder(loads_holding)]
556 ReceiveTeleportedAsset(MultiAssets),
557
558 QueryResponse {
576 #[codec(compact)]
577 query_id: QueryId,
578 response: Response,
579 max_weight: Weight,
580 querier: Option<MultiLocation>,
581 },
582
583 TransferAsset { assets: MultiAssets, beneficiary: MultiLocation },
595
596 TransferReserveAsset { assets: MultiAssets, dest: MultiLocation, xcm: Xcm<()> },
615
616 Transact { origin_kind: OriginKind, require_weight_at_most: Weight, call: DoubleEncoded<Call> },
632
633 HrmpNewChannelOpenRequest {
645 #[codec(compact)]
646 sender: u32,
647 #[codec(compact)]
648 max_message_size: u32,
649 #[codec(compact)]
650 max_capacity: u32,
651 },
652
653 HrmpChannelAccepted {
663 #[codec(compact)]
666 recipient: u32,
667 },
668
669 HrmpChannelClosing {
680 #[codec(compact)]
681 initiator: u32,
682 #[codec(compact)]
683 sender: u32,
684 #[codec(compact)]
685 recipient: u32,
686 },
687
688 ClearOrigin,
700
701 DescendOrigin(InteriorMultiLocation),
707
708 ReportError(QueryResponseInfo),
718
719 DepositAsset { assets: MultiAssetFilter, beneficiary: MultiLocation },
729
730 DepositReserveAsset { assets: MultiAssetFilter, dest: MultiLocation, xcm: Xcm<()> },
747
748 ExchangeAsset { give: MultiAssetFilter, want: MultiAssets, maximal: bool },
764
765 InitiateReserveWithdraw { assets: MultiAssetFilter, reserve: MultiLocation, xcm: Xcm<()> },
780
781 InitiateTeleport { assets: MultiAssetFilter, dest: MultiLocation, xcm: Xcm<()> },
796
797 ReportHolding { response_info: QueryResponseInfo, assets: MultiAssetFilter },
810
811 BuyExecution { fees: MultiAsset, weight_limit: WeightLimit },
823
824 RefundSurplus,
830
831 SetErrorHandler(Xcm<Call>),
846
847 SetAppendix(Xcm<Call>),
862
863 ClearError,
869
870 #[builder(loads_holding)]
881 ClaimAsset { assets: MultiAssets, ticket: MultiLocation },
882
883 Trap(#[codec(compact)] u64),
890
891 SubscribeVersion {
904 #[codec(compact)]
905 query_id: QueryId,
906 max_response_weight: Weight,
907 },
908
909 UnsubscribeVersion,
915
916 BurnAsset(MultiAssets),
926
927 ExpectAsset(MultiAssets),
934
935 ExpectOrigin(Option<MultiLocation>),
942
943 ExpectError(Option<(u32, Error)>),
950
951 ExpectTransactStatus(MaybeErrorCode),
960
961 QueryPallet { module_name: Vec<u8>, response_info: QueryResponseInfo },
976
977 ExpectPallet {
996 #[codec(compact)]
997 index: u32,
998 name: Vec<u8>,
999 module_name: Vec<u8>,
1000 #[codec(compact)]
1001 crate_major: u32,
1002 #[codec(compact)]
1003 min_crate_minor: u32,
1004 },
1005
1006 ReportTransactStatus(QueryResponseInfo),
1018
1019 ClearTransactStatus,
1027
1028 UniversalOrigin(Junction),
1042
1043 ExportMessage { network: NetworkId, destination: InteriorMultiLocation, xcm: Xcm<()> },
1063
1064 LockAsset { asset: MultiAsset, unlocker: MultiLocation },
1079
1080 UnlockAsset { asset: MultiAsset, target: MultiLocation },
1092
1093 NoteUnlockable { asset: MultiAsset, owner: MultiLocation },
1107
1108 RequestUnlock { asset: MultiAsset, locker: MultiLocation },
1121
1122 SetFeesMode { jit_withdraw: bool },
1131
1132 SetTopic([u8; 32]),
1144
1145 ClearTopic,
1151
1152 AliasOrigin(MultiLocation),
1158
1159 UnpaidExecution { weight_limit: WeightLimit, check_origin: Option<MultiLocation> },
1170}
1171
1172impl<Call> Xcm<Call> {
1173 pub fn into<C>(self) -> Xcm<C> {
1174 Xcm::from(self)
1175 }
1176 pub fn from<C>(xcm: Xcm<C>) -> Self {
1177 Self(xcm.0.into_iter().map(Instruction::<Call>::from).collect())
1178 }
1179}
1180
1181impl<Call> Instruction<Call> {
1182 pub fn into<C>(self) -> Instruction<C> {
1183 Instruction::from(self)
1184 }
1185 pub fn from<C>(xcm: Instruction<C>) -> Self {
1186 use Instruction::*;
1187 match xcm {
1188 WithdrawAsset(assets) => WithdrawAsset(assets),
1189 ReserveAssetDeposited(assets) => ReserveAssetDeposited(assets),
1190 ReceiveTeleportedAsset(assets) => ReceiveTeleportedAsset(assets),
1191 QueryResponse { query_id, response, max_weight, querier } =>
1192 QueryResponse { query_id, response, max_weight, querier },
1193 TransferAsset { assets, beneficiary } => TransferAsset { assets, beneficiary },
1194 TransferReserveAsset { assets, dest, xcm } =>
1195 TransferReserveAsset { assets, dest, xcm },
1196 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
1197 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
1198 HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient },
1199 HrmpChannelClosing { initiator, sender, recipient } =>
1200 HrmpChannelClosing { initiator, sender, recipient },
1201 Transact { origin_kind, require_weight_at_most, call } =>
1202 Transact { origin_kind, require_weight_at_most, call: call.into() },
1203 ReportError(response_info) => ReportError(response_info),
1204 DepositAsset { assets, beneficiary } => DepositAsset { assets, beneficiary },
1205 DepositReserveAsset { assets, dest, xcm } => DepositReserveAsset { assets, dest, xcm },
1206 ExchangeAsset { give, want, maximal } => ExchangeAsset { give, want, maximal },
1207 InitiateReserveWithdraw { assets, reserve, xcm } =>
1208 InitiateReserveWithdraw { assets, reserve, xcm },
1209 InitiateTeleport { assets, dest, xcm } => InitiateTeleport { assets, dest, xcm },
1210 ReportHolding { response_info, assets } => ReportHolding { response_info, assets },
1211 BuyExecution { fees, weight_limit } => BuyExecution { fees, weight_limit },
1212 ClearOrigin => ClearOrigin,
1213 DescendOrigin(who) => DescendOrigin(who),
1214 RefundSurplus => RefundSurplus,
1215 SetErrorHandler(xcm) => SetErrorHandler(xcm.into()),
1216 SetAppendix(xcm) => SetAppendix(xcm.into()),
1217 ClearError => ClearError,
1218 ClaimAsset { assets, ticket } => ClaimAsset { assets, ticket },
1219 Trap(code) => Trap(code),
1220 SubscribeVersion { query_id, max_response_weight } =>
1221 SubscribeVersion { query_id, max_response_weight },
1222 UnsubscribeVersion => UnsubscribeVersion,
1223 BurnAsset(assets) => BurnAsset(assets),
1224 ExpectAsset(assets) => ExpectAsset(assets),
1225 ExpectOrigin(origin) => ExpectOrigin(origin),
1226 ExpectError(error) => ExpectError(error),
1227 ExpectTransactStatus(transact_status) => ExpectTransactStatus(transact_status),
1228 QueryPallet { module_name, response_info } =>
1229 QueryPallet { module_name, response_info },
1230 ExpectPallet { index, name, module_name, crate_major, min_crate_minor } =>
1231 ExpectPallet { index, name, module_name, crate_major, min_crate_minor },
1232 ReportTransactStatus(response_info) => ReportTransactStatus(response_info),
1233 ClearTransactStatus => ClearTransactStatus,
1234 UniversalOrigin(j) => UniversalOrigin(j),
1235 ExportMessage { network, destination, xcm } =>
1236 ExportMessage { network, destination, xcm },
1237 LockAsset { asset, unlocker } => LockAsset { asset, unlocker },
1238 UnlockAsset { asset, target } => UnlockAsset { asset, target },
1239 NoteUnlockable { asset, owner } => NoteUnlockable { asset, owner },
1240 RequestUnlock { asset, locker } => RequestUnlock { asset, locker },
1241 SetFeesMode { jit_withdraw } => SetFeesMode { jit_withdraw },
1242 SetTopic(topic) => SetTopic(topic),
1243 ClearTopic => ClearTopic,
1244 AliasOrigin(location) => AliasOrigin(location),
1245 UnpaidExecution { weight_limit, check_origin } =>
1246 UnpaidExecution { weight_limit, check_origin },
1247 }
1248 }
1249}
1250
1251impl<Call, W: XcmWeightInfo<Call>> GetWeight<W> for Instruction<Call> {
1253 fn weight(&self) -> Weight {
1254 use Instruction::*;
1255 match self {
1256 WithdrawAsset(assets) => W::withdraw_asset(assets),
1257 ReserveAssetDeposited(assets) => W::reserve_asset_deposited(assets),
1258 ReceiveTeleportedAsset(assets) => W::receive_teleported_asset(assets),
1259 QueryResponse { query_id, response, max_weight, querier } =>
1260 W::query_response(query_id, response, max_weight, querier),
1261 TransferAsset { assets, beneficiary } => W::transfer_asset(assets, beneficiary),
1262 TransferReserveAsset { assets, dest, xcm } =>
1263 W::transfer_reserve_asset(&assets, dest, xcm),
1264 Transact { origin_kind, require_weight_at_most, call } =>
1265 W::transact(origin_kind, require_weight_at_most, call),
1266 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
1267 W::hrmp_new_channel_open_request(sender, max_message_size, max_capacity),
1268 HrmpChannelAccepted { recipient } => W::hrmp_channel_accepted(recipient),
1269 HrmpChannelClosing { initiator, sender, recipient } =>
1270 W::hrmp_channel_closing(initiator, sender, recipient),
1271 ClearOrigin => W::clear_origin(),
1272 DescendOrigin(who) => W::descend_origin(who),
1273 ReportError(response_info) => W::report_error(&response_info),
1274 DepositAsset { assets, beneficiary } => W::deposit_asset(assets, beneficiary),
1275 DepositReserveAsset { assets, dest, xcm } =>
1276 W::deposit_reserve_asset(assets, dest, xcm),
1277 ExchangeAsset { give, want, maximal } => W::exchange_asset(give, want, maximal),
1278 InitiateReserveWithdraw { assets, reserve, xcm } =>
1279 W::initiate_reserve_withdraw(assets, reserve, xcm),
1280 InitiateTeleport { assets, dest, xcm } => W::initiate_teleport(assets, dest, xcm),
1281 ReportHolding { response_info, assets } => W::report_holding(&response_info, &assets),
1282 BuyExecution { fees, weight_limit } => W::buy_execution(fees, weight_limit),
1283 RefundSurplus => W::refund_surplus(),
1284 SetErrorHandler(xcm) => W::set_error_handler(xcm),
1285 SetAppendix(xcm) => W::set_appendix(xcm),
1286 ClearError => W::clear_error(),
1287 ClaimAsset { assets, ticket } => W::claim_asset(assets, ticket),
1288 Trap(code) => W::trap(code),
1289 SubscribeVersion { query_id, max_response_weight } =>
1290 W::subscribe_version(query_id, max_response_weight),
1291 UnsubscribeVersion => W::unsubscribe_version(),
1292 BurnAsset(assets) => W::burn_asset(assets),
1293 ExpectAsset(assets) => W::expect_asset(assets),
1294 ExpectOrigin(origin) => W::expect_origin(origin),
1295 ExpectError(error) => W::expect_error(error),
1296 ExpectTransactStatus(transact_status) => W::expect_transact_status(transact_status),
1297 QueryPallet { module_name, response_info } =>
1298 W::query_pallet(module_name, response_info),
1299 ExpectPallet { index, name, module_name, crate_major, min_crate_minor } =>
1300 W::expect_pallet(index, name, module_name, crate_major, min_crate_minor),
1301 ReportTransactStatus(response_info) => W::report_transact_status(response_info),
1302 ClearTransactStatus => W::clear_transact_status(),
1303 UniversalOrigin(j) => W::universal_origin(j),
1304 ExportMessage { network, destination, xcm } =>
1305 W::export_message(network, destination, xcm),
1306 LockAsset { asset, unlocker } => W::lock_asset(asset, unlocker),
1307 UnlockAsset { asset, target } => W::unlock_asset(asset, target),
1308 NoteUnlockable { asset, owner } => W::note_unlockable(asset, owner),
1309 RequestUnlock { asset, locker } => W::request_unlock(asset, locker),
1310 SetFeesMode { jit_withdraw } => W::set_fees_mode(jit_withdraw),
1311 SetTopic(topic) => W::set_topic(topic),
1312 ClearTopic => W::clear_topic(),
1313 AliasOrigin(location) => W::alias_origin(location),
1314 UnpaidExecution { weight_limit, check_origin } =>
1315 W::unpaid_execution(weight_limit, check_origin),
1316 }
1317 }
1318}
1319
1320pub mod opaque {
1321 pub type Xcm = super::Xcm<()>;
1324
1325 pub type Instruction = super::Instruction<()>;
1328}
1329
1330impl TryFrom<OldResponse> for Response {
1332 type Error = ();
1333 fn try_from(old_response: OldResponse) -> result::Result<Self, ()> {
1334 match old_response {
1335 OldResponse::Assets(assets) => Ok(Self::Assets(assets.try_into()?)),
1336 OldResponse::Version(version) => Ok(Self::Version(version)),
1337 OldResponse::ExecutionResult(error) => Ok(Self::ExecutionResult(match error {
1338 Some((i, e)) => Some((i, e.try_into()?)),
1339 None => None,
1340 })),
1341 OldResponse::Null => Ok(Self::Null),
1342 }
1343 }
1344}
1345
1346#[allow(deprecated)]
1348impl<Call> TryFrom<OldXcm<Call>> for Xcm<Call> {
1349 type Error = ();
1350 fn try_from(old_xcm: OldXcm<Call>) -> result::Result<Self, ()> {
1351 Ok(Xcm(old_xcm.0.into_iter().map(TryInto::try_into).collect::<result::Result<_, _>>()?))
1352 }
1353}
1354
1355impl<Call> TryFrom<NewXcm<Call>> for Xcm<Call> {
1357 type Error = ();
1358 fn try_from(new_xcm: NewXcm<Call>) -> result::Result<Self, Self::Error> {
1359 Ok(Xcm(new_xcm.0.into_iter().map(TryInto::try_into).collect::<result::Result<_, _>>()?))
1360 }
1361}
1362
1363impl<Call> TryFrom<NewInstruction<Call>> for Instruction<Call> {
1365 type Error = ();
1366 fn try_from(new_instruction: NewInstruction<Call>) -> result::Result<Self, Self::Error> {
1367 use NewInstruction::*;
1368 Ok(match new_instruction {
1369 WithdrawAsset(assets) => Self::WithdrawAsset(assets.try_into()?),
1370 ReserveAssetDeposited(assets) => Self::ReserveAssetDeposited(assets.try_into()?),
1371 ReceiveTeleportedAsset(assets) => Self::ReceiveTeleportedAsset(assets.try_into()?),
1372 QueryResponse { query_id, response, max_weight, querier: Some(querier) } =>
1373 Self::QueryResponse {
1374 query_id,
1375 querier: querier.try_into()?,
1376 response: response.try_into()?,
1377 max_weight,
1378 },
1379 QueryResponse { query_id, response, max_weight, querier: None } =>
1380 Self::QueryResponse {
1381 query_id,
1382 querier: None,
1383 response: response.try_into()?,
1384 max_weight,
1385 },
1386 TransferAsset { assets, beneficiary } => Self::TransferAsset {
1387 assets: assets.try_into()?,
1388 beneficiary: beneficiary.try_into()?,
1389 },
1390 TransferReserveAsset { assets, dest, xcm } => Self::TransferReserveAsset {
1391 assets: assets.try_into()?,
1392 dest: dest.try_into()?,
1393 xcm: xcm.try_into()?,
1394 },
1395 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
1396 Self::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
1397 HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient },
1398 HrmpChannelClosing { initiator, sender, recipient } =>
1399 Self::HrmpChannelClosing { initiator, sender, recipient },
1400 Transact { origin_kind, require_weight_at_most, call } =>
1401 Self::Transact { origin_kind, require_weight_at_most, call: call.into() },
1402 ReportError(response_info) => Self::ReportError(QueryResponseInfo {
1403 query_id: response_info.query_id,
1404 destination: response_info.destination.try_into().map_err(|_| ())?,
1405 max_weight: response_info.max_weight,
1406 }),
1407 DepositAsset { assets, beneficiary } => {
1408 let beneficiary = beneficiary.try_into()?;
1409 let assets = assets.try_into()?;
1410 Self::DepositAsset { assets, beneficiary }
1411 },
1412 DepositReserveAsset { assets, dest, xcm } => {
1413 let dest = dest.try_into()?;
1414 let xcm = xcm.try_into()?;
1415 let assets = assets.try_into()?;
1416 Self::DepositReserveAsset { assets, dest, xcm }
1417 },
1418 ExchangeAsset { give, want, maximal } => {
1419 let give = give.try_into()?;
1420 let want = want.try_into()?;
1421 Self::ExchangeAsset { give, want, maximal }
1422 },
1423 InitiateReserveWithdraw { assets, reserve, xcm } => {
1424 let assets = assets.try_into()?;
1426 let reserve = reserve.try_into()?;
1427 let xcm = xcm.try_into()?;
1428 Self::InitiateReserveWithdraw { assets, reserve, xcm }
1429 },
1430 InitiateTeleport { assets, dest, xcm } => {
1431 let assets = assets.try_into()?;
1433 let dest = dest.try_into()?;
1434 let xcm = xcm.try_into()?;
1435 Self::InitiateTeleport { assets, dest, xcm }
1436 },
1437 ReportHolding { response_info, assets } => {
1438 let response_info = QueryResponseInfo {
1439 destination: response_info.destination.try_into().map_err(|_| ())?,
1440 query_id: response_info.query_id,
1441 max_weight: response_info.max_weight,
1442 };
1443 Self::ReportHolding { response_info, assets: assets.try_into()? }
1444 },
1445 BuyExecution { fees, weight_limit } => {
1446 let fees = fees.try_into()?;
1447 let weight_limit = weight_limit.into();
1448 Self::BuyExecution { fees, weight_limit }
1449 },
1450 ClearOrigin => Self::ClearOrigin,
1451 DescendOrigin(who) => Self::DescendOrigin(who.try_into()?),
1452 RefundSurplus => Self::RefundSurplus,
1453 SetErrorHandler(xcm) => Self::SetErrorHandler(xcm.try_into()?),
1454 SetAppendix(xcm) => Self::SetAppendix(xcm.try_into()?),
1455 ClearError => Self::ClearError,
1456 ClaimAsset { assets, ticket } => {
1457 let assets = assets.try_into()?;
1458 let ticket = ticket.try_into()?;
1459 Self::ClaimAsset { assets, ticket }
1460 },
1461 Trap(code) => Self::Trap(code),
1462 SubscribeVersion { query_id, max_response_weight } =>
1463 Self::SubscribeVersion { query_id, max_response_weight },
1464 UnsubscribeVersion => Self::UnsubscribeVersion,
1465 BurnAsset(assets) => Self::BurnAsset(assets.try_into()?),
1466 ExpectAsset(assets) => Self::ExpectAsset(assets.try_into()?),
1467 ExpectOrigin(maybe_origin) =>
1468 Self::ExpectOrigin(maybe_origin.map(|origin| origin.try_into()).transpose()?),
1469 ExpectError(maybe_error) => Self::ExpectError(maybe_error),
1470 ExpectTransactStatus(maybe_error_code) => Self::ExpectTransactStatus(maybe_error_code),
1471 QueryPallet { module_name, response_info } =>
1472 Self::QueryPallet { module_name, response_info: response_info.try_into()? },
1473 ExpectPallet { index, name, module_name, crate_major, min_crate_minor } =>
1474 Self::ExpectPallet { index, name, module_name, crate_major, min_crate_minor },
1475 ReportTransactStatus(response_info) =>
1476 Self::ReportTransactStatus(response_info.try_into()?),
1477 ClearTransactStatus => Self::ClearTransactStatus,
1478 UniversalOrigin(junction) => Self::UniversalOrigin(junction.try_into()?),
1479 ExportMessage { network, destination, xcm } => Self::ExportMessage {
1480 network: network.into(),
1481 destination: destination.try_into()?,
1482 xcm: xcm.try_into()?,
1483 },
1484 LockAsset { asset, unlocker } =>
1485 Self::LockAsset { asset: asset.try_into()?, unlocker: unlocker.try_into()? },
1486 UnlockAsset { asset, target } =>
1487 Self::UnlockAsset { asset: asset.try_into()?, target: target.try_into()? },
1488 NoteUnlockable { asset, owner } =>
1489 Self::NoteUnlockable { asset: asset.try_into()?, owner: owner.try_into()? },
1490 RequestUnlock { asset, locker } =>
1491 Self::RequestUnlock { asset: asset.try_into()?, locker: locker.try_into()? },
1492 SetFeesMode { jit_withdraw } => Self::SetFeesMode { jit_withdraw },
1493 SetTopic(topic) => Self::SetTopic(topic),
1494 ClearTopic => Self::ClearTopic,
1495 AliasOrigin(location) => Self::AliasOrigin(location.try_into()?),
1496 UnpaidExecution { weight_limit, check_origin } => Self::UnpaidExecution {
1497 weight_limit,
1498 check_origin: check_origin.map(|origin| origin.try_into()).transpose()?,
1499 },
1500 })
1501 }
1502}
1503
1504const DEFAULT_PROOF_SIZE: u64 = 64 * 1024;
1507
1508impl<Call> TryFrom<OldInstruction<Call>> for Instruction<Call> {
1510 type Error = ();
1511 fn try_from(old_instruction: OldInstruction<Call>) -> result::Result<Self, ()> {
1512 use OldInstruction::*;
1513 Ok(match old_instruction {
1514 WithdrawAsset(assets) => Self::WithdrawAsset(assets.try_into()?),
1515 ReserveAssetDeposited(assets) => Self::ReserveAssetDeposited(assets.try_into()?),
1516 ReceiveTeleportedAsset(assets) => Self::ReceiveTeleportedAsset(assets.try_into()?),
1517 QueryResponse { query_id, response, max_weight } => Self::QueryResponse {
1518 query_id,
1519 response: response.try_into()?,
1520 max_weight: Weight::from_parts(max_weight, DEFAULT_PROOF_SIZE),
1521 querier: None,
1522 },
1523 TransferAsset { assets, beneficiary } => Self::TransferAsset {
1524 assets: assets.try_into()?,
1525 beneficiary: beneficiary.try_into()?,
1526 },
1527 TransferReserveAsset { assets, dest, xcm } => Self::TransferReserveAsset {
1528 assets: assets.try_into()?,
1529 dest: dest.try_into()?,
1530 xcm: xcm.try_into()?,
1531 },
1532 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
1533 Self::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
1534 HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient },
1535 HrmpChannelClosing { initiator, sender, recipient } =>
1536 Self::HrmpChannelClosing { initiator, sender, recipient },
1537 Transact { origin_type, require_weight_at_most, call } => Self::Transact {
1538 origin_kind: origin_type.into(),
1539 require_weight_at_most: Weight::from_parts(
1540 require_weight_at_most,
1541 DEFAULT_PROOF_SIZE,
1542 ),
1543 call: call.into(),
1544 },
1545 ReportError { query_id, dest, max_response_weight } => {
1546 let response_info = QueryResponseInfo {
1547 destination: dest.try_into()?,
1548 query_id,
1549 max_weight: Weight::from_parts(max_response_weight, DEFAULT_PROOF_SIZE),
1550 };
1551 Self::ReportError(response_info)
1552 },
1553 DepositAsset { assets, max_assets, beneficiary } => Self::DepositAsset {
1554 assets: (assets, max_assets).try_into()?,
1555 beneficiary: beneficiary.try_into()?,
1556 },
1557 DepositReserveAsset { assets, max_assets, dest, xcm } => {
1558 let assets = (assets, max_assets).try_into()?;
1559 Self::DepositReserveAsset { assets, dest: dest.try_into()?, xcm: xcm.try_into()? }
1560 },
1561 ExchangeAsset { give, receive } => {
1562 let give = give.try_into()?;
1563 let want = receive.try_into()?;
1564 Self::ExchangeAsset { give, want, maximal: true }
1565 },
1566 InitiateReserveWithdraw { assets, reserve, xcm } => Self::InitiateReserveWithdraw {
1567 assets: assets.try_into()?,
1568 reserve: reserve.try_into()?,
1569 xcm: xcm.try_into()?,
1570 },
1571 InitiateTeleport { assets, dest, xcm } => Self::InitiateTeleport {
1572 assets: assets.try_into()?,
1573 dest: dest.try_into()?,
1574 xcm: xcm.try_into()?,
1575 },
1576 QueryHolding { query_id, dest, assets, max_response_weight } => {
1577 let response_info = QueryResponseInfo {
1578 destination: dest.try_into()?,
1579 query_id,
1580 max_weight: Weight::from_parts(max_response_weight, DEFAULT_PROOF_SIZE),
1581 };
1582 Self::ReportHolding { response_info, assets: assets.try_into()? }
1583 },
1584 BuyExecution { fees, weight_limit } =>
1585 Self::BuyExecution { fees: fees.try_into()?, weight_limit: weight_limit.into() },
1586 ClearOrigin => Self::ClearOrigin,
1587 DescendOrigin(who) => Self::DescendOrigin(who.try_into()?),
1588 RefundSurplus => Self::RefundSurplus,
1589 SetErrorHandler(xcm) => Self::SetErrorHandler(xcm.try_into()?),
1590 SetAppendix(xcm) => Self::SetAppendix(xcm.try_into()?),
1591 ClearError => Self::ClearError,
1592 ClaimAsset { assets, ticket } => {
1593 let assets = assets.try_into()?;
1594 let ticket = ticket.try_into()?;
1595 Self::ClaimAsset { assets, ticket }
1596 },
1597 Trap(code) => Self::Trap(code),
1598 SubscribeVersion { query_id, max_response_weight } => Self::SubscribeVersion {
1599 query_id,
1600 max_response_weight: Weight::from_parts(max_response_weight, DEFAULT_PROOF_SIZE),
1601 },
1602 UnsubscribeVersion => Self::UnsubscribeVersion,
1603 })
1604 }
1605}
1606
1607#[cfg(test)]
1608mod tests {
1609 use super::{prelude::*, *};
1610
1611 #[test]
1612 fn decoding_respects_limit() {
1613 let max_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize]);
1614 let encoded = max_xcm.encode();
1615 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_ok());
1616
1617 let big_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize + 1]);
1618 let encoded = big_xcm.encode();
1619 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1620
1621 let nested_xcm = Xcm::<()>(vec![
1622 DepositReserveAsset {
1623 assets: All.into(),
1624 dest: Here.into(),
1625 xcm: max_xcm,
1626 };
1627 (MAX_INSTRUCTIONS_TO_DECODE / 2) as usize
1628 ]);
1629 let encoded = nested_xcm.encode();
1630 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1631
1632 let even_more_nested_xcm = Xcm::<()>(vec![SetAppendix(nested_xcm); 64]);
1633 let encoded = even_more_nested_xcm.encode();
1634 assert_eq!(encoded.len(), 342530);
1635 assert_eq!(MAX_INSTRUCTIONS_TO_DECODE, 100, "precondition");
1637 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1638 }
1639}