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