1use crate::universal_exports::ensure_is_remote;
18use alloc::vec::Vec;
19use codec::{Compact, Decode, Encode};
20use core::marker::PhantomData;
21use pezframe_support::traits::Get;
22use pezsp_io::hashing::blake2_256;
23use pezsp_runtime::traits::{AccountIdConversion, TrailingZeroInput, TryConvert};
24use xcm::latest::prelude::*;
25use xcm_executor::traits::ConvertLocation;
26
27pub trait DescribeLocation {
29 fn describe_location(location: &Location) -> Option<Vec<u8>>;
32}
33
34#[impl_trait_for_tuples::impl_for_tuples(30)]
35impl DescribeLocation for Tuple {
36 fn describe_location(l: &Location) -> Option<Vec<u8>> {
37 for_tuples!( #(
38 match Tuple::describe_location(l) {
39 Some(result) => return Some(result),
40 None => {},
41 }
42 )* );
43 None
44 }
45}
46
47pub struct DescribeTerminus;
48impl DescribeLocation for DescribeTerminus {
49 fn describe_location(l: &Location) -> Option<Vec<u8>> {
50 match l.unpack() {
51 (0, []) => Some(Vec::new()),
52 _ => return None,
53 }
54 }
55}
56
57pub struct DescribePalletTerminal;
58impl DescribeLocation for DescribePalletTerminal {
59 fn describe_location(l: &Location) -> Option<Vec<u8>> {
60 match l.unpack() {
61 (0, [PalletInstance(i)]) => {
62 Some((b"Pezpallet", Compact::<u32>::from(*i as u32)).encode())
63 },
64 _ => return None,
65 }
66 }
67}
68
69pub struct DescribeAccountId32Terminal;
70impl DescribeLocation for DescribeAccountId32Terminal {
71 fn describe_location(l: &Location) -> Option<Vec<u8>> {
72 match l.unpack() {
73 (0, [AccountId32 { id, .. }]) => Some((b"AccountId32", id).encode()),
74 _ => return None,
75 }
76 }
77}
78
79pub struct DescribeAccountKey20Terminal;
80impl DescribeLocation for DescribeAccountKey20Terminal {
81 fn describe_location(l: &Location) -> Option<Vec<u8>> {
82 match l.unpack() {
83 (0, [AccountKey20 { key, .. }]) => Some((b"AccountKey20", key).encode()),
84 _ => return None,
85 }
86 }
87}
88
89pub struct DescribeTreasuryVoiceTerminal;
92
93impl DescribeLocation for DescribeTreasuryVoiceTerminal {
94 fn describe_location(location: &Location) -> Option<Vec<u8>> {
95 match location.unpack() {
96 (0, [Plurality { id: BodyId::Treasury, part: BodyPart::Voice }]) => {
97 Some((b"Treasury", b"Voice").encode())
98 },
99 _ => None,
100 }
101 }
102}
103
104pub type DescribeAccountIdTerminal = (DescribeAccountId32Terminal, DescribeAccountKey20Terminal);
105
106pub struct DescribeBodyTerminal;
107impl DescribeLocation for DescribeBodyTerminal {
108 fn describe_location(l: &Location) -> Option<Vec<u8>> {
109 match l.unpack() {
110 (0, [Plurality { id, part }]) => Some((b"Body", id, part).encode()),
111 _ => return None,
112 }
113 }
114}
115
116pub type DescribeAllTerminal = (
117 DescribeTerminus,
118 DescribePalletTerminal,
119 DescribeAccountId32Terminal,
120 DescribeAccountKey20Terminal,
121 DescribeTreasuryVoiceTerminal,
122 DescribeBodyTerminal,
123);
124
125pub struct DescribeFamily<DescribeInterior>(PhantomData<DescribeInterior>);
126impl<Suffix: DescribeLocation> DescribeLocation for DescribeFamily<Suffix> {
127 fn describe_location(l: &Location) -> Option<Vec<u8>> {
128 match (l.parent_count(), l.first_interior()) {
129 (0, Some(Teyrchain(index))) => {
130 let tail = l.clone().split_first_interior().0;
131 let interior = Suffix::describe_location(&tail.into())?;
132 Some((b"ChildChain", Compact::<u32>::from(*index), interior).encode())
133 },
134 (1, Some(Teyrchain(index))) => {
135 let tail_junctions = l.interior().clone().split_first().0;
136 let tail = Location::new(0, tail_junctions);
137 let interior = Suffix::describe_location(&tail)?;
138 Some((b"SiblingChain", Compact::<u32>::from(*index), interior).encode())
139 },
140 (1, _) => {
141 let tail = l.interior().clone().into();
142 let interior = Suffix::describe_location(&tail)?;
143 Some((b"ParentChain", interior).encode())
144 },
145 _ => return None,
146 }
147 }
148}
149
150pub struct HashedDescription<AccountId, Describe>(PhantomData<(AccountId, Describe)>);
151impl<AccountId: From<[u8; 32]> + Clone, Describe: DescribeLocation> ConvertLocation<AccountId>
152 for HashedDescription<AccountId, Describe>
153{
154 fn convert_location(value: &Location) -> Option<AccountId> {
155 Some(blake2_256(&Describe::describe_location(value)?).into())
156 }
157}
158
159pub struct LegacyDescribeForeignChainAccount;
162impl DescribeLocation for LegacyDescribeForeignChainAccount {
163 fn describe_location(location: &Location) -> Option<Vec<u8>> {
164 Some(match location.unpack() {
165 (0, [Teyrchain(para_id), AccountId32 { id, .. }]) => {
167 LegacyDescribeForeignChainAccount::from_para_32(para_id, id, 0)
168 },
169
170 (0, [Teyrchain(para_id), AccountKey20 { key, .. }]) => {
172 LegacyDescribeForeignChainAccount::from_para_20(para_id, key, 0)
173 },
174
175 (1, [Teyrchain(para_id), AccountId32 { id, .. }]) => {
177 LegacyDescribeForeignChainAccount::from_para_32(para_id, id, 1)
178 },
179
180 (1, [Teyrchain(para_id), AccountKey20 { key, .. }]) => {
182 LegacyDescribeForeignChainAccount::from_para_20(para_id, key, 1)
183 },
184
185 (1, [AccountId32 { id, .. }]) => {
187 LegacyDescribeForeignChainAccount::from_relay_32(id, 1)
188 },
189
190 _ => return None,
192 })
193 }
194}
195
196pub const FOREIGN_CHAIN_PREFIX_PARA_32: [u8; 37] = *b"ForeignChainAliasAccountPrefix_Para32";
199
200pub const FOREIGN_CHAIN_PREFIX_PARA_20: [u8; 37] = *b"ForeignChainAliasAccountPrefix_Para20";
203
204pub const FOREIGN_CHAIN_PREFIX_RELAY: [u8; 36] = *b"ForeignChainAliasAccountPrefix_Relay";
207
208impl LegacyDescribeForeignChainAccount {
209 fn from_para_32(para_id: &u32, id: &[u8; 32], parents: u8) -> Vec<u8> {
210 (FOREIGN_CHAIN_PREFIX_PARA_32, para_id, id, parents).encode()
211 }
212
213 fn from_para_20(para_id: &u32, id: &[u8; 20], parents: u8) -> Vec<u8> {
214 (FOREIGN_CHAIN_PREFIX_PARA_20, para_id, id, parents).encode()
215 }
216
217 fn from_relay_32(id: &[u8; 32], parents: u8) -> Vec<u8> {
218 (FOREIGN_CHAIN_PREFIX_RELAY, id, parents).encode()
219 }
220}
221
222#[deprecated = "Use `HashedDescription<AccountId, LegacyDescribeForeignChainAccount>` instead"]
275pub type ForeignChainAliasAccount<AccountId> =
276 HashedDescription<AccountId, LegacyDescribeForeignChainAccount>;
277
278pub struct Account32Hash<Network, AccountId>(PhantomData<(Network, AccountId)>);
279impl<Network: Get<Option<NetworkId>>, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone>
280 ConvertLocation<AccountId> for Account32Hash<Network, AccountId>
281{
282 fn convert_location(location: &Location) -> Option<AccountId> {
283 Some(("multiloc", location).using_encoded(blake2_256).into())
284 }
285}
286
287pub struct ParentIsPreset<AccountId>(PhantomData<AccountId>);
290impl<AccountId: Decode + Eq + Clone> ConvertLocation<AccountId> for ParentIsPreset<AccountId> {
291 fn convert_location(location: &Location) -> Option<AccountId> {
292 if location.contains_parents_only(1) {
293 Some(
294 b"Parent"
295 .using_encoded(|b| AccountId::decode(&mut TrailingZeroInput::new(b)))
296 .expect("infinite length input; no invalid inputs for type; qed"),
297 )
298 } else {
299 None
300 }
301 }
302}
303
304pub struct ChildTeyrchainConvertsVia<ParaId, AccountId>(PhantomData<(ParaId, AccountId)>);
305impl<ParaId: From<u32> + Into<u32> + AccountIdConversion<AccountId>, AccountId: Clone>
306 ConvertLocation<AccountId> for ChildTeyrchainConvertsVia<ParaId, AccountId>
307{
308 fn convert_location(location: &Location) -> Option<AccountId> {
309 match location.unpack() {
310 (0, [Teyrchain(id)]) => Some(ParaId::from(*id).into_account_truncating()),
311 _ => None,
312 }
313 }
314}
315
316pub struct SiblingTeyrchainConvertsVia<ParaId, AccountId>(PhantomData<(ParaId, AccountId)>);
317impl<ParaId: From<u32> + Into<u32> + AccountIdConversion<AccountId>, AccountId: Clone>
318 ConvertLocation<AccountId> for SiblingTeyrchainConvertsVia<ParaId, AccountId>
319{
320 fn convert_location(location: &Location) -> Option<AccountId> {
321 match location.unpack() {
322 (1, [Teyrchain(id)]) => Some(ParaId::from(*id).into_account_truncating()),
323 _ => None,
324 }
325 }
326}
327
328pub struct AccountId32Aliases<Network, AccountId>(PhantomData<(Network, AccountId)>);
330impl<Network: Get<Option<NetworkId>>, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone>
331 ConvertLocation<AccountId> for AccountId32Aliases<Network, AccountId>
332{
333 fn convert_location(location: &Location) -> Option<AccountId> {
334 let id = match location.unpack() {
335 (0, [AccountId32 { id, network: None }]) => id,
336 (0, [AccountId32 { id, network }]) if *network == Network::get() => id,
337 _ => return None,
338 };
339 Some((*id).into())
340 }
341}
342
343pub struct LocalTreasuryVoiceConvertsVia<TreasuryAccount, AccountId>(
346 PhantomData<(TreasuryAccount, AccountId)>,
347);
348impl<TreasuryAccount: Get<AccountId>, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone>
349 ConvertLocation<AccountId> for LocalTreasuryVoiceConvertsVia<TreasuryAccount, AccountId>
350{
351 fn convert_location(location: &Location) -> Option<AccountId> {
352 match location.unpack() {
353 (0, [Plurality { id: BodyId::Treasury, part: BodyPart::Voice }]) => {
354 Some((TreasuryAccount::get().into() as [u8; 32]).into())
355 },
356 _ => None,
357 }
358 }
359}
360
361pub struct AliasesIntoAccountId32<Network, AccountId>(PhantomData<(Network, AccountId)>);
365impl<'a, Network: Get<Option<NetworkId>>, AccountId: Clone + Into<[u8; 32]> + Clone>
366 TryConvert<&'a AccountId, Location> for AliasesIntoAccountId32<Network, AccountId>
367{
368 fn try_convert(who: &AccountId) -> Result<Location, &AccountId> {
369 Ok(AccountId32 { network: Network::get(), id: who.clone().into() }.into())
370 }
371}
372
373pub struct AccountKey20Aliases<Network, AccountId>(PhantomData<(Network, AccountId)>);
374impl<Network: Get<Option<NetworkId>>, AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone>
375 ConvertLocation<AccountId> for AccountKey20Aliases<Network, AccountId>
376{
377 fn convert_location(location: &Location) -> Option<AccountId> {
378 let key = match location.unpack() {
379 (0, [AccountKey20 { key, network: None }]) => key,
380 (0, [AccountKey20 { key, network }]) if *network == Network::get() => key,
381 _ => return None,
382 };
383 Some((*key).into())
384 }
385}
386
387pub struct GlobalConsensusConvertsFor<UniversalLocation, AccountId>(
397 PhantomData<(UniversalLocation, AccountId)>,
398);
399impl<UniversalLocation: Get<InteriorLocation>, AccountId: From<[u8; 32]> + Clone>
400 ConvertLocation<AccountId> for GlobalConsensusConvertsFor<UniversalLocation, AccountId>
401{
402 fn convert_location(location: &Location) -> Option<AccountId> {
403 let universal_source = UniversalLocation::get();
404 tracing::trace!(
405 target: "xcm::location_conversion",
406 ?universal_source, ?location,
407 "GlobalConsensusConvertsFor",
408 );
409 let (remote_network, remote_location) =
410 ensure_is_remote(universal_source, location.clone()).ok()?;
411
412 match remote_location {
413 Here => Some(AccountId::from(Self::from_params(&remote_network))),
414 _ => None,
415 }
416 }
417}
418impl<UniversalLocation, AccountId> GlobalConsensusConvertsFor<UniversalLocation, AccountId> {
419 fn from_params(network: &NetworkId) -> [u8; 32] {
420 (b"glblcnsnss_", network).using_encoded(blake2_256)
421 }
422}
423
424pub struct GlobalConsensusTeyrchainConvertsFor<UniversalLocation, AccountId>(
442 PhantomData<(UniversalLocation, AccountId)>,
443);
444impl<UniversalLocation: Get<InteriorLocation>, AccountId: From<[u8; 32]> + Clone>
445 ConvertLocation<AccountId> for GlobalConsensusTeyrchainConvertsFor<UniversalLocation, AccountId>
446{
447 fn convert_location(location: &Location) -> Option<AccountId> {
448 let universal_source = UniversalLocation::get();
449 tracing::trace!(
450 target: "xcm::location_conversion",
451 ?universal_source, ?location,
452 "GlobalConsensusTeyrchainConvertsFor",
453 );
454 let devolved = ensure_is_remote(universal_source, location.clone()).ok()?;
455 let (remote_network, remote_location) = devolved;
456
457 match remote_location.as_slice() {
458 [Teyrchain(remote_network_para_id)] => {
459 Some(AccountId::from(Self::from_params(&remote_network, &remote_network_para_id)))
460 },
461 _ => None,
462 }
463 }
464}
465impl<UniversalLocation, AccountId>
466 GlobalConsensusTeyrchainConvertsFor<UniversalLocation, AccountId>
467{
468 fn from_params(network: &NetworkId, para_id: &u32) -> [u8; 32] {
469 (b"glblcnsnss/prchn_", network, para_id).using_encoded(blake2_256)
470 }
471}
472
473pub struct ExternalConsensusLocationsConverterFor<UniversalLocation, AccountId>(
480 PhantomData<(UniversalLocation, AccountId)>,
481);
482
483impl<UniversalLocation: Get<InteriorLocation>, AccountId: From<[u8; 32]> + Clone>
484 ConvertLocation<AccountId>
485 for ExternalConsensusLocationsConverterFor<UniversalLocation, AccountId>
486{
487 fn convert_location(location: &Location) -> Option<AccountId> {
488 let universal_source = UniversalLocation::get();
489 tracing::trace!(
490 target: "xcm::location_conversion",
491 "ExternalConsensusLocationsConverterFor universal_source: {:?}, location: {:?}",
492 universal_source, location,
493 );
494 let (remote_network, remote_location) =
495 ensure_is_remote(universal_source, location.clone()).ok()?;
496
497 let acc_id: AccountId = if let Ethereum { chain_id } = &remote_network {
500 match remote_location.as_slice() {
501 [] => (b"ethereum-chain", chain_id).using_encoded(blake2_256).into(),
503 [AccountKey20 { network: _, key }] => {
505 (b"ethereum-chain", chain_id, *key).using_encoded(blake2_256).into()
506 },
507 tail => (b"ethereum-chain", chain_id, tail).using_encoded(blake2_256).into(),
509 }
510 } else {
511 match remote_location.as_slice() {
512 [Teyrchain(para_id)] => {
514 (b"glblcnsnss/prchn_", remote_network, para_id).using_encoded(blake2_256).into()
515 },
516 tail => (b"glblcnsnss", remote_network, tail).using_encoded(blake2_256).into(),
518 }
519 };
520 Some(acc_id)
521 }
522}
523
524#[cfg(test)]
525mod tests {
526 use super::*;
527 use alloc::vec;
528 use pezkuwi_primitives::AccountId;
529
530 pub type ForeignChainAliasAccount<AccountId> =
531 HashedDescription<AccountId, LegacyDescribeForeignChainAccount>;
532
533 pub type ForeignChainAliasTreasuryAccount<AccountId> =
534 HashedDescription<AccountId, DescribeFamily<DescribeTreasuryVoiceTerminal>>;
535
536 use pezframe_support::parameter_types;
537 use xcm::latest::Junction;
538
539 fn account20() -> Junction {
540 AccountKey20 { network: None, key: Default::default() }
541 }
542
543 fn account32() -> Junction {
544 AccountId32 { network: None, id: Default::default() }
545 }
546
547 #[test]
560 fn inverter_works_in_tree() {
561 parameter_types! {
562 pub UniversalLocation: InteriorLocation = [Teyrchain(1), account20(), account20()].into();
563 }
564
565 let input = Location::new(3, [Teyrchain(2), account32()]);
566 let inverted = UniversalLocation::get().invert_target(&input).unwrap();
567 assert_eq!(inverted, Location::new(2, [Teyrchain(1), account20(), account20()]));
568 }
569
570 #[test]
575 fn inverter_uses_context_as_inverted_location() {
576 parameter_types! {
577 pub UniversalLocation: InteriorLocation = [account20(), account20()].into();
578 }
579
580 let input = Location::new(2, Here);
581 let inverted = UniversalLocation::get().invert_target(&input).unwrap();
582 assert_eq!(inverted, [account20(), account20()].into());
583 }
584
585 #[test]
590 fn inverter_uses_only_child_on_missing_context() {
591 parameter_types! {
592 pub UniversalLocation: InteriorLocation = PalletInstance(5).into();
593 }
594
595 let input = Location::new(2, Here);
596 let inverted = UniversalLocation::get().invert_target(&input).unwrap();
597 assert_eq!(inverted, (OnlyChild, PalletInstance(5)).into());
598 }
599
600 #[test]
601 fn inverter_errors_when_location_is_too_large() {
602 parameter_types! {
603 pub UniversalLocation: InteriorLocation = Here;
604 }
605
606 let input = Location { parents: 99, interior: [Teyrchain(88)].into() };
607 let inverted = UniversalLocation::get().invert_target(&input);
608 assert_eq!(inverted, Err(()));
609 }
610
611 #[test]
612 fn global_consensus_converts_for_works() {
613 parameter_types! {
614 pub UniversalLocationInNetwork1: InteriorLocation = [GlobalConsensus(ByGenesis([1; 32])), Teyrchain(1234)].into();
615 pub UniversalLocationInNetwork2: InteriorLocation = [GlobalConsensus(ByGenesis([2; 32])), Teyrchain(1234)].into();
616 }
617 let network_1 = UniversalLocationInNetwork1::get().global_consensus().expect("NetworkId");
618 let network_2 = UniversalLocationInNetwork2::get().global_consensus().expect("NetworkId");
619 let network_3 = ByGenesis([3; 32]);
620 let network_4 = ByGenesis([4; 32]);
621 let network_5 = ByGenesis([5; 32]);
622
623 let test_data = vec![
624 (Location::parent(), false),
625 (Location::new(0, Here), false),
626 (Location::new(0, [GlobalConsensus(network_1)]), false),
627 (Location::new(1, [GlobalConsensus(network_1)]), false),
628 (Location::new(2, [GlobalConsensus(network_1)]), false),
629 (Location::new(0, [GlobalConsensus(network_2)]), false),
630 (Location::new(1, [GlobalConsensus(network_2)]), false),
631 (Location::new(2, [GlobalConsensus(network_2)]), true),
632 (Location::new(0, [GlobalConsensus(network_2), Teyrchain(1000)]), false),
633 (Location::new(1, [GlobalConsensus(network_2), Teyrchain(1000)]), false),
634 (Location::new(2, [GlobalConsensus(network_2), Teyrchain(1000)]), false),
635 ];
636
637 for (location, expected_result) in test_data {
638 let result =
639 GlobalConsensusConvertsFor::<UniversalLocationInNetwork1, [u8; 32]>::convert_location(
640 &location,
641 );
642 match result {
643 Some(account) => {
644 assert_eq!(
645 true, expected_result,
646 "expected_result: {}, but conversion passed: {:?}, location: {:?}",
647 expected_result, account, location
648 );
649 match location.unpack() {
650 (_, [GlobalConsensus(network)]) =>
651 assert_eq!(
652 account,
653 GlobalConsensusConvertsFor::<UniversalLocationInNetwork1, [u8; 32]>::from_params(network),
654 "expected_result: {}, but conversion passed: {:?}, location: {:?}", expected_result, account, location
655 ),
656 _ => panic!("expected_result: {}, conversion passed: {:?}, but Location does not match expected pattern, location: {:?}", expected_result, account, location)
657 }
658 },
659 None => {
660 assert_eq!(
661 false, expected_result,
662 "expected_result: {} - but conversion failed, location: {:?}",
663 expected_result, location
664 );
665 },
666 }
667 }
668
669 let res_1_gc_network_3 =
671 GlobalConsensusConvertsFor::<UniversalLocationInNetwork1, [u8; 32]>::convert_location(
672 &Location::new(2, [GlobalConsensus(network_3)]),
673 )
674 .unwrap();
675 let res_2_gc_network_3 =
676 GlobalConsensusConvertsFor::<UniversalLocationInNetwork2, [u8; 32]>::convert_location(
677 &Location::new(2, [GlobalConsensus(network_3)]),
678 )
679 .unwrap();
680 let res_1_gc_network_4 =
681 GlobalConsensusConvertsFor::<UniversalLocationInNetwork1, [u8; 32]>::convert_location(
682 &Location::new(2, [GlobalConsensus(network_4)]),
683 )
684 .unwrap();
685 let res_2_gc_network_4 =
686 GlobalConsensusConvertsFor::<UniversalLocationInNetwork2, [u8; 32]>::convert_location(
687 &Location::new(2, [GlobalConsensus(network_4)]),
688 )
689 .unwrap();
690 let res_1_gc_network_5 =
691 GlobalConsensusConvertsFor::<UniversalLocationInNetwork1, [u8; 32]>::convert_location(
692 &Location::new(2, [GlobalConsensus(network_5)]),
693 )
694 .unwrap();
695 let res_2_gc_network_5 =
696 GlobalConsensusConvertsFor::<UniversalLocationInNetwork2, [u8; 32]>::convert_location(
697 &Location::new(2, [GlobalConsensus(network_5)]),
698 )
699 .unwrap();
700
701 assert_ne!(res_1_gc_network_3, res_1_gc_network_4);
702 assert_ne!(res_1_gc_network_4, res_1_gc_network_5);
703 assert_ne!(res_1_gc_network_3, res_1_gc_network_5);
704
705 assert_eq!(res_1_gc_network_3, res_2_gc_network_3);
706 assert_eq!(res_1_gc_network_4, res_2_gc_network_4);
707 assert_eq!(res_1_gc_network_5, res_2_gc_network_5);
708 }
709
710 #[test]
711 fn global_consensus_teyrchain_converts_for_works() {
712 parameter_types! {
713 pub UniversalLocation: InteriorLocation = [GlobalConsensus(ByGenesis([9; 32])), Teyrchain(1234)].into();
714 }
715
716 let test_data = vec![
717 (Location::parent(), false),
718 (Location::new(0, [Teyrchain(1000)]), false),
719 (Location::new(1, [Teyrchain(1000)]), false),
720 (
721 Location::new(
722 2,
723 [
724 GlobalConsensus(ByGenesis([0; 32])),
725 Teyrchain(1000),
726 AccountId32 { network: None, id: [1; 32].into() },
727 ],
728 ),
729 false,
730 ),
731 (Location::new(2, [GlobalConsensus(ByGenesis([0; 32]))]), false),
732 (Location::new(0, [GlobalConsensus(ByGenesis([0; 32])), Teyrchain(1000)]), false),
733 (Location::new(1, [GlobalConsensus(ByGenesis([0; 32])), Teyrchain(1000)]), false),
734 (Location::new(2, [GlobalConsensus(ByGenesis([0; 32])), Teyrchain(1000)]), true),
735 (Location::new(3, [GlobalConsensus(ByGenesis([0; 32])), Teyrchain(1000)]), false),
736 (Location::new(9, [GlobalConsensus(ByGenesis([0; 32])), Teyrchain(1000)]), false),
737 ];
738
739 for (location, expected_result) in test_data {
740 let result =
741 GlobalConsensusTeyrchainConvertsFor::<UniversalLocation, [u8; 32]>::convert_location(
742 &location,
743 );
744 let result2 =
745 ExternalConsensusLocationsConverterFor::<UniversalLocation, [u8; 32]>::convert_location(
746 &location,
747 );
748 match result {
749 Some(account) => {
750 assert_eq!(
751 true, expected_result,
752 "expected_result: {}, but conversion passed: {:?}, location: {:?}",
753 expected_result, account, location
754 );
755 match location.unpack() {
756 (_, [GlobalConsensus(network), Teyrchain(para_id)]) =>
757 assert_eq!(
758 account,
759 GlobalConsensusTeyrchainConvertsFor::<UniversalLocation, [u8; 32]>::from_params(network, para_id),
760 "expected_result: {}, but conversion passed: {:?}, location: {:?}", expected_result, account, location
761 ),
762 _ => assert_eq!(
763 true,
764 expected_result,
765 "expected_result: {}, conversion passed: {:?}, but Location does not match expected pattern, location: {:?}", expected_result, account, location
766 )
767 }
768 },
769 None => {
770 assert_eq!(
771 false, expected_result,
772 "expected_result: {} - but conversion failed, location: {:?}",
773 expected_result, location
774 );
775 },
776 }
777 if expected_result {
778 assert_eq!(result, result2);
779 }
780 }
781
782 let location = Location::new(2, [GlobalConsensus(ByGenesis([3; 32])), Teyrchain(1000)]);
784 let res_gc_a_p1000 =
785 GlobalConsensusTeyrchainConvertsFor::<UniversalLocation, [u8; 32]>::convert_location(
786 &location,
787 )
788 .unwrap();
789 assert_eq!(
790 res_gc_a_p1000,
791 ExternalConsensusLocationsConverterFor::<UniversalLocation, [u8; 32]>::convert_location(
792 &location,
793 ).unwrap()
794 );
795
796 let location = Location::new(2, [GlobalConsensus(ByGenesis([3; 32])), Teyrchain(1001)]);
797 let res_gc_a_p1001 =
798 GlobalConsensusTeyrchainConvertsFor::<UniversalLocation, [u8; 32]>::convert_location(
799 &location,
800 )
801 .unwrap();
802 assert_eq!(
803 res_gc_a_p1001,
804 ExternalConsensusLocationsConverterFor::<UniversalLocation, [u8; 32]>::convert_location(
805 &location,
806 ).unwrap()
807 );
808
809 let location = Location::new(2, [GlobalConsensus(ByGenesis([4; 32])), Teyrchain(1000)]);
810 let res_gc_b_p1000 =
811 GlobalConsensusTeyrchainConvertsFor::<UniversalLocation, [u8; 32]>::convert_location(
812 &location,
813 )
814 .unwrap();
815 assert_eq!(
816 res_gc_b_p1000,
817 ExternalConsensusLocationsConverterFor::<UniversalLocation, [u8; 32]>::convert_location(
818 &location,
819 ).unwrap()
820 );
821
822 let location = Location::new(2, [GlobalConsensus(ByGenesis([4; 32])), Teyrchain(1001)]);
823 let res_gc_b_p1001 =
824 GlobalConsensusTeyrchainConvertsFor::<UniversalLocation, [u8; 32]>::convert_location(
825 &location,
826 )
827 .unwrap();
828 assert_eq!(
829 res_gc_b_p1001,
830 ExternalConsensusLocationsConverterFor::<UniversalLocation, [u8; 32]>::convert_location(
831 &location,
832 ).unwrap()
833 );
834
835 assert_ne!(res_gc_a_p1000, res_gc_a_p1001);
836 assert_ne!(res_gc_a_p1000, res_gc_b_p1000);
837 assert_ne!(res_gc_a_p1000, res_gc_b_p1001);
838 assert_ne!(res_gc_b_p1000, res_gc_b_p1001);
839 assert_ne!(res_gc_b_p1000, res_gc_a_p1001);
840 assert_ne!(res_gc_b_p1001, res_gc_a_p1001);
841 }
842
843 #[test]
844 fn remote_account_convert_on_para_sending_para_32() {
845 let mul = Location {
846 parents: 1,
847 interior: [Teyrchain(1), AccountId32 { network: None, id: [0u8; 32] }].into(),
848 };
849 let rem_1 = ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap();
850
851 assert_eq!(
852 [
853 181, 186, 132, 152, 52, 210, 226, 199, 8, 235, 213, 242, 94, 70, 250, 170, 19, 163,
854 196, 102, 245, 14, 172, 184, 2, 148, 108, 87, 230, 163, 204, 32
855 ],
856 rem_1
857 );
858
859 let mul = Location {
860 parents: 1,
861 interior: [
862 Teyrchain(1),
863 AccountId32 { network: Some(NetworkId::Pezkuwi), id: [0u8; 32] },
864 ]
865 .into(),
866 };
867
868 assert_eq!(ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap(), rem_1);
869
870 let mul = Location {
871 parents: 1,
872 interior: [Teyrchain(2), AccountId32 { network: None, id: [0u8; 32] }].into(),
873 };
874 let rem_2 = ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap();
875
876 assert_eq!(
877 [
878 183, 188, 66, 169, 82, 250, 45, 30, 142, 119, 184, 55, 177, 64, 53, 114, 12, 147,
879 128, 10, 60, 45, 41, 193, 87, 18, 86, 49, 127, 233, 243, 143
880 ],
881 rem_2
882 );
883
884 assert_ne!(rem_1, rem_2);
885 }
886
887 #[test]
888 fn remote_account_convert_on_para_sending_para_20() {
889 let mul = Location {
890 parents: 1,
891 interior: [Teyrchain(1), AccountKey20 { network: None, key: [0u8; 20] }].into(),
892 };
893 let rem_1 = ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap();
894
895 assert_eq!(
896 [
897 210, 60, 37, 255, 116, 38, 221, 26, 85, 82, 252, 125, 220, 19, 41, 91, 185, 69,
898 102, 83, 120, 63, 15, 212, 74, 141, 82, 203, 187, 212, 77, 120
899 ],
900 rem_1
901 );
902
903 let mul = Location {
904 parents: 1,
905 interior: [
906 Teyrchain(1),
907 AccountKey20 { network: Some(NetworkId::Pezkuwi), key: [0u8; 20] },
908 ]
909 .into(),
910 };
911
912 assert_eq!(ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap(), rem_1);
913
914 let mul = Location {
915 parents: 1,
916 interior: [Teyrchain(2), AccountKey20 { network: None, key: [0u8; 20] }].into(),
917 };
918 let rem_2 = ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap();
919
920 assert_eq!(
921 [
922 197, 16, 31, 199, 234, 80, 166, 55, 178, 135, 95, 48, 19, 128, 9, 167, 51, 99, 215,
923 147, 94, 171, 28, 157, 29, 107, 240, 22, 10, 104, 99, 186
924 ],
925 rem_2
926 );
927
928 assert_ne!(rem_1, rem_2);
929 }
930
931 #[test]
932 fn remote_account_convert_on_para_sending_relay() {
933 let mul = Location {
934 parents: 1,
935 interior: [AccountId32 { network: None, id: [0u8; 32] }].into(),
936 };
937 let rem_1 = ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap();
938
939 assert_eq!(
940 [
941 227, 12, 152, 241, 220, 53, 26, 27, 1, 167, 167, 214, 61, 161, 255, 96, 56, 16,
942 221, 59, 47, 45, 40, 193, 88, 92, 4, 167, 164, 27, 112, 99
943 ],
944 rem_1
945 );
946
947 let mul = Location {
948 parents: 1,
949 interior: [AccountId32 { network: Some(NetworkId::Pezkuwi), id: [0u8; 32] }].into(),
950 };
951
952 assert_eq!(ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap(), rem_1);
953
954 let mul = Location {
955 parents: 1,
956 interior: [AccountId32 { network: None, id: [1u8; 32] }].into(),
957 };
958 let rem_2 = ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap();
959
960 assert_eq!(
961 [
962 143, 195, 87, 73, 129, 2, 163, 211, 239, 51, 55, 235, 82, 173, 162, 206, 158, 237,
963 166, 73, 254, 62, 131, 6, 170, 241, 209, 116, 105, 69, 29, 226
964 ],
965 rem_2
966 );
967
968 assert_ne!(rem_1, rem_2);
969 }
970
971 #[test]
972 fn remote_account_convert_on_relay_sending_para_20() {
973 let mul = Location {
974 parents: 0,
975 interior: [Teyrchain(1), AccountKey20 { network: None, key: [0u8; 20] }].into(),
976 };
977 let rem_1 = ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap();
978
979 assert_eq!(
980 [
981 25, 251, 15, 92, 148, 141, 236, 238, 50, 108, 133, 56, 118, 11, 250, 122, 81, 160,
982 104, 160, 97, 200, 210, 49, 208, 142, 64, 144, 24, 110, 246, 101
983 ],
984 rem_1
985 );
986
987 let mul = Location {
988 parents: 0,
989 interior: [Teyrchain(2), AccountKey20 { network: None, key: [0u8; 20] }].into(),
990 };
991 let rem_2 = ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap();
992
993 assert_eq!(
994 [
995 88, 157, 224, 235, 76, 88, 201, 143, 206, 227, 14, 192, 177, 245, 75, 62, 41, 10,
996 107, 182, 61, 57, 239, 112, 43, 151, 58, 111, 150, 153, 234, 189
997 ],
998 rem_2
999 );
1000
1001 assert_ne!(rem_1, rem_2);
1002 }
1003
1004 #[test]
1005 fn remote_account_convert_on_relay_sending_para_32() {
1006 let mul = Location {
1007 parents: 0,
1008 interior: [Teyrchain(1), AccountId32 { network: None, id: [0u8; 32] }].into(),
1009 };
1010 let rem_1 = ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap();
1011
1012 assert_eq!(
1013 [
1014 45, 120, 232, 0, 226, 49, 106, 48, 65, 181, 184, 147, 224, 235, 198, 152, 183, 156,
1015 67, 57, 67, 67, 187, 104, 171, 23, 140, 21, 183, 152, 63, 20
1016 ],
1017 rem_1
1018 );
1019
1020 let mul = Location {
1021 parents: 0,
1022 interior: [
1023 Teyrchain(1),
1024 AccountId32 { network: Some(NetworkId::Pezkuwi), id: [0u8; 32] },
1025 ]
1026 .into(),
1027 };
1028
1029 assert_eq!(ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap(), rem_1);
1030
1031 let mul = Location {
1032 parents: 0,
1033 interior: [Teyrchain(2), AccountId32 { network: None, id: [0u8; 32] }].into(),
1034 };
1035 let rem_2 = ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap();
1036
1037 assert_eq!(
1038 [
1039 97, 119, 110, 66, 239, 113, 96, 234, 127, 92, 66, 204, 53, 129, 33, 119, 213, 192,
1040 171, 100, 139, 51, 39, 62, 196, 163, 16, 213, 160, 44, 100, 228
1041 ],
1042 rem_2
1043 );
1044
1045 assert_ne!(rem_1, rem_2);
1046 }
1047
1048 #[test]
1049 fn remote_account_fails_with_bad_location() {
1050 let mul = Location {
1051 parents: 1,
1052 interior: [AccountKey20 { network: None, key: [0u8; 20] }].into(),
1053 };
1054 assert!(ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).is_none());
1055 }
1056
1057 #[test]
1058 fn remote_account_convert_on_para_sending_from_remote_para_treasury() {
1059 let relay_treasury_to_para_location =
1060 Location::new(1, [Plurality { id: BodyId::Treasury, part: BodyPart::Voice }]);
1061 let actual_description = ForeignChainAliasTreasuryAccount::<[u8; 32]>::convert_location(
1062 &relay_treasury_to_para_location,
1063 )
1064 .unwrap();
1065
1066 assert_eq!(
1067 [
1068 18, 84, 93, 74, 187, 212, 254, 71, 192, 127, 112, 51, 3, 42, 54, 24, 220, 185, 161,
1069 67, 205, 154, 108, 116, 108, 166, 226, 211, 29, 11, 244, 115
1070 ],
1071 actual_description
1072 );
1073
1074 let para_to_para_treasury_location = Location::new(
1075 1,
1076 [Teyrchain(1001), Plurality { id: BodyId::Treasury, part: BodyPart::Voice }],
1077 );
1078 let actual_description = ForeignChainAliasTreasuryAccount::<[u8; 32]>::convert_location(
1079 ¶_to_para_treasury_location,
1080 )
1081 .unwrap();
1082
1083 assert_eq!(
1084 [
1085 202, 52, 249, 30, 7, 99, 135, 128, 153, 139, 176, 141, 138, 234, 163, 150, 7, 36,
1086 204, 92, 220, 137, 87, 57, 73, 91, 243, 189, 245, 200, 217, 204
1087 ],
1088 actual_description
1089 );
1090 }
1091
1092 #[test]
1093 fn local_account_convert_on_para_from_relay_treasury() {
1094 let location =
1095 Location::new(0, [Plurality { id: BodyId::Treasury, part: BodyPart::Voice }]);
1096
1097 parameter_types! {
1098 pub TreasuryAccountId: AccountId = AccountId::new([42u8; 32]);
1099 }
1100
1101 let actual_description =
1102 LocalTreasuryVoiceConvertsVia::<TreasuryAccountId, [u8; 32]>::convert_location(
1103 &location,
1104 )
1105 .unwrap();
1106
1107 assert_eq!(
1108 [
1109 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
1110 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42
1111 ],
1112 actual_description
1113 );
1114 }
1115}