frequency_runtime/
ethereum.rs

1use common_primitives::signatures::{AccountAddressMapper, EthereumAddressMapper};
2use core::{fmt::Debug, marker::PhantomData};
3use parity_scale_codec::Codec;
4use scale_info::StaticTypeInfo;
5use sp_core::hexdisplay::HexDisplay;
6use sp_runtime::{
7	traits::{LookupError, StaticLookup},
8	MultiAddress,
9};
10
11/// A lookup implementation returning the `AccountId` from a `MultiAddress`.
12pub struct EthereumCompatibleAccountIdLookup<AccountId, AccountIndex>(
13	PhantomData<(AccountId, AccountIndex)>,
14);
15impl<AccountId, AccountIndex> StaticLookup
16	for EthereumCompatibleAccountIdLookup<AccountId, AccountIndex>
17where
18	AccountId: Codec + Clone + PartialEq + Debug,
19	AccountIndex: Codec + Clone + PartialEq + Debug,
20	MultiAddress<AccountId, AccountIndex>: Codec + StaticTypeInfo,
21{
22	type Source = MultiAddress<AccountId, AccountIndex>;
23	type Target = AccountId;
24	fn lookup(x: Self::Source) -> Result<Self::Target, LookupError> {
25		match x {
26			MultiAddress::Id(i) => Ok(i),
27			MultiAddress::Address20(acc20) => {
28				log::debug!(target: "ETHEREUM", "lookup 0x{:?}", HexDisplay::from(&acc20));
29				let account_id_bytes = EthereumAddressMapper::to_bytes32(&acc20);
30				let decoded =
31					Self::Target::decode(&mut &account_id_bytes[..]).map_err(|_| LookupError)?;
32				Ok(decoded)
33			},
34			_ => Err(LookupError),
35		}
36	}
37	fn unlookup(x: Self::Target) -> Self::Source {
38		// We are not converting back to 20 bytes since everywhere we are using Id
39		MultiAddress::Id(x)
40	}
41}
42
43#[cfg(test)]
44mod tests {
45	use crate::ethereum::EthereumCompatibleAccountIdLookup;
46	use sp_core::{bytes::from_hex, crypto::AccountId32};
47	use sp_runtime::{traits::StaticLookup, MultiAddress};
48
49	#[test]
50	fn address20_should_get_decoded_correctly() {
51		let lookup =
52			EthereumCompatibleAccountIdLookup::<AccountId32, ()>::lookup(MultiAddress::Address20(
53				from_hex("0x19a701d23f0ee1748b5d5f883cb833943096c6c4")
54					.expect("should convert")
55					.try_into()
56					.expect("invalid size"),
57			));
58		assert!(lookup.is_ok());
59
60		let converted = lookup.unwrap();
61		let expected = AccountId32::new(
62			from_hex("0x19a701d23f0ee1748b5d5f883cb833943096c6c4eeeeeeeeeeeeeeeeeeeeeeee")
63				.expect("should convert")
64				.try_into()
65				.expect("invalid size"),
66		);
67		assert_eq!(converted, expected)
68	}
69}