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