1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
use crate::error::{Error, Result};
use crate::model::account::PublicKey;
use crate::model::ByteString;
use crate::util::{Base58, Crypto, JsonDeserializer};
use serde_json::Value;
use std::fmt;
use std::hash::Hash;

#[derive(Eq, PartialEq, Clone, Hash)]
pub struct Address {
    bytes: Vec<u8>,
}

impl fmt::Debug for Address {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Address {{ {} }}", self.encoded())
    }
}

impl std::str::FromStr for Address {
    type Err = Error;

    fn from_str(base58string: &str) -> Result<Address> {
        Ok(Address {
            bytes: Base58::decode(base58string)?,
        })
    }
}

impl Address {
    pub fn from_public_key(chain_id: u8, public_key: &PublicKey) -> Result<Address> {
        Ok(Address {
            bytes: Crypto::get_address(
                &chain_id,
                &Crypto::get_public_key_hash(&public_key.bytes())?,
            )?,
        })
    }

    pub fn from_string(address: &str) -> Result<Address> {
        Ok(Address {
            bytes: Base58::decode(address)?,
        })
    }

    pub fn chain_id(&self) -> u8 {
        self.bytes[1]
    }

    pub fn public_key_hash(&self) -> Vec<u8> {
        self.bytes[2..22].to_vec()
    }
}

impl ByteString for Address {
    fn bytes(&self) -> Vec<u8> {
        self.bytes.clone()
    }

    fn encoded(&self) -> String {
        Base58::encode(&self.bytes, false)
    }

    fn encoded_with_prefix(&self) -> String {
        Base58::encode(&self.bytes, true)
    }
}

impl TryFrom<&Value> for Address {
    type Error = Error;

    fn try_from(value: &Value) -> Result<Self> {
        let string = JsonDeserializer::safe_to_string(value)?;
        Address::from_string(&string)
    }
}

#[cfg(test)]
mod tests {
    use crate::error::Result;
    use crate::model::account::{Address, PrivateKey};
    use crate::model::{ByteString, ChainId};
    use serde_json::Value;
    use std::borrow::Borrow;
    use std::str::FromStr;

    #[test]
    fn test_address_from_public_key() {
        let seed_phrase = "blame vacant regret company chase trip grant funny brisk innocent";
        let expected_address = "3Ms87NGAAaPWZux233TB9A3TXps4LDkyJWN";

        let private_key =
            PrivateKey::from_seed(seed_phrase, 0).expect("failed to get private key from seed");
        let public_key = private_key.public_key();
        let address = public_key
            .address(ChainId::TESTNET.byte())
            .expect("failed to get address from public key")
            .encoded();

        assert_eq!(address, expected_address)
    }

    #[test]
    fn test_address_from_string() {
        let expected_address = "3MtQQX9NwYH5URGGcS2e6ptEgV7wTFesaRW";
        let address =
            Address::from_string(expected_address).expect("failed to get address from string");
        assert_eq!(expected_address, address.encoded())
    }

    #[test]
    fn test_address_std_from_str() {
        let expected_address = "3MtQQX9NwYH5URGGcS2e6ptEgV7wTFesaRW";
        let address =
            Address::from_str(expected_address).expect("failed to get address from string");
        assert_eq!(expected_address, address.encoded())
    }

    #[test]
    fn test_address_from_json() -> Result<()> {
        let expected_address = "3MtQQX9NwYH5URGGcS2e6ptEgV7wTFesaRW";
        let address: Address = Value::String("3MtQQX9NwYH5URGGcS2e6ptEgV7wTFesaRW".to_owned())
            .borrow()
            .try_into()?;
        assert_eq!(expected_address, address.encoded());
        Ok(())
    }

    #[test]
    fn test_byte_string_for_address() -> Result<()> {
        let address = Address::from_string("3MtQQX9NwYH5URGGcS2e6ptEgV7wTFesaRW")?;
        let expected_bytes: Vec<u8> = vec![
            1, 84, 49, 59, 204, 61, 157, 141, 148, 218, 122, 51, 43, 12, 171, 81, 190, 13, 80, 46,
            88, 199, 218, 79, 208, 145,
        ];
        let expected_encoded = "3MtQQX9NwYH5URGGcS2e6ptEgV7wTFesaRW";
        let expected_encoded_with_prefix = "base58:3MtQQX9NwYH5URGGcS2e6ptEgV7wTFesaRW";
        assert_eq!(expected_bytes, address.bytes());
        assert_eq!(expected_encoded, address.encoded());
        assert_eq!(expected_encoded_with_prefix, address.encoded_with_prefix());
        Ok(())
    }
}