#![cfg_attr(not(feature = "std"), no_std)]
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_core::{ecdsa, RuntimeDebug, H160, H256};
use sp_io::hashing::keccak_256;
use sp_runtime_interface::pass_by::PassByInner;
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Hash)]
#[derive(Encode, Decode, MaxEncodedLen, TypeInfo)]
pub struct AccountId20(pub [u8; 20]);
#[cfg(feature = "serde")]
impl_serde::impl_fixed_hash_serde!(AccountId20, 20);
#[cfg(feature = "std")]
impl std::str::FromStr for AccountId20 {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
H160::from_str(s)
.map(Into::into)
.map_err(|_| "invalid hex address.")
}
}
#[cfg(feature = "std")]
impl std::fmt::Display for AccountId20 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let address = hex::encode(self.0).trim_start_matches("0x").to_lowercase();
let address_hash = hex::encode(keccak_256(address.as_bytes()));
let checksum: String =
address
.char_indices()
.fold(String::from("0x"), |mut acc, (index, address_char)| {
let n = u16::from_str_radix(&address_hash[index..index.saturating_add(1)], 16)
.expect("Keccak256 hashed; qed");
if n > 7 {
acc.push_str(&address_char.to_uppercase().to_string())
} else {
acc.push(address_char)
}
acc
});
write!(f, "{checksum}")
}
}
impl sp_std::fmt::Debug for AccountId20 {
fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result {
write!(f, "{:?}", H160(self.0))
}
}
impl From<[u8; 20]> for AccountId20 {
fn from(bytes: [u8; 20]) -> Self {
Self(bytes)
}
}
impl<'a> TryFrom<&'a [u8]> for AccountId20 {
type Error = ();
fn try_from(x: &'a [u8]) -> Result<AccountId20, ()> {
if x.len() == 20 {
let mut data = [0; 20];
data.copy_from_slice(x);
Ok(AccountId20(data))
} else {
Err(())
}
}
}
impl From<AccountId20> for [u8; 20] {
fn from(val: AccountId20) -> Self {
val.0
}
}
impl From<H160> for AccountId20 {
fn from(h160: H160) -> Self {
Self(h160.0)
}
}
impl From<AccountId20> for H160 {
fn from(val: AccountId20) -> Self {
H160(val.0)
}
}
impl AsRef<[u8]> for AccountId20 {
fn as_ref(&self) -> &[u8] {
&self.0[..]
}
}
impl AsMut<[u8]> for AccountId20 {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0[..]
}
}
impl AsRef<[u8; 20]> for AccountId20 {
fn as_ref(&self) -> &[u8; 20] {
&self.0
}
}
impl AsMut<[u8; 20]> for AccountId20 {
fn as_mut(&mut self) -> &mut [u8; 20] {
&mut self.0
}
}
impl From<sp_std::vec::Vec<u8>> for AccountId20 {
fn from(bytes: sp_std::vec::Vec<u8>) -> Self {
if bytes.len() == 20 {
let mut data = [0; 20];
data.copy_from_slice(&bytes);
AccountId20(data)
} else if bytes.len() == 22 {
assert!(bytes.starts_with(b"0x"), "Invalid Prefix");
let mut data = [0; 20];
data.copy_from_slice(&bytes[2..]);
AccountId20(data)
} else {
panic!("Invalid length for AccountId20 bytes");
}
}
}
impl From<ecdsa::Public> for AccountId20 {
fn from(pk: ecdsa::Public) -> Self {
let decompressed = libsecp256k1::PublicKey::parse_compressed(&pk.0)
.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(keccak_256(&m)));
Self(account.into())
}
}
#[derive(Eq, PartialEq, Clone, RuntimeDebug, Encode, Decode, TypeInfo)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EthereumSignature(ecdsa::Signature);
impl sp_runtime::traits::Verify for EthereumSignature {
type Signer = EthereumSigner;
fn verify<L: sp_runtime::traits::Lazy<[u8]>>(&self, mut msg: L, signer: &AccountId20) -> bool {
let m = keccak_256(msg.get());
match sp_io::crypto::secp256k1_ecdsa_recover(self.0.as_ref(), &m) {
Ok(pubkey) => AccountId20(H160::from(H256::from(keccak_256(&pubkey))).0) == *signer,
Err(sp_io::EcdsaVerifyError::BadRS) => {
log::error!(target: "evm", "Error recovering: Incorrect value of R or S");
false
}
Err(sp_io::EcdsaVerifyError::BadV) => {
log::error!(target: "evm", "Error recovering: Incorrect value of V");
false
}
Err(sp_io::EcdsaVerifyError::BadSignature) => {
log::error!(target: "evm", "Error recovering: Invalid signature");
false
}
}
}
}
impl EthereumSignature {
pub fn new(s: ecdsa::Signature) -> Self {
EthereumSignature(s)
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[derive(RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo, PassByInner)]
pub struct EthereumSigner([u8; 20]);
impl From<[u8; 20]> for EthereumSigner {
fn from(x: [u8; 20]) -> Self {
EthereumSigner(x)
}
}
impl sp_runtime::traits::IdentifyAccount for EthereumSigner {
type AccountId = AccountId20;
fn into_account(self) -> AccountId20 {
AccountId20(self.0)
}
}
#[cfg(feature = "std")]
impl std::fmt::Display for EthereumSigner {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "{:?}", H160::from(self.0))
}
}
impl From<ecdsa::Public> for EthereumSigner {
fn from(pk: ecdsa::Public) -> Self {
let decompressed = libsecp256k1::PublicKey::parse_compressed(&pk.0)
.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(keccak_256(&m)));
EthereumSigner(account.into())
}
}