1use super::{
56 v3::{
57 BodyId as NewBodyId, BodyPart as NewBodyPart, Instruction as NewInstruction,
58 NetworkId as NewNetworkId, OriginKind as NewOriginKind, Response as NewResponse,
59 WeightLimit as NewWeightLimit, Xcm as NewXcm,
60 },
61 DoubleEncoded,
62};
63use alloc::{vec, vec::Vec};
64use bounded_collections::{ConstU32, WeakBoundedVec};
65use codec::{
66 self, decode_vec_with_len, Compact, Decode, Encode, Error as CodecError, Input as CodecInput,
67 MaxEncodedLen,
68};
69use core::{fmt::Debug, result};
70use derivative::Derivative;
71use scale_info::TypeInfo;
72
73mod junction;
74mod multiasset;
75mod multilocation;
76mod traits;
77
78pub use junction::Junction;
79pub use multiasset::{
80 AssetId, AssetInstance, Fungibility, MultiAsset, MultiAssetFilter, MultiAssets,
81 WildFungibility, WildMultiAsset,
82};
83pub use multilocation::{
84 Ancestor, AncestorThen, InteriorMultiLocation, Junctions, MultiLocation, Parent, ParentThen,
85};
86pub use traits::{Error, ExecuteXcm, GetWeight, Outcome, Result, SendError, SendResult, SendXcm};
87
88#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
90#[scale_info(replace_segment("staging_xcm", "xcm"))]
91#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
92pub enum OriginKind {
93 Native,
98
99 SovereignAccount,
102
103 Superuser,
106
107 Xcm,
111}
112
113impl From<NewOriginKind> for OriginKind {
114 fn from(new: NewOriginKind) -> Self {
115 use NewOriginKind::*;
116 match new {
117 Native => Self::Native,
118 SovereignAccount => Self::SovereignAccount,
119 Superuser => Self::Superuser,
120 Xcm => Self::Xcm,
121 }
122 }
123}
124
125#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
127#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
128#[scale_info(replace_segment("staging_xcm", "xcm"))]
129pub enum NetworkId {
130 Any,
132 Named(WeakBoundedVec<u8, ConstU32<32>>),
134 Polkadot,
136 Kusama,
138}
139
140impl TryFrom<Option<NewNetworkId>> for NetworkId {
141 type Error = ();
142 fn try_from(new: Option<NewNetworkId>) -> result::Result<NetworkId, ()> {
143 match new {
144 None => Ok(NetworkId::Any),
145 Some(id) => Self::try_from(id),
146 }
147 }
148}
149
150impl TryFrom<NewNetworkId> for NetworkId {
151 type Error = ();
152 fn try_from(new: NewNetworkId) -> result::Result<NetworkId, ()> {
153 use NewNetworkId::*;
154 match new {
155 Polkadot => Ok(NetworkId::Polkadot),
156 Kusama => Ok(NetworkId::Kusama),
157 _ => Err(()),
158 }
159 }
160}
161
162#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
164#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
165#[scale_info(replace_segment("staging_xcm", "xcm"))]
166pub enum BodyId {
167 Unit,
169 Named(WeakBoundedVec<u8, ConstU32<32>>),
171 Index(#[codec(compact)] u32),
173 Executive,
175 Technical,
177 Legislative,
180 Judicial,
183 Defense,
186 Administration,
189 Treasury,
192}
193
194impl From<NewBodyId> for BodyId {
195 fn from(n: NewBodyId) -> Self {
196 use NewBodyId::*;
197 match n {
198 Unit => Self::Unit,
199 Moniker(n) => Self::Named(
200 n[..]
201 .to_vec()
202 .try_into()
203 .expect("array size is 4 and so will never be out of bounds; qed"),
204 ),
205 Index(n) => Self::Index(n),
206 Executive => Self::Executive,
207 Technical => Self::Technical,
208 Legislative => Self::Legislative,
209 Judicial => Self::Judicial,
210 Defense => Self::Defense,
211 Administration => Self::Administration,
212 Treasury => Self::Treasury,
213 }
214 }
215}
216
217#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
219#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
220#[scale_info(replace_segment("staging_xcm", "xcm"))]
221pub enum BodyPart {
222 Voice,
224 Members {
226 #[codec(compact)]
227 count: u32,
228 },
229 Fraction {
231 #[codec(compact)]
232 nom: u32,
233 #[codec(compact)]
234 denom: u32,
235 },
236 AtLeastProportion {
238 #[codec(compact)]
239 nom: u32,
240 #[codec(compact)]
241 denom: u32,
242 },
243 MoreThanProportion {
245 #[codec(compact)]
246 nom: u32,
247 #[codec(compact)]
248 denom: u32,
249 },
250}
251
252impl BodyPart {
253 pub fn is_majority(&self) -> bool {
255 match self {
256 BodyPart::Fraction { nom, denom } if *nom * 2 > *denom => true,
257 BodyPart::AtLeastProportion { nom, denom } if *nom * 2 > *denom => true,
258 BodyPart::MoreThanProportion { nom, denom } if *nom * 2 >= *denom => true,
259 _ => false,
260 }
261 }
262}
263
264impl From<NewBodyPart> for BodyPart {
265 fn from(n: NewBodyPart) -> Self {
266 use NewBodyPart::*;
267 match n {
268 Voice => Self::Voice,
269 Members { count } => Self::Members { count },
270 Fraction { nom, denom } => Self::Fraction { nom, denom },
271 AtLeastProportion { nom, denom } => Self::AtLeastProportion { nom, denom },
272 MoreThanProportion { nom, denom } => Self::MoreThanProportion { nom, denom },
273 }
274 }
275}
276
277pub const VERSION: super::Version = 2;
279
280pub type QueryId = u64;
282
283#[derive(Derivative, Default, Encode, TypeInfo)]
285#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
286#[codec(encode_bound())]
287#[codec(decode_bound())]
288#[scale_info(bounds(), skip_type_params(RuntimeCall))]
289#[scale_info(replace_segment("staging_xcm", "xcm"))]
290pub struct Xcm<RuntimeCall>(pub Vec<Instruction<RuntimeCall>>);
291
292environmental::environmental!(instructions_count: u8);
293
294impl<Call> Decode for Xcm<Call> {
295 fn decode<I: CodecInput>(input: &mut I) -> core::result::Result<Self, CodecError> {
296 instructions_count::using_once(&mut 0, || {
297 let number_of_instructions: u32 = <Compact<u32>>::decode(input)?.into();
298 instructions_count::with(|count| {
299 *count = count.saturating_add(number_of_instructions as u8);
300 if *count > MAX_INSTRUCTIONS_TO_DECODE {
301 return Err(CodecError::from("Max instructions exceeded"))
302 }
303 Ok(())
304 })
305 .unwrap_or(Ok(()))?;
306 let decoded_instructions = decode_vec_with_len(input, number_of_instructions as usize)?;
307 Ok(Self(decoded_instructions))
308 })
309 }
310}
311
312pub const MAX_INSTRUCTIONS_TO_DECODE: u8 = 100;
316
317impl<RuntimeCall> Xcm<RuntimeCall> {
318 pub fn new() -> Self {
320 Self(vec![])
321 }
322
323 pub fn is_empty(&self) -> bool {
325 self.0.is_empty()
326 }
327
328 pub fn len(&self) -> usize {
330 self.0.len()
331 }
332
333 pub fn or_else(self, f: impl FnOnce() -> Self) -> Self {
336 if self.0.is_empty() {
337 f()
338 } else {
339 self
340 }
341 }
342
343 pub fn first(&self) -> Option<&Instruction<RuntimeCall>> {
345 self.0.first()
346 }
347
348 pub fn last(&self) -> Option<&Instruction<RuntimeCall>> {
350 self.0.last()
351 }
352
353 pub fn only(&self) -> Option<&Instruction<RuntimeCall>> {
355 if self.0.len() == 1 {
356 self.0.first()
357 } else {
358 None
359 }
360 }
361
362 pub fn into_only(mut self) -> core::result::Result<Instruction<RuntimeCall>, Self> {
365 if self.0.len() == 1 {
366 self.0.pop().ok_or(self)
367 } else {
368 Err(self)
369 }
370 }
371}
372
373pub mod prelude {
375 mod contents {
376 pub use super::super::{
377 Ancestor, AncestorThen,
378 AssetId::{self, *},
379 AssetInstance::{self, *},
380 BodyId, BodyPart, Error as XcmError, ExecuteXcm,
381 Fungibility::{self, *},
382 Instruction::*,
383 InteriorMultiLocation,
384 Junction::{self, *},
385 Junctions::{self, *},
386 MultiAsset,
387 MultiAssetFilter::{self, *},
388 MultiAssets, MultiLocation,
389 NetworkId::{self, *},
390 OriginKind, Outcome, Parent, ParentThen, QueryId, Response, Result as XcmResult,
391 SendError, SendResult, SendXcm,
392 WeightLimit::{self, *},
393 WildFungibility::{self, Fungible as WildFungible, NonFungible as WildNonFungible},
394 WildMultiAsset::{self, *},
395 XcmWeightInfo, VERSION as XCM_VERSION,
396 };
397 }
398 pub use super::{Instruction, Xcm};
399 pub use contents::*;
400 pub mod opaque {
401 pub use super::{
402 super::opaque::{Instruction, Xcm},
403 contents::*,
404 };
405 }
406}
407
408#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
410#[scale_info(replace_segment("staging_xcm", "xcm"))]
411pub enum Response {
412 Null,
414 Assets(MultiAssets),
416 ExecutionResult(Option<(u32, Error)>),
418 Version(super::Version),
420}
421
422impl Default for Response {
423 fn default() -> Self {
424 Self::Null
425 }
426}
427
428#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
430#[scale_info(replace_segment("staging_xcm", "xcm"))]
431pub enum WeightLimit {
432 Unlimited,
434 Limited(#[codec(compact)] u64),
436}
437
438impl From<Option<u64>> for WeightLimit {
439 fn from(x: Option<u64>) -> Self {
440 match x {
441 Some(w) => WeightLimit::Limited(w),
442 None => WeightLimit::Unlimited,
443 }
444 }
445}
446
447impl From<WeightLimit> for Option<u64> {
448 fn from(x: WeightLimit) -> Self {
449 match x {
450 WeightLimit::Limited(w) => Some(w),
451 WeightLimit::Unlimited => None,
452 }
453 }
454}
455
456impl TryFrom<NewWeightLimit> for WeightLimit {
457 type Error = ();
458 fn try_from(x: NewWeightLimit) -> result::Result<Self, Self::Error> {
459 use NewWeightLimit::*;
460 match x {
461 Limited(w) => Ok(Self::Limited(w.ref_time())),
462 Unlimited => Ok(Self::Unlimited),
463 }
464 }
465}
466
467pub type Weight = u64;
469
470#[derive(Derivative, Encode, Decode, TypeInfo, xcm_procedural::XcmWeightInfoTrait)]
479#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
480#[codec(encode_bound())]
481#[codec(decode_bound())]
482#[scale_info(bounds(), skip_type_params(RuntimeCall))]
483#[scale_info(replace_segment("staging_xcm", "xcm"))]
484pub enum Instruction<RuntimeCall> {
485 WithdrawAsset(MultiAssets),
494
495 ReserveAssetDeposited(MultiAssets),
507
508 ReceiveTeleportedAsset(MultiAssets),
520
521 QueryResponse {
533 #[codec(compact)]
534 query_id: QueryId,
535 response: Response,
536 #[codec(compact)]
537 max_weight: u64,
538 },
539
540 TransferAsset { assets: MultiAssets, beneficiary: MultiLocation },
552
553 TransferReserveAsset { assets: MultiAssets, dest: MultiLocation, xcm: Xcm<()> },
572
573 Transact {
587 origin_type: OriginKind,
588 #[codec(compact)]
589 require_weight_at_most: u64,
590 call: DoubleEncoded<RuntimeCall>,
591 },
592
593 HrmpNewChannelOpenRequest {
605 #[codec(compact)]
606 sender: u32,
607 #[codec(compact)]
608 max_message_size: u32,
609 #[codec(compact)]
610 max_capacity: u32,
611 },
612
613 HrmpChannelAccepted {
623 #[codec(compact)]
626 recipient: u32,
627 },
628
629 HrmpChannelClosing {
640 #[codec(compact)]
641 initiator: u32,
642 #[codec(compact)]
643 sender: u32,
644 #[codec(compact)]
645 recipient: u32,
646 },
647
648 ClearOrigin,
660
661 DescendOrigin(InteriorMultiLocation),
667
668 ReportError {
683 #[codec(compact)]
684 query_id: QueryId,
685 dest: MultiLocation,
686 #[codec(compact)]
687 max_response_weight: u64,
688 },
689
690 DepositAsset {
703 assets: MultiAssetFilter,
704 #[codec(compact)]
705 max_assets: u32,
706 beneficiary: MultiLocation,
707 },
708
709 DepositReserveAsset {
729 assets: MultiAssetFilter,
730 #[codec(compact)]
731 max_assets: u32,
732 dest: MultiLocation,
733 xcm: Xcm<()>,
734 },
735
736 ExchangeAsset { give: MultiAssetFilter, receive: MultiAssets },
749
750 InitiateReserveWithdraw { assets: MultiAssetFilter, reserve: MultiLocation, xcm: Xcm<()> },
765
766 InitiateTeleport { assets: MultiAssetFilter, dest: MultiLocation, xcm: Xcm<()> },
781
782 QueryHolding {
799 #[codec(compact)]
800 query_id: QueryId,
801 dest: MultiLocation,
802 assets: MultiAssetFilter,
803 #[codec(compact)]
804 max_response_weight: u64,
805 },
806
807 BuyExecution { fees: MultiAsset, weight_limit: WeightLimit },
819
820 RefundSurplus,
826
827 SetErrorHandler(Xcm<RuntimeCall>),
842
843 SetAppendix(Xcm<RuntimeCall>),
858
859 ClearError,
865
866 ClaimAsset { assets: MultiAssets, ticket: MultiLocation },
877
878 Trap(#[codec(compact)] u64),
885
886 SubscribeVersion {
899 #[codec(compact)]
900 query_id: QueryId,
901 #[codec(compact)]
902 max_response_weight: u64,
903 },
904
905 UnsubscribeVersion,
911}
912
913impl<RuntimeCall> Xcm<RuntimeCall> {
914 pub fn into<C>(self) -> Xcm<C> {
915 Xcm::from(self)
916 }
917 pub fn from<C>(xcm: Xcm<C>) -> Self {
918 Self(xcm.0.into_iter().map(Instruction::<RuntimeCall>::from).collect())
919 }
920}
921
922impl<RuntimeCall> Instruction<RuntimeCall> {
923 pub fn into<C>(self) -> Instruction<C> {
924 Instruction::from(self)
925 }
926 pub fn from<C>(xcm: Instruction<C>) -> Self {
927 use Instruction::*;
928 match xcm {
929 WithdrawAsset(assets) => WithdrawAsset(assets),
930 ReserveAssetDeposited(assets) => ReserveAssetDeposited(assets),
931 ReceiveTeleportedAsset(assets) => ReceiveTeleportedAsset(assets),
932 QueryResponse { query_id, response, max_weight } =>
933 QueryResponse { query_id, response, max_weight },
934 TransferAsset { assets, beneficiary } => TransferAsset { assets, beneficiary },
935 TransferReserveAsset { assets, dest, xcm } =>
936 TransferReserveAsset { assets, dest, xcm },
937 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
938 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
939 HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient },
940 HrmpChannelClosing { initiator, sender, recipient } =>
941 HrmpChannelClosing { initiator, sender, recipient },
942 Transact { origin_type, require_weight_at_most, call } =>
943 Transact { origin_type, require_weight_at_most, call: call.into() },
944 ReportError { query_id, dest, max_response_weight } =>
945 ReportError { query_id, dest, max_response_weight },
946 DepositAsset { assets, max_assets, beneficiary } =>
947 DepositAsset { assets, max_assets, beneficiary },
948 DepositReserveAsset { assets, max_assets, dest, xcm } =>
949 DepositReserveAsset { assets, max_assets, dest, xcm },
950 ExchangeAsset { give, receive } => ExchangeAsset { give, receive },
951 InitiateReserveWithdraw { assets, reserve, xcm } =>
952 InitiateReserveWithdraw { assets, reserve, xcm },
953 InitiateTeleport { assets, dest, xcm } => InitiateTeleport { assets, dest, xcm },
954 QueryHolding { query_id, dest, assets, max_response_weight } =>
955 QueryHolding { query_id, dest, assets, max_response_weight },
956 BuyExecution { fees, weight_limit } => BuyExecution { fees, weight_limit },
957 ClearOrigin => ClearOrigin,
958 DescendOrigin(who) => DescendOrigin(who),
959 RefundSurplus => RefundSurplus,
960 SetErrorHandler(xcm) => SetErrorHandler(xcm.into()),
961 SetAppendix(xcm) => SetAppendix(xcm.into()),
962 ClearError => ClearError,
963 ClaimAsset { assets, ticket } => ClaimAsset { assets, ticket },
964 Trap(code) => Trap(code),
965 SubscribeVersion { query_id, max_response_weight } =>
966 SubscribeVersion { query_id, max_response_weight },
967 UnsubscribeVersion => UnsubscribeVersion,
968 }
969 }
970}
971
972impl<RuntimeCall, W: XcmWeightInfo<RuntimeCall>> GetWeight<W> for Instruction<RuntimeCall> {
974 fn weight(&self) -> sp_weights::Weight {
975 use Instruction::*;
976 match self {
977 WithdrawAsset(assets) => sp_weights::Weight::from_parts(W::withdraw_asset(assets), 0),
978 ReserveAssetDeposited(assets) =>
979 sp_weights::Weight::from_parts(W::reserve_asset_deposited(assets), 0),
980 ReceiveTeleportedAsset(assets) =>
981 sp_weights::Weight::from_parts(W::receive_teleported_asset(assets), 0),
982 QueryResponse { query_id, response, max_weight } =>
983 sp_weights::Weight::from_parts(W::query_response(query_id, response, max_weight), 0),
984 TransferAsset { assets, beneficiary } =>
985 sp_weights::Weight::from_parts(W::transfer_asset(assets, beneficiary), 0),
986 TransferReserveAsset { assets, dest, xcm } =>
987 sp_weights::Weight::from_parts(W::transfer_reserve_asset(&assets, dest, xcm), 0),
988 Transact { origin_type, require_weight_at_most, call } =>
989 sp_weights::Weight::from_parts(
990 W::transact(origin_type, require_weight_at_most, call),
991 0,
992 ),
993 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
994 sp_weights::Weight::from_parts(
995 W::hrmp_new_channel_open_request(sender, max_message_size, max_capacity),
996 0,
997 ),
998 HrmpChannelAccepted { recipient } =>
999 sp_weights::Weight::from_parts(W::hrmp_channel_accepted(recipient), 0),
1000 HrmpChannelClosing { initiator, sender, recipient } => sp_weights::Weight::from_parts(
1001 W::hrmp_channel_closing(initiator, sender, recipient),
1002 0,
1003 ),
1004 ClearOrigin => sp_weights::Weight::from_parts(W::clear_origin(), 0),
1005 DescendOrigin(who) => sp_weights::Weight::from_parts(W::descend_origin(who), 0),
1006 ReportError { query_id, dest, max_response_weight } => sp_weights::Weight::from_parts(
1007 W::report_error(query_id, dest, max_response_weight),
1008 0,
1009 ),
1010 DepositAsset { assets, max_assets, beneficiary } =>
1011 sp_weights::Weight::from_parts(W::deposit_asset(assets, max_assets, beneficiary), 0),
1012 DepositReserveAsset { assets, max_assets, dest, xcm } =>
1013 sp_weights::Weight::from_parts(
1014 W::deposit_reserve_asset(assets, max_assets, dest, xcm),
1015 0,
1016 ),
1017 ExchangeAsset { give, receive } =>
1018 sp_weights::Weight::from_parts(W::exchange_asset(give, receive), 0),
1019 InitiateReserveWithdraw { assets, reserve, xcm } => sp_weights::Weight::from_parts(
1020 W::initiate_reserve_withdraw(assets, reserve, xcm),
1021 0,
1022 ),
1023 InitiateTeleport { assets, dest, xcm } =>
1024 sp_weights::Weight::from_parts(W::initiate_teleport(assets, dest, xcm), 0),
1025 QueryHolding { query_id, dest, assets, max_response_weight } =>
1026 sp_weights::Weight::from_parts(
1027 W::query_holding(query_id, dest, assets, max_response_weight),
1028 0,
1029 ),
1030 BuyExecution { fees, weight_limit } =>
1031 sp_weights::Weight::from_parts(W::buy_execution(fees, weight_limit), 0),
1032 RefundSurplus => sp_weights::Weight::from_parts(W::refund_surplus(), 0),
1033 SetErrorHandler(xcm) => sp_weights::Weight::from_parts(W::set_error_handler(xcm), 0),
1034 SetAppendix(xcm) => sp_weights::Weight::from_parts(W::set_appendix(xcm), 0),
1035 ClearError => sp_weights::Weight::from_parts(W::clear_error(), 0),
1036 ClaimAsset { assets, ticket } =>
1037 sp_weights::Weight::from_parts(W::claim_asset(assets, ticket), 0),
1038 Trap(code) => sp_weights::Weight::from_parts(W::trap(code), 0),
1039 SubscribeVersion { query_id, max_response_weight } => sp_weights::Weight::from_parts(
1040 W::subscribe_version(query_id, max_response_weight),
1041 0,
1042 ),
1043 UnsubscribeVersion => sp_weights::Weight::from_parts(W::unsubscribe_version(), 0),
1044 }
1045 }
1046}
1047
1048pub mod opaque {
1049 pub type Xcm = super::Xcm<()>;
1052
1053 pub type Instruction = super::Instruction<()>;
1056}
1057
1058impl TryFrom<NewResponse> for Response {
1060 type Error = ();
1061 fn try_from(response: NewResponse) -> result::Result<Self, ()> {
1062 Ok(match response {
1063 NewResponse::Assets(assets) => Self::Assets(assets.try_into()?),
1064 NewResponse::Version(version) => Self::Version(version),
1065 NewResponse::ExecutionResult(error) => Self::ExecutionResult(match error {
1066 Some((i, e)) => Some((i, e.try_into()?)),
1067 None => None,
1068 }),
1069 NewResponse::Null => Self::Null,
1070 _ => return Err(()),
1071 })
1072 }
1073}
1074
1075impl<RuntimeCall> TryFrom<NewXcm<RuntimeCall>> for Xcm<RuntimeCall> {
1077 type Error = ();
1078 fn try_from(new_xcm: NewXcm<RuntimeCall>) -> result::Result<Self, ()> {
1079 Ok(Xcm(new_xcm.0.into_iter().map(TryInto::try_into).collect::<result::Result<_, _>>()?))
1080 }
1081}
1082
1083impl<RuntimeCall> TryFrom<NewInstruction<RuntimeCall>> for Instruction<RuntimeCall> {
1085 type Error = ();
1086 fn try_from(instruction: NewInstruction<RuntimeCall>) -> result::Result<Self, ()> {
1087 use NewInstruction::*;
1088 Ok(match instruction {
1089 WithdrawAsset(assets) => Self::WithdrawAsset(assets.try_into()?),
1090 ReserveAssetDeposited(assets) => Self::ReserveAssetDeposited(assets.try_into()?),
1091 ReceiveTeleportedAsset(assets) => Self::ReceiveTeleportedAsset(assets.try_into()?),
1092 QueryResponse { query_id, response, max_weight, .. } => Self::QueryResponse {
1093 query_id,
1094 response: response.try_into()?,
1095 max_weight: max_weight.ref_time(),
1096 },
1097 TransferAsset { assets, beneficiary } => Self::TransferAsset {
1098 assets: assets.try_into()?,
1099 beneficiary: beneficiary.try_into()?,
1100 },
1101 TransferReserveAsset { assets, dest, xcm } => Self::TransferReserveAsset {
1102 assets: assets.try_into()?,
1103 dest: dest.try_into()?,
1104 xcm: xcm.try_into()?,
1105 },
1106 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
1107 Self::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
1108 HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient },
1109 HrmpChannelClosing { initiator, sender, recipient } =>
1110 Self::HrmpChannelClosing { initiator, sender, recipient },
1111 Transact { origin_kind, require_weight_at_most, call } => Self::Transact {
1112 origin_type: origin_kind.into(),
1113 require_weight_at_most: require_weight_at_most.ref_time(),
1114 call: call.into(),
1115 },
1116 ReportError(response_info) => Self::ReportError {
1117 query_id: response_info.query_id,
1118 dest: response_info.destination.try_into()?,
1119 max_response_weight: response_info.max_weight.ref_time(),
1120 },
1121 DepositAsset { assets, beneficiary } => {
1122 let max_assets = assets.count().ok_or(())?;
1123 let beneficiary = beneficiary.try_into()?;
1124 let assets = assets.try_into()?;
1125 Self::DepositAsset { assets, max_assets, beneficiary }
1126 },
1127 DepositReserveAsset { assets, dest, xcm } => {
1128 let max_assets = assets.count().ok_or(())?;
1129 let dest = dest.try_into()?;
1130 let xcm = xcm.try_into()?;
1131 let assets = assets.try_into()?;
1132 Self::DepositReserveAsset { assets, max_assets, dest, xcm }
1133 },
1134 ExchangeAsset { give, want, .. } => {
1135 let give = give.try_into()?;
1136 let receive = want.try_into()?;
1137 Self::ExchangeAsset { give, receive }
1138 },
1139 InitiateReserveWithdraw { assets, reserve, xcm } => {
1140 let assets = assets.try_into()?;
1142 let reserve = reserve.try_into()?;
1143 let xcm = xcm.try_into()?;
1144 Self::InitiateReserveWithdraw { assets, reserve, xcm }
1145 },
1146 InitiateTeleport { assets, dest, xcm } => {
1147 let assets = assets.try_into()?;
1149 let dest = dest.try_into()?;
1150 let xcm = xcm.try_into()?;
1151 Self::InitiateTeleport { assets, dest, xcm }
1152 },
1153 ReportHolding { response_info, assets } => Self::QueryHolding {
1154 query_id: response_info.query_id,
1155 dest: response_info.destination.try_into()?,
1156 assets: assets.try_into()?,
1157 max_response_weight: response_info.max_weight.ref_time(),
1158 },
1159 BuyExecution { fees, weight_limit } => {
1160 let fees = fees.try_into()?;
1161 let weight_limit = weight_limit.try_into()?;
1162 Self::BuyExecution { fees, weight_limit }
1163 },
1164 ClearOrigin => Self::ClearOrigin,
1165 DescendOrigin(who) => Self::DescendOrigin(who.try_into()?),
1166 RefundSurplus => Self::RefundSurplus,
1167 SetErrorHandler(xcm) => Self::SetErrorHandler(xcm.try_into()?),
1168 SetAppendix(xcm) => Self::SetAppendix(xcm.try_into()?),
1169 ClearError => Self::ClearError,
1170 ClaimAsset { assets, ticket } => {
1171 let assets = assets.try_into()?;
1172 let ticket = ticket.try_into()?;
1173 Self::ClaimAsset { assets, ticket }
1174 },
1175 Trap(code) => Self::Trap(code),
1176 SubscribeVersion { query_id, max_response_weight } => Self::SubscribeVersion {
1177 query_id,
1178 max_response_weight: max_response_weight.ref_time(),
1179 },
1180 UnsubscribeVersion => Self::UnsubscribeVersion,
1181 i => {
1182 log::debug!(target: "xcm::v3tov2", "`{i:?}` not supported by v2");
1183 return Err(());
1184 },
1185 })
1186 }
1187}
1188
1189#[cfg(test)]
1190mod tests {
1191 use super::{prelude::*, *};
1192
1193 #[test]
1194 fn decoding_respects_limit() {
1195 let max_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize]);
1196 let encoded = max_xcm.encode();
1197 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_ok());
1198
1199 let big_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize + 1]);
1200 let encoded = big_xcm.encode();
1201 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1202
1203 let nested_xcm = Xcm::<()>(vec![
1204 DepositReserveAsset {
1205 assets: All.into(),
1206 dest: Here.into(),
1207 xcm: max_xcm,
1208 max_assets: 1,
1209 };
1210 (MAX_INSTRUCTIONS_TO_DECODE / 2) as usize
1211 ]);
1212 let encoded = nested_xcm.encode();
1213 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1214
1215 let even_more_nested_xcm = Xcm::<()>(vec![SetAppendix(nested_xcm); 64]);
1216 let encoded = even_more_nested_xcm.encode();
1217 assert_eq!(encoded.len(), 345730);
1218 assert_eq!(MAX_INSTRUCTIONS_TO_DECODE, 100, "precondition");
1220 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1221 }
1222}