use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use sha3::{Digest, Keccak256};
use sp_core::{ecdsa, H160, H256};
use scale_info::TypeInfo;
#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Encode, Decode, sp_core::RuntimeDebug)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub struct EthereumSigner([u8; 20]);
impl sp_runtime::traits::IdentifyAccount for EthereumSigner {
type AccountId = AccountId20;
fn into_account(self) -> AccountId20 {
AccountId20(self.0)
}
}
impl From<[u8; 20]> for EthereumSigner {
fn from(x: [u8; 20]) -> Self {
EthereumSigner(x)
}
}
impl From<ecdsa::Public> for EthereumSigner {
fn from(x: ecdsa::Public) -> Self {
let decompressed = libsecp256k1::PublicKey::parse_slice(
&x.0,
Some(libsecp256k1::PublicKeyFormat::Compressed),
)
.expect("Wrong compressed public key provided")
.serialize();
let mut m = [0u8; 64];
m.copy_from_slice(&decompressed[1..65]);
let account = H160::from(H256::from_slice(Keccak256::digest(&m).as_slice()));
EthereumSigner(account.into())
}
}
impl From<libsecp256k1::PublicKey> for EthereumSigner {
fn from(x: libsecp256k1::PublicKey) -> Self {
let mut m = [0u8; 64];
m.copy_from_slice(&x.serialize()[1..65]);
let account = H160::from(H256::from_slice(Keccak256::digest(&m).as_slice()));
EthereumSigner(account.into())
}
}
#[derive(
Eq, PartialEq, Copy, Clone, Encode, Decode, TypeInfo, MaxEncodedLen, Default, PartialOrd, Ord,
)]
pub struct AccountId20(pub [u8; 20]);
#[cfg(feature = "std")]
impl_serde::impl_fixed_hash_serde!(AccountId20, 20);
#[cfg(feature = "std")]
impl std::fmt::Display for AccountId20 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.0)
}
}
impl core::fmt::Debug for AccountId20 {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", H160(self.0))
}
}
impl From<[u8; 20]> for AccountId20 {
fn from(bytes: [u8; 20]) -> Self {
Self(bytes)
}
}
impl Into<[u8; 20]> for AccountId20 {
fn into(self: Self) -> [u8; 20] {
self.0
}
}
impl From<H160> for AccountId20 {
fn from(h160: H160) -> Self {
Self(h160.0)
}
}
impl Into<H160> for AccountId20 {
fn into(self: Self) -> H160 {
H160(self.0)
}
}
#[cfg(feature = "std")]
impl std::str::FromStr for AccountId20 {
type Err = &'static str;
fn from_str(input: &str) -> Result<Self, Self::Err> {
H160::from_str(input)
.map(Into::into)
.map_err(|_| "invalid hex address.")
}
}