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#[codec(decode_with_mem_tracking_bound(Call: Decode))]
64#[scale_info(bounds(), skip_type_params(Call))]
65#[scale_info(replace_segment("staging_xcm", "xcm"))]
66#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
67pub struct Xcm<Call>(pub Vec<Instruction<Call>>);
68
69impl<Call> Decode for Xcm<Call>
70where
71 Call: Decode,
72{
73 fn decode<I: CodecInput>(input: &mut I) -> core::result::Result<Self, CodecError> {
74 Ok(Xcm(decode_xcm_instructions(input)?))
75 }
76}
77
78impl<Call> Xcm<Call> {
79 pub fn new() -> Self {
81 Self(vec![])
82 }
83
84 pub fn is_empty(&self) -> bool {
86 self.0.is_empty()
87 }
88
89 pub fn len(&self) -> usize {
91 self.0.len()
92 }
93
94 pub fn inner(&self) -> &[Instruction<Call>] {
96 &self.0
97 }
98
99 pub fn inner_mut(&mut self) -> &mut Vec<Instruction<Call>> {
101 &mut self.0
102 }
103
104 pub fn into_inner(self) -> Vec<Instruction<Call>> {
106 self.0
107 }
108
109 pub fn iter(&self) -> impl Iterator<Item = &Instruction<Call>> {
111 self.0.iter()
112 }
113
114 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Instruction<Call>> {
116 self.0.iter_mut()
117 }
118
119 pub fn into_iter(self) -> impl Iterator<Item = Instruction<Call>> {
121 self.0.into_iter()
122 }
123
124 pub fn or_else(self, f: impl FnOnce() -> Self) -> Self {
127 if self.0.is_empty() {
128 f()
129 } else {
130 self
131 }
132 }
133
134 pub fn first(&self) -> Option<&Instruction<Call>> {
136 self.0.first()
137 }
138
139 pub fn last(&self) -> Option<&Instruction<Call>> {
141 self.0.last()
142 }
143
144 pub fn only(&self) -> Option<&Instruction<Call>> {
146 if self.0.len() == 1 {
147 self.0.first()
148 } else {
149 None
150 }
151 }
152
153 pub fn into_only(mut self) -> core::result::Result<Instruction<Call>, Self> {
156 if self.0.len() == 1 {
157 self.0.pop().ok_or(self)
158 } else {
159 Err(self)
160 }
161 }
162}
163
164impl<Call> From<Vec<Instruction<Call>>> for Xcm<Call> {
165 fn from(c: Vec<Instruction<Call>>) -> Self {
166 Self(c)
167 }
168}
169
170impl<Call> From<Xcm<Call>> for Vec<Instruction<Call>> {
171 fn from(c: Xcm<Call>) -> Self {
172 c.0
173 }
174}
175
176pub mod prelude {
178 mod contents {
179 pub use super::super::{
180 send_xcm, validate_send, Ancestor, AncestorThen,
181 AssetId::{self, *},
182 AssetInstance::{self, *},
183 BodyId, BodyPart, Error as XcmError, ExecuteXcm,
184 Fungibility::{self, *},
185 GetWeight,
186 Instruction::*,
187 InteriorMultiLocation,
188 Junction::{self, *},
189 Junctions::{self, *},
190 Location, MaybeErrorCode, MultiAsset,
191 MultiAssetFilter::{self, *},
192 MultiAssets, MultiLocation,
193 NetworkId::{self, *},
194 OriginKind, Outcome, PalletInfo, Parent, ParentThen, PreparedMessage, QueryId,
195 QueryResponseInfo, Response, Result as XcmResult, SendError, SendResult, SendXcm,
196 Weight,
197 WeightLimit::{self, *},
198 WildFungibility::{self, Fungible as WildFungible, NonFungible as WildNonFungible},
199 WildMultiAsset::{self, *},
200 XcmContext, XcmHash, XcmWeightInfo, VERSION as XCM_VERSION,
201 };
202 }
203 pub use super::{Instruction, Xcm};
204 pub use contents::*;
205 pub mod opaque {
206 pub use super::{
207 super::opaque::{Instruction, Xcm},
208 contents::*,
209 };
210 }
211}
212
213parameter_types! {
214 #[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
215 pub MaxPalletNameLen: u32 = 48;
216 #[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
219 pub MaxDispatchErrorLen: u32 = 128;
220 #[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
221 pub MaxPalletsInfo: u32 = 64;
222}
223
224#[derive(
225 Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo, MaxEncodedLen,
226)]
227#[scale_info(replace_segment("staging_xcm", "xcm"))]
228#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
229pub struct PalletInfo {
230 #[codec(compact)]
231 pub index: u32,
232 pub name: BoundedVec<u8, MaxPalletNameLen>,
233 pub module_name: BoundedVec<u8, MaxPalletNameLen>,
234 #[codec(compact)]
235 pub major: u32,
236 #[codec(compact)]
237 pub minor: u32,
238 #[codec(compact)]
239 pub patch: u32,
240}
241
242impl PalletInfo {
243 pub fn new(
244 index: u32,
245 name: Vec<u8>,
246 module_name: Vec<u8>,
247 major: u32,
248 minor: u32,
249 patch: u32,
250 ) -> result::Result<Self, Error> {
251 let name = BoundedVec::try_from(name).map_err(|_| Error::Overflow)?;
252 let module_name = BoundedVec::try_from(module_name).map_err(|_| Error::Overflow)?;
253
254 Ok(Self { index, name, module_name, major, minor, patch })
255 }
256}
257
258impl TryInto<NewPalletInfo> for PalletInfo {
259 type Error = ();
260
261 fn try_into(self) -> result::Result<NewPalletInfo, Self::Error> {
262 NewPalletInfo::new(
263 self.index,
264 self.name.into_inner(),
265 self.module_name.into_inner(),
266 self.major,
267 self.minor,
268 self.patch,
269 )
270 .map_err(|_| ())
271 }
272}
273
274#[derive(
275 Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo, MaxEncodedLen,
276)]
277#[scale_info(replace_segment("staging_xcm", "xcm"))]
278#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
279pub enum MaybeErrorCode {
280 Success,
281 Error(BoundedVec<u8, MaxDispatchErrorLen>),
282 TruncatedError(BoundedVec<u8, MaxDispatchErrorLen>),
283}
284
285impl From<Vec<u8>> for MaybeErrorCode {
286 fn from(v: Vec<u8>) -> Self {
287 match BoundedVec::try_from(v) {
288 Ok(error) => MaybeErrorCode::Error(error),
289 Err(error) => MaybeErrorCode::TruncatedError(BoundedVec::truncate_from(error)),
290 }
291 }
292}
293
294impl Default for MaybeErrorCode {
295 fn default() -> MaybeErrorCode {
296 MaybeErrorCode::Success
297 }
298}
299
300#[derive(
302 Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo, MaxEncodedLen,
303)]
304#[scale_info(replace_segment("staging_xcm", "xcm"))]
305#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
306pub enum Response {
307 Null,
309 Assets(MultiAssets),
311 ExecutionResult(Option<(u32, Error)>),
313 Version(super::Version),
315 PalletsInfo(BoundedVec<PalletInfo, MaxPalletsInfo>),
317 DispatchResult(MaybeErrorCode),
319}
320
321impl Default for Response {
322 fn default() -> Self {
323 Self::Null
324 }
325}
326
327impl TryFrom<NewResponse> for Response {
328 type Error = ();
329
330 fn try_from(new: NewResponse) -> result::Result<Self, Self::Error> {
331 use NewResponse::*;
332 Ok(match new {
333 Null => Self::Null,
334 Assets(assets) => Self::Assets(assets.try_into()?),
335 ExecutionResult(result) => {
336 Self::ExecutionResult(result.map(|(num, old_error)| (num, old_error.into())))
337 },
338 Version(version) => Self::Version(version),
339 PalletsInfo(pallet_info) => {
340 let inner = pallet_info
341 .into_iter()
342 .map(TryInto::try_into)
343 .collect::<result::Result<Vec<_>, _>>()?;
344 Self::PalletsInfo(
345 BoundedVec::<PalletInfo, MaxPalletsInfo>::try_from(inner).map_err(|_| ())?,
346 )
347 },
348 DispatchResult(maybe_error) => {
349 Self::DispatchResult(maybe_error.try_into().map_err(|_| ())?)
350 },
351 })
352 }
353}
354
355#[derive(Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo)]
357#[scale_info(replace_segment("staging_xcm", "xcm"))]
358#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
359pub struct QueryResponseInfo {
360 pub destination: MultiLocation,
362 #[codec(compact)]
364 pub query_id: QueryId,
365 pub max_weight: Weight,
367}
368
369impl TryFrom<NewQueryResponseInfo> for QueryResponseInfo {
370 type Error = ();
371
372 fn try_from(new: NewQueryResponseInfo) -> result::Result<Self, Self::Error> {
373 Ok(Self {
374 destination: new.destination.try_into()?,
375 query_id: new.query_id,
376 max_weight: new.max_weight,
377 })
378 }
379}
380
381#[derive(Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo)]
383#[scale_info(replace_segment("staging_xcm", "xcm"))]
384#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
385pub enum WeightLimit {
386 Unlimited,
388 Limited(Weight),
390}
391
392impl From<Option<Weight>> for WeightLimit {
393 fn from(x: Option<Weight>) -> Self {
394 match x {
395 Some(w) => WeightLimit::Limited(w),
396 None => WeightLimit::Unlimited,
397 }
398 }
399}
400
401impl From<WeightLimit> for Option<Weight> {
402 fn from(x: WeightLimit) -> Self {
403 match x {
404 WeightLimit::Limited(w) => Some(w),
405 WeightLimit::Unlimited => None,
406 }
407 }
408}
409
410#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo)]
412#[scale_info(replace_segment("staging_xcm", "xcm"))]
413#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
414pub enum OriginKind {
415 Native,
420
421 SovereignAccount,
424
425 Superuser,
428
429 Xcm,
433}
434
435#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)]
437pub struct XcmContext {
438 pub origin: Option<MultiLocation>,
440 pub message_id: XcmHash,
443 pub topic: Option<[u8; 32]>,
445}
446
447impl XcmContext {
448 #[deprecated = "Use `with_message_id` instead."]
451 pub fn with_message_hash(message_id: XcmHash) -> XcmContext {
452 XcmContext { origin: None, message_id, topic: None }
453 }
454
455 pub fn with_message_id(message_id: XcmHash) -> XcmContext {
458 XcmContext { origin: None, message_id, topic: None }
459 }
460}
461
462#[derive(
471 Encode,
472 Decode,
473 DecodeWithMemTracking,
474 TypeInfo,
475 xcm_procedural::XcmWeightInfoTrait,
476 xcm_procedural::Builder,
477)]
478#[derive_where(Clone, Eq, PartialEq, Debug)]
479#[codec(encode_bound())]
480#[codec(decode_bound(Call: Decode))]
481#[codec(decode_with_mem_tracking_bound(Call: Decode))]
482#[scale_info(bounds(), skip_type_params(Call))]
483#[scale_info(replace_segment("staging_xcm", "xcm"))]
484#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
485pub enum Instruction<Call> {
486 #[builder(loads_holding)]
495 WithdrawAsset(MultiAssets),
496
497 #[builder(loads_holding)]
509 ReserveAssetDeposited(MultiAssets),
510
511 #[builder(loads_holding)]
523 ReceiveTeleportedAsset(MultiAssets),
524
525 QueryResponse {
543 #[codec(compact)]
544 query_id: QueryId,
545 response: Response,
546 max_weight: Weight,
547 querier: Option<MultiLocation>,
548 },
549
550 TransferAsset { assets: MultiAssets, beneficiary: MultiLocation },
562
563 TransferReserveAsset { assets: MultiAssets, dest: MultiLocation, xcm: Xcm<()> },
582
583 Transact { origin_kind: OriginKind, require_weight_at_most: Weight, call: DoubleEncoded<Call> },
599
600 HrmpNewChannelOpenRequest {
612 #[codec(compact)]
613 sender: u32,
614 #[codec(compact)]
615 max_message_size: u32,
616 #[codec(compact)]
617 max_capacity: u32,
618 },
619
620 HrmpChannelAccepted {
630 #[codec(compact)]
633 recipient: u32,
634 },
635
636 HrmpChannelClosing {
647 #[codec(compact)]
648 initiator: u32,
649 #[codec(compact)]
650 sender: u32,
651 #[codec(compact)]
652 recipient: u32,
653 },
654
655 ClearOrigin,
667
668 DescendOrigin(InteriorMultiLocation),
674
675 ReportError(QueryResponseInfo),
685
686 DepositAsset { assets: MultiAssetFilter, beneficiary: MultiLocation },
696
697 DepositReserveAsset { assets: MultiAssetFilter, dest: MultiLocation, xcm: Xcm<()> },
714
715 ExchangeAsset { give: MultiAssetFilter, want: MultiAssets, maximal: bool },
731
732 InitiateReserveWithdraw { assets: MultiAssetFilter, reserve: MultiLocation, xcm: Xcm<()> },
747
748 InitiateTeleport { assets: MultiAssetFilter, dest: MultiLocation, xcm: Xcm<()> },
763
764 ReportHolding { response_info: QueryResponseInfo, assets: MultiAssetFilter },
777
778 #[builder(pays_fees)]
790 BuyExecution { fees: MultiAsset, weight_limit: WeightLimit },
791
792 RefundSurplus,
798
799 SetErrorHandler(Xcm<Call>),
814
815 SetAppendix(Xcm<Call>),
830
831 ClearError,
837
838 #[builder(loads_holding)]
849 ClaimAsset { assets: MultiAssets, ticket: MultiLocation },
850
851 Trap(#[codec(compact)] u64),
858
859 SubscribeVersion {
872 #[codec(compact)]
873 query_id: QueryId,
874 max_response_weight: Weight,
875 },
876
877 UnsubscribeVersion,
883
884 BurnAsset(MultiAssets),
894
895 ExpectAsset(MultiAssets),
902
903 ExpectOrigin(Option<MultiLocation>),
910
911 ExpectError(Option<(u32, Error)>),
918
919 ExpectTransactStatus(MaybeErrorCode),
928
929 QueryPallet { module_name: Vec<u8>, response_info: QueryResponseInfo },
944
945 ExpectPallet {
964 #[codec(compact)]
965 index: u32,
966 name: Vec<u8>,
967 module_name: Vec<u8>,
968 #[codec(compact)]
969 crate_major: u32,
970 #[codec(compact)]
971 min_crate_minor: u32,
972 },
973
974 ReportTransactStatus(QueryResponseInfo),
986
987 ClearTransactStatus,
995
996 UniversalOrigin(Junction),
1010
1011 ExportMessage { network: NetworkId, destination: InteriorMultiLocation, xcm: Xcm<()> },
1031
1032 LockAsset { asset: MultiAsset, unlocker: MultiLocation },
1047
1048 UnlockAsset { asset: MultiAsset, target: MultiLocation },
1060
1061 NoteUnlockable { asset: MultiAsset, owner: MultiLocation },
1075
1076 RequestUnlock { asset: MultiAsset, locker: MultiLocation },
1089
1090 SetFeesMode { jit_withdraw: bool },
1099
1100 SetTopic([u8; 32]),
1112
1113 ClearTopic,
1119
1120 AliasOrigin(MultiLocation),
1126
1127 UnpaidExecution { weight_limit: WeightLimit, check_origin: Option<MultiLocation> },
1138}
1139
1140impl<Call> Xcm<Call> {
1141 pub fn into<C>(self) -> Xcm<C> {
1142 Xcm::from(self)
1143 }
1144 pub fn from<C>(xcm: Xcm<C>) -> Self {
1145 Self(xcm.0.into_iter().map(Instruction::<Call>::from).collect())
1146 }
1147}
1148
1149impl<Call> Instruction<Call> {
1150 pub fn into<C>(self) -> Instruction<C> {
1151 Instruction::from(self)
1152 }
1153 pub fn from<C>(xcm: Instruction<C>) -> Self {
1154 use Instruction::*;
1155 match xcm {
1156 WithdrawAsset(assets) => WithdrawAsset(assets),
1157 ReserveAssetDeposited(assets) => ReserveAssetDeposited(assets),
1158 ReceiveTeleportedAsset(assets) => ReceiveTeleportedAsset(assets),
1159 QueryResponse { query_id, response, max_weight, querier } => {
1160 QueryResponse { query_id, response, max_weight, querier }
1161 },
1162 TransferAsset { assets, beneficiary } => TransferAsset { assets, beneficiary },
1163 TransferReserveAsset { assets, dest, xcm } => {
1164 TransferReserveAsset { assets, dest, xcm }
1165 },
1166 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => {
1167 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity }
1168 },
1169 HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient },
1170 HrmpChannelClosing { initiator, sender, recipient } => {
1171 HrmpChannelClosing { initiator, sender, recipient }
1172 },
1173 Transact { origin_kind, require_weight_at_most, call } => {
1174 Transact { origin_kind, require_weight_at_most, call: call.transmute_encoded() }
1175 },
1176 ReportError(response_info) => ReportError(response_info),
1177 DepositAsset { assets, beneficiary } => DepositAsset { assets, beneficiary },
1178 DepositReserveAsset { assets, dest, xcm } => DepositReserveAsset { assets, dest, xcm },
1179 ExchangeAsset { give, want, maximal } => ExchangeAsset { give, want, maximal },
1180 InitiateReserveWithdraw { assets, reserve, xcm } => {
1181 InitiateReserveWithdraw { assets, reserve, xcm }
1182 },
1183 InitiateTeleport { assets, dest, xcm } => InitiateTeleport { assets, dest, xcm },
1184 ReportHolding { response_info, assets } => ReportHolding { response_info, assets },
1185 BuyExecution { fees, weight_limit } => BuyExecution { fees, weight_limit },
1186 ClearOrigin => ClearOrigin,
1187 DescendOrigin(who) => DescendOrigin(who),
1188 RefundSurplus => RefundSurplus,
1189 SetErrorHandler(xcm) => SetErrorHandler(xcm.into()),
1190 SetAppendix(xcm) => SetAppendix(xcm.into()),
1191 ClearError => ClearError,
1192 ClaimAsset { assets, ticket } => ClaimAsset { assets, ticket },
1193 Trap(code) => Trap(code),
1194 SubscribeVersion { query_id, max_response_weight } => {
1195 SubscribeVersion { query_id, max_response_weight }
1196 },
1197 UnsubscribeVersion => UnsubscribeVersion,
1198 BurnAsset(assets) => BurnAsset(assets),
1199 ExpectAsset(assets) => ExpectAsset(assets),
1200 ExpectOrigin(origin) => ExpectOrigin(origin),
1201 ExpectError(error) => ExpectError(error),
1202 ExpectTransactStatus(transact_status) => ExpectTransactStatus(transact_status),
1203 QueryPallet { module_name, response_info } => {
1204 QueryPallet { module_name, response_info }
1205 },
1206 ExpectPallet { index, name, module_name, crate_major, min_crate_minor } => {
1207 ExpectPallet { index, name, module_name, crate_major, min_crate_minor }
1208 },
1209 ReportTransactStatus(response_info) => ReportTransactStatus(response_info),
1210 ClearTransactStatus => ClearTransactStatus,
1211 UniversalOrigin(j) => UniversalOrigin(j),
1212 ExportMessage { network, destination, xcm } => {
1213 ExportMessage { network, destination, xcm }
1214 },
1215 LockAsset { asset, unlocker } => LockAsset { asset, unlocker },
1216 UnlockAsset { asset, target } => UnlockAsset { asset, target },
1217 NoteUnlockable { asset, owner } => NoteUnlockable { asset, owner },
1218 RequestUnlock { asset, locker } => RequestUnlock { asset, locker },
1219 SetFeesMode { jit_withdraw } => SetFeesMode { jit_withdraw },
1220 SetTopic(topic) => SetTopic(topic),
1221 ClearTopic => ClearTopic,
1222 AliasOrigin(location) => AliasOrigin(location),
1223 UnpaidExecution { weight_limit, check_origin } => {
1224 UnpaidExecution { weight_limit, check_origin }
1225 },
1226 }
1227 }
1228}
1229
1230impl<Call, W: XcmWeightInfo<Call>> GetWeight<W> for Instruction<Call> {
1232 fn weight(&self) -> Weight {
1233 use Instruction::*;
1234 match self {
1235 WithdrawAsset(assets) => W::withdraw_asset(assets),
1236 ReserveAssetDeposited(assets) => W::reserve_asset_deposited(assets),
1237 ReceiveTeleportedAsset(assets) => W::receive_teleported_asset(assets),
1238 QueryResponse { query_id, response, max_weight, querier } => {
1239 W::query_response(query_id, response, max_weight, querier)
1240 },
1241 TransferAsset { assets, beneficiary } => W::transfer_asset(assets, beneficiary),
1242 TransferReserveAsset { assets, dest, xcm } => {
1243 W::transfer_reserve_asset(&assets, dest, xcm)
1244 },
1245 Transact { origin_kind, require_weight_at_most, call } => {
1246 W::transact(origin_kind, require_weight_at_most, call)
1247 },
1248 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => {
1249 W::hrmp_new_channel_open_request(sender, max_message_size, max_capacity)
1250 },
1251 HrmpChannelAccepted { recipient } => W::hrmp_channel_accepted(recipient),
1252 HrmpChannelClosing { initiator, sender, recipient } => {
1253 W::hrmp_channel_closing(initiator, sender, recipient)
1254 },
1255 ClearOrigin => W::clear_origin(),
1256 DescendOrigin(who) => W::descend_origin(who),
1257 ReportError(response_info) => W::report_error(&response_info),
1258 DepositAsset { assets, beneficiary } => W::deposit_asset(assets, beneficiary),
1259 DepositReserveAsset { assets, dest, xcm } => {
1260 W::deposit_reserve_asset(assets, dest, xcm)
1261 },
1262 ExchangeAsset { give, want, maximal } => W::exchange_asset(give, want, maximal),
1263 InitiateReserveWithdraw { assets, reserve, xcm } => {
1264 W::initiate_reserve_withdraw(assets, reserve, xcm)
1265 },
1266 InitiateTeleport { assets, dest, xcm } => W::initiate_teleport(assets, dest, xcm),
1267 ReportHolding { response_info, assets } => W::report_holding(&response_info, &assets),
1268 BuyExecution { fees, weight_limit } => W::buy_execution(fees, weight_limit),
1269 RefundSurplus => W::refund_surplus(),
1270 SetErrorHandler(xcm) => W::set_error_handler(xcm),
1271 SetAppendix(xcm) => W::set_appendix(xcm),
1272 ClearError => W::clear_error(),
1273 ClaimAsset { assets, ticket } => W::claim_asset(assets, ticket),
1274 Trap(code) => W::trap(code),
1275 SubscribeVersion { query_id, max_response_weight } => {
1276 W::subscribe_version(query_id, max_response_weight)
1277 },
1278 UnsubscribeVersion => W::unsubscribe_version(),
1279 BurnAsset(assets) => W::burn_asset(assets),
1280 ExpectAsset(assets) => W::expect_asset(assets),
1281 ExpectOrigin(origin) => W::expect_origin(origin),
1282 ExpectError(error) => W::expect_error(error),
1283 ExpectTransactStatus(transact_status) => W::expect_transact_status(transact_status),
1284 QueryPallet { module_name, response_info } => {
1285 W::query_pallet(module_name, response_info)
1286 },
1287 ExpectPallet { index, name, module_name, crate_major, min_crate_minor } => {
1288 W::expect_pallet(index, name, module_name, crate_major, min_crate_minor)
1289 },
1290 ReportTransactStatus(response_info) => W::report_transact_status(response_info),
1291 ClearTransactStatus => W::clear_transact_status(),
1292 UniversalOrigin(j) => W::universal_origin(j),
1293 ExportMessage { network, destination, xcm } => {
1294 W::export_message(network, destination, xcm)
1295 },
1296 LockAsset { asset, unlocker } => W::lock_asset(asset, unlocker),
1297 UnlockAsset { asset, target } => W::unlock_asset(asset, target),
1298 NoteUnlockable { asset, owner } => W::note_unlockable(asset, owner),
1299 RequestUnlock { asset, locker } => W::request_unlock(asset, locker),
1300 SetFeesMode { jit_withdraw } => W::set_fees_mode(jit_withdraw),
1301 SetTopic(topic) => W::set_topic(topic),
1302 ClearTopic => W::clear_topic(),
1303 AliasOrigin(location) => W::alias_origin(location),
1304 UnpaidExecution { weight_limit, check_origin } => {
1305 W::unpaid_execution(weight_limit, check_origin)
1306 },
1307 }
1308 }
1309}
1310
1311pub mod opaque {
1312 pub type Xcm = super::Xcm<()>;
1315
1316 pub type Instruction = super::Instruction<()>;
1319}
1320
1321impl<Call> TryFrom<NewXcm<Call>> for Xcm<Call> {
1323 type Error = ();
1324 fn try_from(new_xcm: NewXcm<Call>) -> result::Result<Self, Self::Error> {
1325 Ok(Xcm(new_xcm.0.into_iter().map(TryInto::try_into).collect::<result::Result<_, _>>()?))
1326 }
1327}
1328
1329impl<Call> TryFrom<NewInstruction<Call>> for Instruction<Call> {
1331 type Error = ();
1332 fn try_from(new_instruction: NewInstruction<Call>) -> result::Result<Self, Self::Error> {
1333 use NewInstruction::*;
1334 Ok(match new_instruction {
1335 WithdrawAsset(assets) => Self::WithdrawAsset(assets.try_into()?),
1336 ReserveAssetDeposited(assets) => Self::ReserveAssetDeposited(assets.try_into()?),
1337 ReceiveTeleportedAsset(assets) => Self::ReceiveTeleportedAsset(assets.try_into()?),
1338 QueryResponse { query_id, response, max_weight, querier: Some(querier) } => {
1339 Self::QueryResponse {
1340 query_id,
1341 querier: querier.try_into()?,
1342 response: response.try_into()?,
1343 max_weight,
1344 }
1345 },
1346 QueryResponse { query_id, response, max_weight, querier: None } => {
1347 Self::QueryResponse {
1348 query_id,
1349 querier: None,
1350 response: response.try_into()?,
1351 max_weight,
1352 }
1353 },
1354 TransferAsset { assets, beneficiary } => Self::TransferAsset {
1355 assets: assets.try_into()?,
1356 beneficiary: beneficiary.try_into()?,
1357 },
1358 TransferReserveAsset { assets, dest, xcm } => Self::TransferReserveAsset {
1359 assets: assets.try_into()?,
1360 dest: dest.try_into()?,
1361 xcm: xcm.try_into()?,
1362 },
1363 HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => {
1364 Self::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity }
1365 },
1366 HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient },
1367 HrmpChannelClosing { initiator, sender, recipient } => {
1368 Self::HrmpChannelClosing { initiator, sender, recipient }
1369 },
1370 Transact { origin_kind, require_weight_at_most, call } => {
1371 Self::Transact { origin_kind, require_weight_at_most, call: call.into() }
1372 },
1373 ReportError(response_info) => Self::ReportError(QueryResponseInfo {
1374 query_id: response_info.query_id,
1375 destination: response_info.destination.try_into().map_err(|_| ())?,
1376 max_weight: response_info.max_weight,
1377 }),
1378 DepositAsset { assets, beneficiary } => {
1379 let beneficiary = beneficiary.try_into()?;
1380 let assets = assets.try_into()?;
1381 Self::DepositAsset { assets, beneficiary }
1382 },
1383 DepositReserveAsset { assets, dest, xcm } => {
1384 let dest = dest.try_into()?;
1385 let xcm = xcm.try_into()?;
1386 let assets = assets.try_into()?;
1387 Self::DepositReserveAsset { assets, dest, xcm }
1388 },
1389 ExchangeAsset { give, want, maximal } => {
1390 let give = give.try_into()?;
1391 let want = want.try_into()?;
1392 Self::ExchangeAsset { give, want, maximal }
1393 },
1394 InitiateReserveWithdraw { assets, reserve, xcm } => {
1395 let assets = assets.try_into()?;
1397 let reserve = reserve.try_into()?;
1398 let xcm = xcm.try_into()?;
1399 Self::InitiateReserveWithdraw { assets, reserve, xcm }
1400 },
1401 InitiateTeleport { assets, dest, xcm } => {
1402 let assets = assets.try_into()?;
1404 let dest = dest.try_into()?;
1405 let xcm = xcm.try_into()?;
1406 Self::InitiateTeleport { assets, dest, xcm }
1407 },
1408 ReportHolding { response_info, assets } => {
1409 let response_info = QueryResponseInfo {
1410 destination: response_info.destination.try_into().map_err(|_| ())?,
1411 query_id: response_info.query_id,
1412 max_weight: response_info.max_weight,
1413 };
1414 Self::ReportHolding { response_info, assets: assets.try_into()? }
1415 },
1416 BuyExecution { fees, weight_limit } => {
1417 let fees = fees.try_into()?;
1418 let weight_limit = weight_limit.into();
1419 Self::BuyExecution { fees, weight_limit }
1420 },
1421 ClearOrigin => Self::ClearOrigin,
1422 DescendOrigin(who) => Self::DescendOrigin(who.try_into()?),
1423 RefundSurplus => Self::RefundSurplus,
1424 SetErrorHandler(xcm) => Self::SetErrorHandler(xcm.try_into()?),
1425 SetAppendix(xcm) => Self::SetAppendix(xcm.try_into()?),
1426 ClearError => Self::ClearError,
1427 ClaimAsset { assets, ticket } => {
1428 let assets = assets.try_into()?;
1429 let ticket = ticket.try_into()?;
1430 Self::ClaimAsset { assets, ticket }
1431 },
1432 Trap(code) => Self::Trap(code),
1433 SubscribeVersion { query_id, max_response_weight } => {
1434 Self::SubscribeVersion { query_id, max_response_weight }
1435 },
1436 UnsubscribeVersion => Self::UnsubscribeVersion,
1437 BurnAsset(assets) => Self::BurnAsset(assets.try_into()?),
1438 ExpectAsset(assets) => Self::ExpectAsset(assets.try_into()?),
1439 ExpectOrigin(maybe_origin) => {
1440 Self::ExpectOrigin(maybe_origin.map(|origin| origin.try_into()).transpose()?)
1441 },
1442 ExpectError(maybe_error) => Self::ExpectError(maybe_error),
1443 ExpectTransactStatus(maybe_error_code) => Self::ExpectTransactStatus(maybe_error_code),
1444 QueryPallet { module_name, response_info } => {
1445 Self::QueryPallet { module_name, response_info: response_info.try_into()? }
1446 },
1447 ExpectPallet { index, name, module_name, crate_major, min_crate_minor } => {
1448 Self::ExpectPallet { index, name, module_name, crate_major, min_crate_minor }
1449 },
1450 ReportTransactStatus(response_info) => {
1451 Self::ReportTransactStatus(response_info.try_into()?)
1452 },
1453 ClearTransactStatus => Self::ClearTransactStatus,
1454 UniversalOrigin(junction) => Self::UniversalOrigin(junction.try_into()?),
1455 ExportMessage { network, destination, xcm } => Self::ExportMessage {
1456 network: network.into(),
1457 destination: destination.try_into()?,
1458 xcm: xcm.try_into()?,
1459 },
1460 LockAsset { asset, unlocker } => {
1461 Self::LockAsset { asset: asset.try_into()?, unlocker: unlocker.try_into()? }
1462 },
1463 UnlockAsset { asset, target } => {
1464 Self::UnlockAsset { asset: asset.try_into()?, target: target.try_into()? }
1465 },
1466 NoteUnlockable { asset, owner } => {
1467 Self::NoteUnlockable { asset: asset.try_into()?, owner: owner.try_into()? }
1468 },
1469 RequestUnlock { asset, locker } => {
1470 Self::RequestUnlock { asset: asset.try_into()?, locker: locker.try_into()? }
1471 },
1472 SetFeesMode { jit_withdraw } => Self::SetFeesMode { jit_withdraw },
1473 SetTopic(topic) => Self::SetTopic(topic),
1474 ClearTopic => Self::ClearTopic,
1475 AliasOrigin(location) => Self::AliasOrigin(location.try_into()?),
1476 UnpaidExecution { weight_limit, check_origin } => Self::UnpaidExecution {
1477 weight_limit,
1478 check_origin: check_origin.map(|origin| origin.try_into()).transpose()?,
1479 },
1480 })
1481 }
1482}
1483
1484#[cfg(test)]
1485mod tests {
1486 use super::{prelude::*, *};
1487 use crate::MAX_INSTRUCTIONS_TO_DECODE;
1488
1489 #[test]
1490 fn decoding_respects_limit() {
1491 let max_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize]);
1492 let encoded = max_xcm.encode();
1493 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_ok());
1494
1495 let big_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize + 1]);
1496 let encoded = big_xcm.encode();
1497 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1498
1499 let nested_xcm = Xcm::<()>(vec![
1500 DepositReserveAsset {
1501 assets: All.into(),
1502 dest: Here.into(),
1503 xcm: max_xcm,
1504 };
1505 (MAX_INSTRUCTIONS_TO_DECODE / 2) as usize
1506 ]);
1507 let encoded = nested_xcm.encode();
1508 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1509
1510 let even_more_nested_xcm = Xcm::<()>(vec![SetAppendix(nested_xcm); 64]);
1511 let encoded = even_more_nested_xcm.encode();
1512 assert_eq!(encoded.len(), 342530);
1513 assert_eq!(MAX_INSTRUCTIONS_TO_DECODE, 100, "precondition");
1515 assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1516 }
1517}