1use super::{Junctions, MultiLocation};
20use crate::{
21 v2::{
22 BodyId as OldBodyId, BodyPart as OldBodyPart, Junction as OldJunction,
23 NetworkId as OldNetworkId,
24 },
25 v4::{Junction as NewJunction, NetworkId as NewNetworkId},
26 VersionedLocation,
27};
28use bounded_collections::{BoundedSlice, BoundedVec, ConstU32};
29use codec::{self, Decode, Encode, MaxEncodedLen};
30use scale_info::TypeInfo;
31use serde::{Deserialize, Serialize};
32
33#[derive(
38 Copy,
39 Clone,
40 Eq,
41 PartialEq,
42 Ord,
43 PartialOrd,
44 Encode,
45 Decode,
46 Debug,
47 TypeInfo,
48 MaxEncodedLen,
49 Serialize,
50 Deserialize,
51)]
52#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
53#[scale_info(replace_segment("staging_xcm", "xcm"))]
54pub enum NetworkId {
55 ByGenesis([u8; 32]),
57 ByFork { block_number: u64, block_hash: [u8; 32] },
59 Polkadot,
61 Kusama,
63 Westend,
65 Rococo,
67 Wococo,
69 Ethereum {
71 #[codec(compact)]
73 chain_id: u64,
74 },
75 BitcoinCore,
77 BitcoinCash,
79 PolkadotBulletin,
81}
82
83impl From<OldNetworkId> for Option<NetworkId> {
84 fn from(old: OldNetworkId) -> Option<NetworkId> {
85 use OldNetworkId::*;
86 match old {
87 Any => None,
88 Named(_) => None,
89 Polkadot => Some(NetworkId::Polkadot),
90 Kusama => Some(NetworkId::Kusama),
91 }
92 }
93}
94
95impl TryFrom<OldNetworkId> for NetworkId {
96 type Error = ();
97 fn try_from(old: OldNetworkId) -> Result<Self, Self::Error> {
98 use OldNetworkId::*;
99 match old {
100 Any | Named(_) => Err(()),
101 Polkadot => Ok(NetworkId::Polkadot),
102 Kusama => Ok(NetworkId::Kusama),
103 }
104 }
105}
106
107impl From<NewNetworkId> for Option<NetworkId> {
108 fn from(new: NewNetworkId) -> Self {
109 Some(NetworkId::from(new))
110 }
111}
112
113impl From<NewNetworkId> for NetworkId {
114 fn from(new: NewNetworkId) -> Self {
115 use NewNetworkId::*;
116 match new {
117 ByGenesis(hash) => Self::ByGenesis(hash),
118 ByFork { block_number, block_hash } => Self::ByFork { block_number, block_hash },
119 Polkadot => Self::Polkadot,
120 Kusama => Self::Kusama,
121 Westend => Self::Westend,
122 Rococo => Self::Rococo,
123 Wococo => Self::Wococo,
124 Ethereum { chain_id } => Self::Ethereum { chain_id },
125 BitcoinCore => Self::BitcoinCore,
126 BitcoinCash => Self::BitcoinCash,
127 PolkadotBulletin => Self::PolkadotBulletin,
128 }
129 }
130}
131
132#[derive(
134 Copy,
135 Clone,
136 Eq,
137 PartialEq,
138 Ord,
139 PartialOrd,
140 Encode,
141 Decode,
142 Debug,
143 TypeInfo,
144 MaxEncodedLen,
145 Serialize,
146 Deserialize,
147)]
148#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
149#[scale_info(replace_segment("staging_xcm", "xcm"))]
150pub enum BodyId {
151 Unit,
153 Moniker([u8; 4]),
155 Index(#[codec(compact)] u32),
157 Executive,
159 Technical,
161 Legislative,
164 Judicial,
167 Defense,
170 Administration,
173 Treasury,
176}
177
178impl TryFrom<OldBodyId> for BodyId {
179 type Error = ();
180 fn try_from(value: OldBodyId) -> Result<Self, ()> {
181 use OldBodyId::*;
182 Ok(match value {
183 Unit => Self::Unit,
184 Named(n) =>
185 if n.len() == 4 {
186 let mut r = [0u8; 4];
187 r.copy_from_slice(&n[..]);
188 Self::Moniker(r)
189 } else {
190 return Err(())
191 },
192 Index(n) => Self::Index(n),
193 Executive => Self::Executive,
194 Technical => Self::Technical,
195 Legislative => Self::Legislative,
196 Judicial => Self::Judicial,
197 Defense => Self::Defense,
198 Administration => Self::Administration,
199 Treasury => Self::Treasury,
200 })
201 }
202}
203
204#[derive(
206 Copy,
207 Clone,
208 Eq,
209 PartialEq,
210 Ord,
211 PartialOrd,
212 Encode,
213 Decode,
214 Debug,
215 TypeInfo,
216 MaxEncodedLen,
217 Serialize,
218 Deserialize,
219)]
220#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
221#[scale_info(replace_segment("staging_xcm", "xcm"))]
222pub enum BodyPart {
223 Voice,
225 Members {
227 #[codec(compact)]
228 count: u32,
229 },
230 Fraction {
232 #[codec(compact)]
233 nom: u32,
234 #[codec(compact)]
235 denom: u32,
236 },
237 AtLeastProportion {
239 #[codec(compact)]
240 nom: u32,
241 #[codec(compact)]
242 denom: u32,
243 },
244 MoreThanProportion {
246 #[codec(compact)]
247 nom: u32,
248 #[codec(compact)]
249 denom: u32,
250 },
251}
252
253impl BodyPart {
254 pub fn is_majority(&self) -> bool {
256 match self {
257 BodyPart::Fraction { nom, denom } if *nom * 2 > *denom => true,
258 BodyPart::AtLeastProportion { nom, denom } if *nom * 2 > *denom => true,
259 BodyPart::MoreThanProportion { nom, denom } if *nom * 2 >= *denom => true,
260 _ => false,
261 }
262 }
263}
264
265impl TryFrom<OldBodyPart> for BodyPart {
266 type Error = ();
267 fn try_from(value: OldBodyPart) -> Result<Self, ()> {
268 use OldBodyPart::*;
269 Ok(match value {
270 Voice => Self::Voice,
271 Members { count } => Self::Members { count },
272 Fraction { nom, denom } => Self::Fraction { nom, denom },
273 AtLeastProportion { nom, denom } => Self::AtLeastProportion { nom, denom },
274 MoreThanProportion { nom, denom } => Self::MoreThanProportion { nom, denom },
275 })
276 }
277}
278
279#[derive(
283 Copy,
284 Clone,
285 Eq,
286 PartialEq,
287 Ord,
288 PartialOrd,
289 Encode,
290 Decode,
291 Debug,
292 TypeInfo,
293 MaxEncodedLen,
294 Serialize,
295 Deserialize,
296)]
297#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
298#[scale_info(replace_segment("staging_xcm", "xcm"))]
299pub enum Junction {
300 Parachain(#[codec(compact)] u32),
304 AccountId32 { network: Option<NetworkId>, id: [u8; 32] },
309 AccountIndex64 {
314 network: Option<NetworkId>,
315 #[codec(compact)]
316 index: u64,
317 },
318 AccountKey20 { network: Option<NetworkId>, key: [u8; 20] },
323 PalletInstance(u8),
328 GeneralIndex(#[codec(compact)] u128),
334 GeneralKey { length: u8, data: [u8; 32] },
343 OnlyChild,
347 Plurality { id: BodyId, part: BodyPart },
352 GlobalConsensus(NetworkId),
355}
356
357impl From<NetworkId> for Junction {
358 fn from(n: NetworkId) -> Self {
359 Self::GlobalConsensus(n)
360 }
361}
362
363impl From<[u8; 32]> for Junction {
364 fn from(id: [u8; 32]) -> Self {
365 Self::AccountId32 { network: None, id }
366 }
367}
368
369impl From<BoundedVec<u8, ConstU32<32>>> for Junction {
370 fn from(key: BoundedVec<u8, ConstU32<32>>) -> Self {
371 key.as_bounded_slice().into()
372 }
373}
374
375impl<'a> From<BoundedSlice<'a, u8, ConstU32<32>>> for Junction {
376 fn from(key: BoundedSlice<'a, u8, ConstU32<32>>) -> Self {
377 let mut data = [0u8; 32];
378 data[..key.len()].copy_from_slice(&key[..]);
379 Self::GeneralKey { length: key.len() as u8, data }
380 }
381}
382
383impl<'a> TryFrom<&'a Junction> for BoundedSlice<'a, u8, ConstU32<32>> {
384 type Error = ();
385 fn try_from(key: &'a Junction) -> Result<Self, ()> {
386 match key {
387 Junction::GeneralKey { length, data } =>
388 BoundedSlice::try_from(&data[..data.len().min(*length as usize)]).map_err(|_| ()),
389 _ => Err(()),
390 }
391 }
392}
393
394impl From<[u8; 20]> for Junction {
395 fn from(key: [u8; 20]) -> Self {
396 Self::AccountKey20 { network: None, key }
397 }
398}
399
400impl From<u64> for Junction {
401 fn from(index: u64) -> Self {
402 Self::AccountIndex64 { network: None, index }
403 }
404}
405
406impl From<u128> for Junction {
407 fn from(id: u128) -> Self {
408 Self::GeneralIndex(id)
409 }
410}
411
412impl TryFrom<OldJunction> for Junction {
413 type Error = ();
414 fn try_from(value: OldJunction) -> Result<Self, ()> {
415 use OldJunction::*;
416 Ok(match value {
417 Parachain(id) => Self::Parachain(id),
418 AccountId32 { network, id } => Self::AccountId32 { network: network.into(), id },
419 AccountIndex64 { network, index } =>
420 Self::AccountIndex64 { network: network.into(), index },
421 AccountKey20 { network, key } => Self::AccountKey20 { network: network.into(), key },
422 PalletInstance(index) => Self::PalletInstance(index),
423 GeneralIndex(id) => Self::GeneralIndex(id),
424 GeneralKey(key) => match key.len() {
425 len @ 0..=32 => Self::GeneralKey {
426 length: len as u8,
427 data: {
428 let mut data = [0u8; 32];
429 data[..len].copy_from_slice(&key[..]);
430 data
431 },
432 },
433 _ => return Err(()),
434 },
435 OnlyChild => Self::OnlyChild,
436 Plurality { id, part } =>
437 Self::Plurality { id: id.try_into()?, part: part.try_into()? },
438 })
439 }
440}
441
442impl TryFrom<NewJunction> for Junction {
443 type Error = ();
444
445 fn try_from(value: NewJunction) -> Result<Self, Self::Error> {
446 use NewJunction::*;
447 Ok(match value {
448 Parachain(id) => Self::Parachain(id),
449 AccountId32 { network: maybe_network, id } =>
450 Self::AccountId32 { network: maybe_network.map(|network| network.into()), id },
451 AccountIndex64 { network: maybe_network, index } =>
452 Self::AccountIndex64 { network: maybe_network.map(|network| network.into()), index },
453 AccountKey20 { network: maybe_network, key } =>
454 Self::AccountKey20 { network: maybe_network.map(|network| network.into()), key },
455 PalletInstance(index) => Self::PalletInstance(index),
456 GeneralIndex(id) => Self::GeneralIndex(id),
457 GeneralKey { length, data } => Self::GeneralKey { length, data },
458 OnlyChild => Self::OnlyChild,
459 Plurality { id, part } => Self::Plurality { id, part },
460 GlobalConsensus(network) => Self::GlobalConsensus(network.into()),
461 })
462 }
463}
464
465impl Junction {
466 pub const fn into_location(self) -> MultiLocation {
470 MultiLocation { parents: 0, interior: Junctions::X1(self) }
471 }
472
473 pub const fn into_exterior(self, n: u8) -> MultiLocation {
478 MultiLocation { parents: n, interior: Junctions::X1(self) }
479 }
480
481 pub const fn into_versioned(self) -> VersionedLocation {
485 self.into_location().into_versioned()
486 }
487
488 pub fn remove_network_id(&mut self) {
490 use Junction::*;
491 match self {
492 AccountId32 { ref mut network, .. } |
493 AccountIndex64 { ref mut network, .. } |
494 AccountKey20 { ref mut network, .. } => *network = None,
495 _ => {},
496 }
497 }
498}
499
500#[cfg(test)]
501mod tests {
502 use super::*;
503 use alloc::vec;
504
505 #[test]
506 fn junction_round_trip_works() {
507 let j = Junction::GeneralKey { length: 32, data: [1u8; 32] };
508 let k = Junction::try_from(OldJunction::try_from(j).unwrap()).unwrap();
509 assert_eq!(j, k);
510
511 let j = OldJunction::GeneralKey(vec![1u8; 32].try_into().unwrap());
512 let k = OldJunction::try_from(Junction::try_from(j.clone()).unwrap()).unwrap();
513 assert_eq!(j, k);
514
515 let j = Junction::from(BoundedVec::try_from(vec![1u8, 2, 3, 4]).unwrap());
516 let k = Junction::try_from(OldJunction::try_from(j).unwrap()).unwrap();
517 assert_eq!(j, k);
518 let s: BoundedSlice<_, _> = (&k).try_into().unwrap();
519 assert_eq!(s, &[1u8, 2, 3, 4][..]);
520
521 let j = OldJunction::GeneralKey(vec![1u8, 2, 3, 4].try_into().unwrap());
522 let k = OldJunction::try_from(Junction::try_from(j.clone()).unwrap()).unwrap();
523 assert_eq!(j, k);
524 }
525}