1use crate::Config;2use codec::{Encode, EncodeLike, Decode};3use scale_info::build::{FieldsBuilder, UnnamedFields, Variants};4use scale_info::{Path, Type, TypeInfo};5use sp_core::crypto::AccountId32;6use primitive_types::H160;7use core::cmp::Ordering;8use serde::{Serialize, Deserialize};9use pallet_evm::AddressMapping;10use sp_std::vec::Vec;11use sp_std::clone::Clone;1213pub trait CrossAccountId<AccountId>:14 Encode + EncodeLike + Decode + TypeInfo + Clone + PartialEq + Ord + core::fmt::Debug151617{18 fn as_sub(&self) -> &AccountId;19 fn as_eth(&self) -> &H160;2021 fn from_sub(account: AccountId) -> Self;22 fn from_eth(account: H160) -> Self;23}2425#[derive(Eq, Serialize, Deserialize)]26pub struct BasicCrossAccountId<T: Config> {27 28 from_ethereum: bool,29 substrate: T::AccountId,30 ethereum: H160,31}3233impl<T: Config> TypeInfo for BasicCrossAccountId<T> {34 type Identity = Self;3536 fn type_info() -> Type {37 Type::builder()38 .path(Path::new("BasicCrossAccountId", "pallet_nft::eth::account"))39 40 41 42 43 44 .variant(45 Variants::new()46 .variant("Substrate", |t| {47 t.fields(48 <FieldsBuilder<UnnamedFields>>::default()49 .field(|f| f.ty::<T::AccountId>()),50 )51 .index(0)52 })53 .variant("Ethereum", |t| {54 t.fields(55 <FieldsBuilder<UnnamedFields>>::default().field(|f| f.ty::<H160>()),56 )57 .index(1)58 }),59 )60 }61}6263impl<T: Config> core::fmt::Debug for BasicCrossAccountId<T> {64 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {65 if self.from_ethereum {66 fmt.debug_tuple("CrossAccountId::Ethereum")67 .field(&self.ethereum)68 .finish()69 } else {70 fmt.debug_tuple("CrossAccountId::Substrate")71 .field(&self.substrate)72 .finish()73 }74 }75}7677impl<T: Config> PartialOrd for BasicCrossAccountId<T> {78 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {79 Some(self.substrate.cmp(&other.substrate))80 }81}8283impl<T: Config> Ord for BasicCrossAccountId<T> {84 fn cmp(&self, other: &Self) -> Ordering {85 self.partial_cmp(other)86 .expect("substrate account is total ordered")87 }88}8990impl<T: Config> PartialEq for BasicCrossAccountId<T> {91 fn eq(&self, other: &Self) -> bool {92 if self.from_ethereum == other.from_ethereum {93 self.substrate == other.substrate && self.ethereum == other.ethereum94 } else if self.from_ethereum {95 96 self.substrate == other.substrate97 } else {98 self.ethereum == other.ethereum99 }100 }101}102impl<T: Config> Clone for BasicCrossAccountId<T> {103 fn clone(&self) -> Self {104 Self {105 from_ethereum: self.from_ethereum,106 substrate: self.substrate.clone(),107 ethereum: self.ethereum,108 }109 }110}111impl<T: Config> Encode for BasicCrossAccountId<T> {112 fn encode(&self) -> Vec<u8> {113 let as_result = if !self.from_ethereum {114 Ok(self.substrate.clone())115 } else {116 Err(self.ethereum)117 };118 as_result.encode()119 }120}121impl<T: Config> EncodeLike for BasicCrossAccountId<T> {}122impl<T: Config> Decode for BasicCrossAccountId<T> {123 fn decode<I>(input: &mut I) -> Result<Self, codec::Error>124 where125 I: codec::Input,126 {127 Ok(match <Result<T::AccountId, H160>>::decode(input)? {128 Ok(s) => Self::from_sub(s),129 Err(e) => Self::from_eth(e),130 })131 }132}133impl<T: Config> CrossAccountId<T::AccountId> for BasicCrossAccountId<T> {134 fn as_sub(&self) -> &T::AccountId {135 &self.substrate136 }137 fn as_eth(&self) -> &H160 {138 &self.ethereum139 }140 fn from_sub(substrate: T::AccountId) -> Self {141 Self {142 ethereum: T::EvmBackwardsAddressMapping::from_account_id(substrate.clone()),143 substrate,144 from_ethereum: false,145 }146 }147 fn from_eth(ethereum: H160) -> Self {148 Self {149 ethereum,150 substrate: T::EvmAddressMapping::into_account_id(ethereum),151 from_ethereum: true,152 }153 }154}155156pub trait EvmBackwardsAddressMapping<AccountId> {157 fn from_account_id(account_id: AccountId) -> H160;158}159160161pub struct MapBackwardsAddressTruncated;162impl EvmBackwardsAddressMapping<AccountId32> for MapBackwardsAddressTruncated {163 fn from_account_id(account_id: AccountId32) -> H160 {164 let mut out = [0; 20];165 out.copy_from_slice(&(account_id.as_ref() as &[u8])[0..20]);166 H160(out)167 }168}