use crate::{format, AsBytes, String, H160};
use borsh::{io, BorshDeserialize, BorshSerialize};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub struct Address(H160);
impl Address {
#[must_use]
pub const fn new(val: H160) -> Self {
Self(val)
}
#[must_use]
pub const fn raw(&self) -> H160 {
self.0
}
#[must_use]
pub fn encode(&self) -> String {
hex::encode(self.0.as_bytes())
}
pub fn decode(address: &str) -> Result<Self, error::AddressError> {
if address.len() != 40 {
return Err(error::AddressError::IncorrectLength);
}
let mut result = [0u8; 20];
hex::decode_to_slice(address, &mut result)
.map_err(|_| error::AddressError::FailedDecodeHex)?;
Ok(Self::new(H160(result)))
}
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
self.0.as_bytes()
}
pub fn try_from_slice(raw_addr: &[u8]) -> Result<Self, error::AddressError> {
if raw_addr.len() != 20 {
return Err(error::AddressError::IncorrectLength);
}
Ok(Self::new(H160::from_slice(raw_addr)))
}
#[must_use]
pub const fn from_array(array: [u8; 20]) -> Self {
Self(H160(array))
}
#[must_use]
pub const fn zero() -> Self {
Self::new(H160([0u8; 20]))
}
}
impl TryFrom<&[u8]> for Address {
type Error = error::AddressError;
fn try_from(raw_addr: &[u8]) -> Result<Self, Self::Error> {
Self::try_from_slice(raw_addr).map_err(|_| error::AddressError::IncorrectLength)
}
}
impl AsBytes for Address {
fn as_bytes(&self) -> &[u8] {
self.as_bytes()
}
}
impl BorshSerialize for Address {
fn serialize<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
writer.write_all(self.0.as_bytes())
}
}
impl BorshDeserialize for Address {
fn deserialize_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
let mut buf = [0u8; 20];
let maybe_read = reader.read_exact(&mut buf);
if maybe_read.as_ref().err().map(io::Error::kind) == Some(io::ErrorKind::UnexpectedEof) {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("{}", error::AddressError::IncorrectLength),
));
}
maybe_read?;
let address = Self(H160(buf));
Ok(address)
}
}
impl Default for Address {
fn default() -> Self {
Self::zero()
}
}
#[must_use]
pub const fn make_address(x: u32, y: u128) -> Address {
let x_bytes = x.to_be_bytes();
let y_bytes = y.to_be_bytes();
Address::new(H160([
x_bytes[0],
x_bytes[1],
x_bytes[2],
x_bytes[3],
y_bytes[0],
y_bytes[1],
y_bytes[2],
y_bytes[3],
y_bytes[4],
y_bytes[5],
y_bytes[6],
y_bytes[7],
y_bytes[8],
y_bytes[9],
y_bytes[10],
y_bytes[11],
y_bytes[12],
y_bytes[13],
y_bytes[14],
y_bytes[15],
]))
}
pub mod error {
use crate::{fmt, String};
#[derive(Eq, Hash, Clone, Debug, PartialEq)]
pub enum AddressError {
FailedDecodeHex,
IncorrectLength,
}
impl AsRef<[u8]> for AddressError {
fn as_ref(&self) -> &[u8] {
match self {
Self::FailedDecodeHex => b"FAILED_DECODE_ETH_ADDRESS",
Self::IncorrectLength => b"ETH_WRONG_ADDRESS_LENGTH",
}
}
}
impl fmt::Display for AddressError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let msg = String::from_utf8(self.as_ref().to_vec()).unwrap();
write!(f, "{msg}")
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use rand::Rng;
const fn u8_to_address(x: u8) -> Address {
let mut bytes = [0u8; 20];
bytes[19] = x;
Address::new(H160(bytes))
}
fn split_address(a: Address) -> (u32, u128) {
let mut x_bytes = [0u8; 4];
let mut y_bytes = [0u8; 16];
x_bytes.copy_from_slice(&a.raw()[0..4]);
y_bytes.copy_from_slice(&a.raw()[4..20]);
(u32::from_be_bytes(x_bytes), u128::from_be_bytes(y_bytes))
}
#[test]
fn test_address_serializer() {
let eth_address = "096DE9C2B8A5B8c22cEe3289B101f6960d68E51E";
let serialized_addr = borsh::to_vec(&Address::new(H160::from_slice(
&hex::decode(eth_address).unwrap()[..],
)))
.unwrap();
assert_eq!(serialized_addr.len(), 20);
let addr = Address::try_from_slice(&serialized_addr).unwrap();
assert_eq!(
addr.encode(),
"096DE9C2B8A5B8c22cEe3289B101f6960d68E51E".to_lowercase()
);
}
#[test]
fn test_address_decode() {
let eth_address_vec = hex::decode("096DE9C2B8A5B8c22cEe3289B101f6960d68E51E").unwrap();
let mut eth_address = [0u8; 20];
eth_address.copy_from_slice(ð_address_vec[..]);
let aurora_eth_address =
Address::decode("096DE9C2B8A5B8c22cEe3289B101f6960d68E51E").unwrap();
assert_eq!(eth_address, aurora_eth_address.as_bytes());
let serialized_addr = borsh::to_vec(ð_address).unwrap();
let aurora_serialized_addr = borsh::to_vec(&aurora_eth_address).unwrap();
assert_eq!(serialized_addr.len(), 20);
assert_eq!(aurora_serialized_addr.len(), 20);
assert_eq!(serialized_addr, aurora_serialized_addr);
let addr = Address::try_from_slice(&serialized_addr).unwrap();
assert_eq!(
addr.encode(),
"096DE9C2B8A5B8c22cEe3289B101f6960d68E51E".to_lowercase()
);
}
#[test]
fn test_wrong_address_19() {
let serialized_addr = [0u8; 19];
let addr = Address::try_from_slice(&serialized_addr);
let err = addr.unwrap_err();
matches!(err, error::AddressError::IncorrectLength);
}
#[test]
fn test_make_address() {
for i in 0..u8::MAX {
assert_eq!(make_address(0, i.into()), u8_to_address(i));
}
let mut rng = rand::thread_rng();
for _ in 0..u8::MAX {
let address = Address::new(H160(rng.gen()));
let (x, y) = split_address(address);
assert_eq!(address, make_address(x, y));
}
}
}