git.delta.rocks / unique-network / refs/commits / 6cd8e0c2387a

difftreelog

source

pallets/common/src/account.rs5.0 KiBsourcehistory
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 + Default14// +15// Serialize + Deserialize<'static>16{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	/// If true - then ethereum is canonical encoding34	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			// ethereum is canonical encoding, but we need to compare derived address86			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}183184/// Should have same mapping as EnsureAddressTruncated185pub 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}