use std::{fmt, str::FromStr};
use tiny_keccak::Hasher;
use crate::keys::PublicKey;
use super::Error;
#[derive(Clone, PartialEq, Eq)]
pub struct Address([u8; 20]);
impl Address {
pub fn new(addr: [u8; 20]) -> Self {
Address(addr)
}
pub fn from_slice(addr: &[u8]) -> Result<Self, Error> {
if addr.len() != 20 {
return Err(Error::InvalidAddress);
}
let mut a = [0u8; 20];
a.copy_from_slice(addr);
Ok(Address(a))
}
pub fn from_public(pubkey: &PublicKey) -> Self {
let pk_bytes = pubkey.to_bytes_uncompressed();
let mut buf = [0u8; 32];
let mut hasher = tiny_keccak::Keccak::v256();
hasher.update(&pk_bytes[1..]);
hasher.finalize(&mut buf);
let mut addr = [0u8; 20];
addr.copy_from_slice(&buf[12..]);
Address(addr)
}
pub fn to_hex(&self) -> String {
let hex_addr = hex::encode(&self.0);
let mut hasher = tiny_keccak::Keccak::v256();
hasher.update(hex_addr.as_bytes());
let mut buf = [0u8; 32];
hasher.finalize(&mut buf);
let addr_hash = hex::encode(&buf);
hex_addr
.char_indices()
.fold(String::from("0x"), |mut x, (i, c)| {
let n = u16::from_str_radix(&addr_hash[i..i + 1], 16).unwrap();
if n > 7 {
x.push(c.to_ascii_uppercase());
} else {
x.push(c);
}
x
})
}
pub fn as_str(&self) -> &'static str {
let string = self.to_hex();
Box::leak(string.into_boxed_str())
}
pub fn to_bytes(&self) -> [u8; 20] {
self.0
}
}
impl fmt::Display for Address {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.to_hex())
}
}
impl fmt::Debug for Address {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "0x{}", hex::encode(&self.0))
}
}
impl fmt::UpperHex for Address {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "0x{}", hex::encode_upper(&self.0))
}
}
impl fmt::LowerHex for Address {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "0x{}", hex::encode(&self.0))
}
}
impl From<[u8; 20]> for Address {
fn from(addr: [u8; 20]) -> Self {
Address(addr)
}
}
impl FromStr for Address {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.trim_start_matches("0x");
let addr = hex::decode(s).map_err(|_| Error::InvalidAddress)?;
Address::from_slice(&addr)
}
}