1use crate::Config;2use codec::{Encode, EncodeLike, Decode};3use sp_core::H160;4use scale_info::{Type, TypeInfo};5use sp_core::crypto::AccountId32;6use core::cmp::Ordering;7use serde::{Serialize, Deserialize};8use pallet_evm::AddressMapping;9use sp_std::vec::Vec;10use sp_std::clone::Clone;1112pub trait CrossAccountId<AccountId>:13 Encode + EncodeLike + Decode + TypeInfo + Clone + PartialEq + Ord + core::fmt::Debug + Default141516{17 fn as_sub(&self) -> &AccountId;18 fn as_eth(&self) -> &H160;1920 fn from_sub(account: AccountId) -> Self;21 fn from_eth(account: H160) -> Self;22}2324#[derive(Encode, Decode, Serialize, Deserialize, TypeInfo)]25#[serde(rename_all = "camelCase")]26enum BasicCrossAccountIdRepr<AccountId> {27 Substrate(AccountId),28 Ethereum(H160),29}3031#[derive(Eq)]32pub struct BasicCrossAccountId<T: Config> {33 34 from_ethereum: bool,35 substrate: T::AccountId,36 ethereum: H160,37}3839impl<T: Config> TypeInfo for BasicCrossAccountId<T> {40 type Identity = Self;4142 fn type_info() -> Type {43 <BasicCrossAccountIdRepr<T::AccountId>>::type_info()44 }45}4647impl<T: Config> Default for BasicCrossAccountId<T> {48 fn default() -> Self {49 Self::from_sub(T::AccountId::default())50 }51}5253impl<T: Config> core::fmt::Debug for BasicCrossAccountId<T> {54 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {55 if self.from_ethereum {56 fmt.debug_tuple("CrossAccountId::Ethereum")57 .field(&self.ethereum)58 .finish()59 } else {60 fmt.debug_tuple("CrossAccountId::Substrate")61 .field(&self.substrate)62 .finish()63 }64 }65}6667impl<T: Config> PartialOrd for BasicCrossAccountId<T> {68 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {69 Some(self.substrate.cmp(&other.substrate))70 }71}7273impl<T: Config> Ord for BasicCrossAccountId<T> {74 fn cmp(&self, other: &Self) -> Ordering {75 self.partial_cmp(other)76 .expect("substrate account is total ordered")77 }78}7980impl<T: Config> PartialEq for BasicCrossAccountId<T> {81 fn eq(&self, other: &Self) -> bool {82 if self.from_ethereum == other.from_ethereum {83 self.substrate == other.substrate && self.ethereum == other.ethereum84 } else if self.from_ethereum {85 86 self.substrate == other.substrate87 } else {88 self.ethereum == other.ethereum89 }90 }91}92impl<T: Config> Clone for BasicCrossAccountId<T> {93 fn clone(&self) -> Self {94 Self {95 from_ethereum: self.from_ethereum,96 substrate: self.substrate.clone(),97 ethereum: self.ethereum,98 }99 }100}101impl<T: Config> Encode for BasicCrossAccountId<T> {102 fn encode(&self) -> Vec<u8> {103 BasicCrossAccountIdRepr::from(self.clone()).encode()104 }105}106impl<T: Config> EncodeLike for BasicCrossAccountId<T> {}107impl<T: Config> Decode for BasicCrossAccountId<T> {108 fn decode<I>(input: &mut I) -> Result<Self, codec::Error>109 where110 I: codec::Input,111 {112 Ok(BasicCrossAccountIdRepr::decode(input)?.into())113 }114}115impl<T> Serialize for BasicCrossAccountId<T>116where117 T: Config,118 T::AccountId: Serialize,119{120 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>121 where122 S: serde::Serializer,123 {124 let repr = BasicCrossAccountIdRepr::from(self.clone());125 (&repr).serialize(serializer)126 }127}128impl<'de, T> Deserialize<'de> for BasicCrossAccountId<T>129where130 T: Config,131 T::AccountId: Deserialize<'de>,132{133 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>134 where135 D: serde::Deserializer<'de>,136 {137 Ok(BasicCrossAccountIdRepr::deserialize(deserializer)?.into())138 }139}140impl<T: Config> CrossAccountId<T::AccountId> for BasicCrossAccountId<T> {141 fn as_sub(&self) -> &T::AccountId {142 &self.substrate143 }144 fn as_eth(&self) -> &H160 {145 &self.ethereum146 }147 fn from_sub(substrate: T::AccountId) -> Self {148 Self {149 ethereum: T::EvmBackwardsAddressMapping::from_account_id(substrate.clone()),150 substrate,151 from_ethereum: false,152 }153 }154 fn from_eth(ethereum: H160) -> Self {155 Self {156 ethereum,157 substrate: T::EvmAddressMapping::into_account_id(ethereum),158 from_ethereum: true,159 }160 }161}162impl<T: Config> From<BasicCrossAccountIdRepr<T::AccountId>> for BasicCrossAccountId<T> {163 fn from(repr: BasicCrossAccountIdRepr<T::AccountId>) -> Self {164 match repr {165 BasicCrossAccountIdRepr::Substrate(s) => Self::from_sub(s),166 BasicCrossAccountIdRepr::Ethereum(e) => Self::from_eth(e),167 }168 }169}170impl<T: Config> From<BasicCrossAccountId<T>> for BasicCrossAccountIdRepr<T::AccountId> {171 fn from(v: BasicCrossAccountId<T>) -> Self {172 if v.from_ethereum {173 BasicCrossAccountIdRepr::Ethereum(*v.as_eth())174 } else {175 BasicCrossAccountIdRepr::Substrate(v.as_sub().clone())176 }177 }178}179180pub trait EvmBackwardsAddressMapping<AccountId> {181 fn from_account_id(account_id: AccountId) -> H160;182}183184185pub struct MapBackwardsAddressTruncated;186impl EvmBackwardsAddressMapping<AccountId32> for MapBackwardsAddressTruncated {187 fn from_account_id(account_id: AccountId32) -> H160 {188 let mut out = [0; 20];189 out.copy_from_slice(&(account_id.as_ref() as &[u8])[0..20]);190 H160(out)191 }192}