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