thor_devkit/
address.rs

1//! VeChain address operations and verifications.
2
3use crate::rlp::{Decodable, Encodable, RLPError};
4use crate::utils::keccak;
5use ethereum_types::Address as WrappedAddress;
6pub use secp256k1::{PublicKey, SecretKey as PrivateKey};
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9use std::{
10    ops::{Deref, DerefMut},
11    str::FromStr,
12};
13
14#[cfg_attr(feature = "serde", serde_with::serde_as)]
15#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
16#[cfg_attr(feature = "serde", serde(remote = "ethereum_types::H160"))]
17struct _Address(#[cfg_attr(feature = "serde", serde_as(as = "crate::utils::unhex::Hex"))] [u8; 20]);
18
19/// VeChain address.
20#[cfg_attr(feature = "serde", serde_with::serde_as)]
21#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
22#[derive(Copy, Clone, Debug, PartialEq, Eq)]
23pub struct Address(#[cfg_attr(feature = "serde", serde_as(as = "_Address"))] WrappedAddress);
24
25impl DerefMut for Address {
26    fn deref_mut(&mut self) -> &mut WrappedAddress {
27        &mut self.0
28    }
29}
30impl Deref for Address {
31    type Target = WrappedAddress;
32
33    fn deref(&self) -> &Self::Target {
34        &self.0
35    }
36}
37impl Encodable for Address {
38    fn encode(&self, out: &mut dyn bytes::BufMut) {
39        self.0.encode(out)
40    }
41}
42impl Decodable for Address {
43    fn decode(buf: &mut &[u8]) -> Result<Self, RLPError> {
44        Ok(Self(WrappedAddress::decode(buf)?))
45    }
46}
47impl FromStr for Address {
48    type Err = rustc_hex::FromHexError;
49
50    fn from_str(s: &str) -> Result<Self, Self::Err> {
51        Ok(Self(WrappedAddress::from_str(s)?))
52    }
53}
54impl<T: Into<WrappedAddress>> From<T> for Address {
55    fn from(s: T) -> Self {
56        Self(s.into())
57    }
58}
59
60impl Address {
61    /// Size of underlying array in bytes.
62    pub const WIDTH: usize = 20;
63
64    pub fn to_hex(&self) -> String {
65        //! Encode as a hex string with `0x` prefix.
66        format!("{:02x?}", self.0)
67    }
68
69    pub fn to_checksum_address(&self) -> String {
70        //! Create a checksum address
71
72        let body = self.to_hex();
73        let hash = keccak(&body.clone()[2..42]);
74
75        "0x".chars()
76            .chain(
77                body.chars()
78                    .skip(2)
79                    .zip(itertools::interleave(
80                        hash.iter().map(|x| x >> 4),
81                        hash.iter().map(|x| x & 15),
82                    ))
83                    .map(|(ch, h)| if h >= 8 { ch.to_ascii_uppercase() } else { ch }),
84            )
85            .collect()
86    }
87}
88
89/// A trait for objects that can generate an on-chain address.
90pub trait AddressConvertible {
91    /// Create an address
92    fn address(&self) -> Address;
93}
94
95impl AddressConvertible for secp256k1::PublicKey {
96    fn address(&self) -> Address {
97        //! Generate address from public key.
98        // Get rid of the 0x04 (first byte) at the beginning.
99        let hash = keccak(&self.serialize_uncompressed()[1..]);
100        // last 20 bytes from the 32 bytes hash.
101        let suffix: [u8; 20] = hash[12..32].try_into().expect("Preset slice length");
102        Address(WrappedAddress::from_slice(&suffix))
103    }
104}