1use crate::Config;2use codec::{Encode, EncodeLike, Decode};3use sp_core::{H160, H256, crypto::AccountId32};4use core::cmp::Ordering;5use serde::{Serialize, Deserialize};6use pallet_evm::AddressMapping;7use sp_std::vec::Vec;8use sp_std::clone::Clone;910pub trait CrossAccountId<AccountId>: 11 Encode + EncodeLike + Decode + 12 Clone + PartialEq + Ord + core::fmt::Debug 13 14{15 fn as_sub(&self) -> &AccountId;16 fn as_eth(&self) -> &H160;1718 fn from_sub(account: AccountId) -> Self;19 fn from_eth(account: H160) -> Self;20}2122#[derive(Eq)]23#[derive(Serialize, Deserialize)]24pub struct BasicCrossAccountId<T: Config> {25 26 from_ethereum: bool,27 substrate: T::AccountId,28 ethereum: H160,29}3031impl<T: Config> core::fmt::Debug for BasicCrossAccountId<T> {32 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {33 if self.from_ethereum {34 fmt.debug_tuple("CrossAccountId::Ethereum")35 .field(&self.ethereum)36 .finish()37 } else {38 fmt.debug_tuple("CrossAccountId::Substrate")39 .field(&self.substrate)40 .finish()41 }42 }43}4445impl<T: Config> PartialOrd for BasicCrossAccountId<T> {46 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {47 Some(self.substrate.cmp(&other.substrate))48 }49}5051impl<T: Config> Ord for BasicCrossAccountId<T> {52 fn cmp(&self, other: &Self) -> Ordering {53 self.partial_cmp(other).expect("substrate account is total ordered")54 }55}5657impl<T: Config> PartialEq for BasicCrossAccountId<T> {58 fn eq(&self, other: &Self) -> bool {59 if self.from_ethereum == other.from_ethereum {60 self.substrate == other.substrate && self.ethereum == other.ethereum61 } else if self.from_ethereum {62 63 self.substrate == other.substrate64 } else {65 self.ethereum == other.ethereum66 }67 }68}69impl<T: Config> Clone for BasicCrossAccountId<T> {70 fn clone(&self) -> Self {71 Self {72 from_ethereum: self.from_ethereum,73 substrate: self.substrate.clone(),74 ethereum: self.ethereum,75 }76 }77}78impl<T: Config> Encode for BasicCrossAccountId<T> {79 fn encode(&self) -> Vec<u8> {80 let as_result = if !self.from_ethereum {81 Ok(self.substrate.clone())82 } else {83 Err(self.ethereum)84 };85 as_result.encode()86 }87}88impl<T: Config> EncodeLike for BasicCrossAccountId<T> {}89impl<T: Config> Decode for BasicCrossAccountId<T> {90 fn decode<I>(input: &mut I) -> Result<Self, codec::Error>91 where I: codec::Input92 {93 Ok(match <Result<T::AccountId, H160>>::decode(input)? {94 Ok(s) => Self::from_sub(s),95 Err(e) => Self::from_eth(e),96 })97 }98}99impl<T: Config> CrossAccountId<T::AccountId> for BasicCrossAccountId<T> {100 fn as_sub(&self) -> &T::AccountId {101 &self.substrate102 }103 fn as_eth(&self) -> &H160 {104 &self.ethereum105 }106 fn from_sub(substrate: T::AccountId) -> Self {107 Self {108 ethereum: T::EvmBackwardsAddressMapping::from_account_id(substrate.clone()),109 substrate,110 from_ethereum: false,111 }112 }113 fn from_eth(ethereum: H160) -> Self {114 Self {115 ethereum,116 substrate: T::EvmAddressMapping::into_account_id(ethereum),117 from_ethereum: true,118 }119 }120}121122pub trait EvmBackwardsAddressMapping<AccountId> {123 fn from_account_id(account_id: AccountId) -> H160;124}125126127pub struct MapBackwardsAddressTruncated;128impl EvmBackwardsAddressMapping<AccountId32> for MapBackwardsAddressTruncated {129 fn from_account_id(account_id: AccountId32) -> H160 {130 let mut out = [0; 20];131 out.copy_from_slice(&(account_id.as_ref() as &[u8])[0..20]);132 H160(out)133 }134}