1use std::{
2 cmp::Ordering,
3 fmt::{Debug, Display, Formatter},
4 str::FromStr,
5};
6
7use chrono::{DateTime, Utc};
8use sha3::Digest;
9
10use crate::{
11 errors::{
12 GeneralError,
13 GeneralError::{InvalidInput, ParseError},
14 Result,
15 },
16 prelude::BytesRepresentable,
17 traits::{IntoEndian, ToHex, UnitaryFloatOps},
18};
19
20pub type U256 = primitive_types::U256;
21
22#[derive(Clone, Copy, Eq, PartialEq, Default, Hash, PartialOrd, Ord)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25pub struct Address([u8; Self::SIZE]);
26
27impl Debug for Address {
28 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
30 write!(f, "{}", self.to_hex())
31 }
32}
33
34impl Display for Address {
35 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
36 write!(f, "{}", self.to_hex())
37 }
38}
39
40impl Address {
41 pub fn new(bytes: &[u8]) -> Self {
42 assert_eq!(bytes.len(), Self::SIZE, "invalid length");
43 let mut ret = Self::default();
44 ret.0.copy_from_slice(bytes);
45 ret
46 }
47
48 pub fn to_bytes32(&self) -> Box<[u8]> {
49 let mut ret = Vec::with_capacity(12 + Self::SIZE);
50 ret.extend_from_slice(&[0u8; 12]);
51 ret.extend_from_slice(&self.0);
52 ret.into_boxed_slice()
53 }
54
55 pub fn is_zero(&self) -> bool {
57 self.0.iter().all(|e| 0_u8.eq(e))
58 }
59
60 pub fn to_checksum(&self) -> String {
63 let address_hex = hex::encode(self.0);
64
65 let hash = sha3::Keccak256::digest(address_hex.as_bytes());
66
67 let mut ret = String::with_capacity(Self::SIZE * 2 + 2);
68 ret.push_str("0x");
69
70 for (i, c) in address_hex.chars().enumerate() {
71 let nibble = (hash[i / 2] >> (((i + 1) % 2) * 4)) & 0xf;
72 if nibble < 8 {
73 ret.push(c);
74 } else {
75 ret.push(c.to_ascii_uppercase());
76 }
77 }
78 ret
79 }
80}
81
82impl AsRef<[u8]> for Address {
83 fn as_ref(&self) -> &[u8] {
84 &self.0
85 }
86}
87
88impl TryFrom<&[u8]> for Address {
89 type Error = GeneralError;
90
91 fn try_from(value: &[u8]) -> std::result::Result<Self, Self::Error> {
92 Ok(Self(value.try_into().map_err(|_| ParseError("Address".into()))?))
93 }
94}
95
96impl BytesRepresentable for Address {
97 const SIZE: usize = 20;
99}
100
101impl From<[u8; Address::SIZE]> for Address {
102 fn from(value: [u8; Address::SIZE]) -> Self {
103 Self(value)
104 }
105}
106
107impl From<Address> for [u8; Address::SIZE] {
108 fn from(value: Address) -> Self {
109 value.0
110 }
111}
112
113impl From<primitive_types::H160> for Address {
114 fn from(value: primitive_types::H160) -> Self {
115 Self(value.0)
116 }
117}
118
119impl From<Address> for primitive_types::H160 {
120 fn from(value: Address) -> Self {
121 primitive_types::H160::from_slice(&value.0)
122 }
123}
124
125impl FromStr for Address {
126 type Err = GeneralError;
127
128 fn from_str(value: &str) -> Result<Address> {
129 Self::from_hex(value)
130 }
131}
132
133#[derive(Clone, Copy, Eq, PartialEq, Debug, Default)]
137#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
138pub struct EthereumChallenge(pub Address);
139impl AsRef<[u8]> for EthereumChallenge {
140 fn as_ref(&self) -> &[u8] {
141 self.0.as_ref()
142 }
143}
144
145impl TryFrom<&[u8]> for EthereumChallenge {
146 type Error = GeneralError;
147
148 fn try_from(value: &[u8]) -> std::result::Result<Self, Self::Error> {
149 Ok(Self(
150 value.try_into().map_err(|_| ParseError("EthereumChallenge".into()))?,
151 ))
152 }
153}
154
155impl BytesRepresentable for EthereumChallenge {
156 const SIZE: usize = Address::SIZE;
157}
158
159impl IntoEndian<32> for U256 {
160 fn from_be_bytes<T: AsRef<[u8]>>(bytes: T) -> Self {
161 U256::from_big_endian(bytes.as_ref())
162 }
163
164 fn from_le_bytes<T: AsRef<[u8]>>(bytes: T) -> Self {
165 U256::from_little_endian(bytes.as_ref())
166 }
167
168 fn to_le_bytes(self) -> [u8; 32] {
169 self.to_little_endian()
170 }
171
172 fn to_be_bytes(self) -> [u8; 32] {
173 self.to_big_endian()
174 }
175}
176
177impl UnitaryFloatOps for U256 {
178 fn mul_f64(&self, rhs: f64) -> Result<Self> {
179 if !(0.0..=1.0).contains(&rhs) {
180 return Err(InvalidInput);
181 }
182
183 if rhs == 1.0 {
184 Ok(Self(self.0))
186 } else if rhs == 0.0 {
187 Ok(U256::zero())
189 } else {
190 Ok(
191 (*self * U256::from((rhs + 1.0 + f64::EPSILON).to_bits() & 0x000fffffffffffff_u64))
192 >> U256::from(52_u64),
193 )
194 }
195 }
196
197 fn div_f64(&self, rhs: f64) -> Result<Self> {
198 if rhs <= 0.0 || rhs > 1.0 {
199 return Err(InvalidInput);
200 }
201
202 if rhs == 1.0 {
203 Ok(Self(self.0))
204 } else {
205 let nom = *self << U256::from(52_u64);
206 let denom = U256::from((rhs + 1.0).to_bits() & 0x000fffffffffffff_u64);
207
208 Ok(nom / denom)
209 }
210 }
211}
212
213#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
217#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
218pub struct SerializableLog {
219 pub address: Address,
221 pub topics: Vec<[u8; 32]>,
223 pub data: Vec<u8>,
225 pub tx_index: u64,
227 pub block_number: u64,
229 pub block_hash: [u8; 32],
231 pub tx_hash: [u8; 32],
233 pub log_index: u64,
235 pub removed: bool,
237 pub processed: Option<bool>,
239 #[cfg_attr(feature = "serde", serde(with = "chrono::serde::ts_seconds_option"))]
241 pub processed_at: Option<DateTime<Utc>>,
242 pub checksum: Option<String>,
244}
245
246impl Display for SerializableLog {
247 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
248 write!(
249 f,
250 "log #{} in tx #{} in block #{} of address {} with {} topics",
251 self.log_index,
252 self.tx_index,
253 self.block_number,
254 self.address,
255 self.topics.len()
256 )
257 }
258}
259
260impl Ord for SerializableLog {
261 fn cmp(&self, other: &Self) -> Ordering {
262 let block_number_order = self.block_number.cmp(&other.block_number);
263 if block_number_order == Ordering::Equal {
264 let tx_index_order = self.tx_index.cmp(&other.tx_index);
265 if tx_index_order == Ordering::Equal {
266 self.log_index.cmp(&other.log_index)
267 } else {
268 tx_index_order
269 }
270 } else {
271 block_number_order
272 }
273 }
274}
275
276impl PartialOrd<Self> for SerializableLog {
277 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
278 Some(self.cmp(other))
279 }
280}
281
282#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
284#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
285pub struct KeyIdent<const N: usize = 4>(#[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] [u8; N]);
286
287impl<const N: usize> Display for KeyIdent<N> {
288 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
289 write!(f, "{}", self.to_hex())
290 }
291}
292
293impl From<u32> for KeyIdent<4> {
294 fn from(value: u32) -> Self {
295 Self(value.to_be_bytes())
296 }
297}
298
299impl From<KeyIdent<4>> for u32 {
300 fn from(value: KeyIdent<4>) -> Self {
301 u32::from_be_bytes(value.0)
302 }
303}
304
305impl From<u64> for KeyIdent<8> {
306 fn from(value: u64) -> Self {
307 Self(value.to_be_bytes())
308 }
309}
310
311impl From<KeyIdent<8>> for u64 {
312 fn from(value: KeyIdent<8>) -> Self {
313 u64::from_be_bytes(value.0)
314 }
315}
316
317impl<const N: usize> TryFrom<&[u8]> for KeyIdent<N> {
318 type Error = GeneralError;
319
320 fn try_from(value: &[u8]) -> std::result::Result<Self, Self::Error> {
321 Ok(Self(value.try_into().map_err(|_| ParseError("KeyIdent".into()))?))
322 }
323}
324
325impl<const N: usize> AsRef<[u8]> for KeyIdent<N> {
326 fn as_ref(&self) -> &[u8] {
327 &self.0
328 }
329}
330
331impl<const N: usize> Default for KeyIdent<N> {
332 fn default() -> Self {
333 Self([0u8; N])
334 }
335}
336
337impl<const N: usize> BytesRepresentable for KeyIdent<N> {
338 const SIZE: usize = N;
339}
340
341#[cfg(test)]
343mod tests {
344 use std::str::FromStr;
345
346 use hex_literal::hex;
347 use primitive_types::U256;
348
349 use super::*;
350
351 #[test]
352 fn address_tests() -> anyhow::Result<()> {
353 let addr_1 = Address::from(hex!("Cf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9"));
354 let addr_2 = Address::try_from(addr_1.as_ref())?;
355
356 assert_eq!(addr_1, addr_2, "deserialized address does not match");
357 assert_eq!(addr_1, Address::from_str("Cf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9")?);
358
359 assert_eq!(addr_1, Address::from_str("0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9")?);
360
361 assert_eq!(addr_1, Address::from_str(&addr_1.to_hex())?);
362
363 Ok(())
364 }
365
366 #[test]
367 fn eth_challenge_tests() -> anyhow::Result<()> {
368 let e_1 = EthereumChallenge::default();
369 let e_2 = EthereumChallenge::try_from(e_1.as_ref())?;
370
371 assert_eq!(e_1, e_2);
372
373 Ok(())
374 }
375
376 #[test]
377 fn u256_float_multiply() -> anyhow::Result<()> {
378 assert_eq!(U256::one(), U256::one().mul_f64(1.0f64)?);
379 assert_eq!(U256::one(), U256::from(10u64).mul_f64(0.1f64)?);
380
381 assert!(U256::one().mul_f64(-1.0).is_err());
383 assert!(U256::one().mul_f64(1.1).is_err());
384
385 Ok(())
386 }
387
388 #[test]
389 fn u256_float_divide() -> anyhow::Result<()> {
390 assert_eq!(U256::one(), U256::one().div_f64(1.0f64)?);
391
392 assert_eq!(U256::from(2u64), U256::one().div_f64(0.5f64)?);
393 assert_eq!(U256::from(10000u64), U256::one().div_f64(0.0001f64)?);
394
395 assert!(U256::one().div_f64(0.0).is_err());
397 assert!(U256::one().div_f64(1.1).is_err());
398
399 Ok(())
400 }
401
402 #[test]
403 fn u256_endianness() {
404 let num: U256 = 123456789000_u128.into();
405
406 let be_bytes = num.to_be_bytes();
407 let le_bytes = num.to_le_bytes();
408
409 assert_ne!(
410 be_bytes, le_bytes,
411 "sanity check: input number must have different endianness"
412 );
413
414 let expected_be = hex!("0000000000000000000000000000000000000000000000000000001CBE991A08");
415 assert_eq!(expected_be, be_bytes);
416 assert_eq!(U256::from_be_bytes(expected_be), num);
417
418 let expected_le = hex!("081A99BE1C000000000000000000000000000000000000000000000000000000");
419 assert_eq!(expected_le, le_bytes);
420 assert_eq!(U256::from_le_bytes(expected_le), num);
421 }
422
423 #[test]
424 fn address_to_checksum_all_caps() -> anyhow::Result<()> {
425 let addr_1 = Address::from_str("52908400098527886e0f7030069857d2e4169ee7")?;
426 let value_1 = addr_1.to_checksum();
427 let addr_2 = Address::from_str("8617e340b3d01fa5f11f306f4090fd50e238070d")?;
428 let value_2 = addr_2.to_checksum();
429
430 assert_eq!(
431 value_1, "0x52908400098527886E0F7030069857D2E4169EE7",
432 "checksumed address does not match"
433 );
434 assert_eq!(
435 value_2, "0x8617E340B3D01FA5F11F306F4090FD50E238070D",
436 "checksumed address does not match"
437 );
438
439 Ok(())
440 }
441
442 #[test]
443 fn address_to_checksum_all_lower() -> anyhow::Result<()> {
444 let addr_1 = Address::from_str("de709f2102306220921060314715629080e2fb77")?;
445 let value_1 = addr_1.to_checksum();
446 let addr_2 = Address::from_str("27b1fdb04752bbc536007a920d24acb045561c26")?;
447 let value_2 = addr_2.to_checksum();
448
449 assert_eq!(
450 value_1, "0xde709f2102306220921060314715629080e2fb77",
451 "checksumed address does not match"
452 );
453 assert_eq!(
454 value_2, "0x27b1fdb04752bbc536007a920d24acb045561c26",
455 "checksumed address does not match"
456 );
457
458 Ok(())
459 }
460
461 #[test]
462 fn address_to_checksum_all_normal() -> anyhow::Result<()> {
463 let addr_1 = Address::from_str("5aaeb6053f3e94c9b9a09f33669435e7ef1beaed")?;
464 let addr_2 = Address::from_str("fb6916095ca1df60bb79ce92ce3ea74c37c5d359")?;
465 let addr_3 = Address::from_str("dbf03b407c01e7cd3cbea99509d93f8dddc8c6fb")?;
466 let addr_4 = Address::from_str("d1220a0cf47c7b9be7a2e6ba89f429762e7b9adb")?;
467
468 let value_1 = addr_1.to_checksum();
469 let value_2 = addr_2.to_checksum();
470 let value_3 = addr_3.to_checksum();
471 let value_4 = addr_4.to_checksum();
472
473 assert_eq!(
474 value_1, "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
475 "checksumed address does not match"
476 );
477 assert_eq!(
478 value_2, "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359",
479 "checksumed address does not match"
480 );
481 assert_eq!(
482 value_3, "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB",
483 "checksumed address does not match"
484 );
485 assert_eq!(
486 value_4, "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb",
487 "checksumed address does not match"
488 );
489
490 Ok(())
491 }
492}