ethers_types_rs/
address.rs1use ethers_hash_rs::keccak256;
2use hex::FromHexError;
3
4use ethabi::ethereum_types::Address;
5
6use crate::bytes::bytes_to_string;
7
8#[derive(Debug, Clone, thiserror::Error)]
9pub enum AddressError {
10 #[error("Convert address from str error,{0}")]
11 HexFormat(FromHexError),
12
13 #[error("Convert bytes to compressed public key error, {0}")]
14 CompressedPubKey(String),
15
16 #[error("Address public key len either 33 or 65")]
17 InvalidPubKeyLength,
18
19 #[error("Address checksum mismatch")]
20 AddressChecksum,
21}
22
23pub trait AddressEx {
25 fn from_pub_key<K>(key: K) -> anyhow::Result<Address>
27 where
28 K: TryInto<[u8; 65]>,
29 K::Error: std::error::Error + Send + Sync + 'static,
30 {
31 let key = key.try_into()?;
32
33 let buf: [u8; 20] = keccak256(&key[1..])[12..]
34 .try_into()
35 .expect("To address array");
36
37 Ok(buf.into())
38 }
39
40 #[cfg(feature = "rust_crypto")]
42 fn from_pub_key_compressed<K>(key: K) -> anyhow::Result<Address>
43 where
44 K: TryInto<[u8; 33]>,
45 K::Error: std::error::Error + Send + Sync + 'static,
46 {
47 let key = key.try_into()?;
48
49 let key = k256::EncodedPoint::from_bytes(&key)
50 .map_err(|err| AddressError::CompressedPubKey(err.to_string()))?;
51
52 let key = k256::ecdsa::VerifyingKey::from_encoded_point(&key)?;
53
54 Self::from_pub_key(key.to_encoded_point(false).as_bytes())
55 }
56
57 fn from_any_pub_key<S>(key: S) -> anyhow::Result<Address>
59 where
60 S: AsRef<[u8]>,
61 {
62 let key = key.as_ref();
63
64 match key.len() {
65 33 => Self::from_pub_key_compressed(key),
66 65 => Self::from_pub_key(key),
67 _ => Err(AddressError::InvalidPubKeyLength.into()),
68 }
69 }
70
71 #[cfg(feature = "rust_crypto")]
73 fn from_private_key(key: &[u8]) -> anyhow::Result<Address> {
74 let pk = k256::ecdsa::SigningKey::from_bytes(key)?;
75
76 Self::from_pub_key(pk.verifying_key().to_encoded_point(false).as_bytes())
77 }
78}
79
80impl AddressEx for Address {}
81
82pub trait Eip55: Sized {
83 fn to_checksum_string(&self) -> String;
84
85 fn from_checksum_string(source: &str) -> anyhow::Result<Self>;
86}
87
88impl Eip55 for Address {
89 fn to_checksum_string(&self) -> String {
90 let mut data = bytes_to_string(self.as_bytes());
91
92 let digest = keccak256(&data.as_bytes()[2..]);
93
94 let addr = unsafe { &mut data.as_bytes_mut()[2..] };
95
96 for i in 0..addr.len() {
97 let byte = digest[i / 2];
98 let nibble = 0xf & if i % 2 == 0 { byte >> 4 } else { byte };
99 if nibble >= 8 {
100 addr[i] = addr[i].to_ascii_uppercase();
101 }
102 }
103
104 data
105 }
106
107 fn from_checksum_string(source: &str) -> anyhow::Result<Self> {
108 let address: Address = Self::try_from(source)?;
109
110 let expected = address.to_checksum_string();
111
112 if expected != source {
113 return Err(AddressError::AddressChecksum.into());
114 }
115
116 Ok(address)
117 }
118}