1use basex_rs::{BaseX, Decode, Encode, BITCOIN};
18use bitcoin_hashes::sha256;
19use bitcoin_hashes::Hash;
20use hex;
21
22pub enum QtumNetwork {
24 Mainnet,
26 Testnet,
28}
29
30impl QtumNetwork {
31 pub fn to_prefix_byte(&self) -> u8 {
33 match self {
34 QtumNetwork::Mainnet => 0x3a,
35 QtumNetwork::Testnet => 0x78,
36 }
37 }
38}
39
40impl From<u8> for QtumNetwork {
41 fn from(item: u8) -> Self {
42 match item {
43 0x3a => QtumNetwork::Mainnet,
44 0x78 => QtumNetwork::Testnet,
45 _ => panic!(""),
46 }
47 }
48}
49
50pub struct QtumAddress {
52 prefix: u8,
53}
54
55impl QtumAddress {
56 pub fn new(network: QtumNetwork) -> Self {
58 Self {
59 prefix: network.to_prefix_byte(),
60 }
61 }
62
63 pub fn gethexaddress(&self, address: &str) -> Result<String, &str> {
65 if address.is_empty() {
66 return Err("Invalid address");
67 }
68
69 let decode_bytes = match BaseX::new(BITCOIN).decode(address.to_string()) {
70 Some(bytes) => bytes,
71 None => return Err("Invalid address"),
72 };
73
74 let new_bytes = match decode_bytes.get(1..21) {
75 Some(hash) => hash,
76 None => return Err("Invalid address"),
77 };
78
79 let hex = hex::encode(new_bytes);
80
81 Ok(hex)
82 }
83
84 pub fn fromhexaddress(&self, address: &str) -> Result<String, &str> {
86 if address.is_empty() || address.len() != 40 {
87 return Err("Invalid address");
88 }
89
90 let mut address_bytes = match hex::decode(address) {
91 Ok(bytes) => bytes,
92 Err(_) => return Err("Invalid address"),
93 };
94 address_bytes.insert(0, self.prefix);
95
96 let checksum = self.hash(&self.hash(&address_bytes));
97 match checksum.get(0..4) {
98 Some(hash) => {
99 for byte in hash.iter() {
100 address_bytes.push(*byte);
101 }
102 }
103 None => return Err("Invalid address"),
104 };
105
106 let encode = BaseX::new(BITCOIN).encode(&address_bytes);
107
108 Ok(encode)
109 }
110
111 pub fn addprefix(address: &str) -> String {
113 format!("0x{}", address)
114 }
115
116 fn hash(&self, byte: &Vec<u8>) -> Vec<u8> {
118 hex::decode(sha256::Hash::hash(byte.as_slice()).to_string()).unwrap()
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 #[test]
127 fn it_works_testnet() {
128 let eth_addresses = [
129 "6c89a1a6ca2ae7c00b248bb2832d6f480f27da68",
130 "49a80104c0d27a9ba29678d07e87a57151107613",
131 "7926223070547d2d15b2ef5e7383e541c338ffe9",
132 "2352be3db3177f0a07efbe6da5857615b8c9901d",
133 "69b004ac2b3993bf2fdf56b02746a1f57997420d",
134 "8c647515f03daeefd09872d7530fa8d8450f069a",
135 "2191744eb5ebeac90e523a817b77a83a0058003b",
136 "88b0bf4b301c21f8a47be2188bad6467ad556dcf",
137 ];
138
139 let qtum_addresses = [
140 "qTTH1Yr2eKCuDLqfxUyBLCAjmomQ8pyrBt",
141 "qQGqkA16ZY6bCYy7Qjr77eU4BPsdadibCG",
142 "qUbxboqjBRp96j3La8D1RYkyqx5uQbJPoW",
143 "qLn9vqbr2Gx3TsVR9QyTVB5mrMoh4x43Uf",
144 "qTCCy8qy7pW94EApdoBjYc1vQ2w68UnXPi",
145 "qWMi6ne9mDQFatRGejxdDYVUV9rQVkAFGp",
146 "qLcshhsRS6HKeTKRYFdpXnGVZxw96QQcfm",
147 "qW28njWueNpBXYWj2KDmtFG2gbLeALeHfV",
148 ];
149
150 let qtum = QtumAddress::new(QtumNetwork::Testnet);
151
152 for addr in qtum_addresses.iter() {
153 let eth_addr = qtum.gethexaddress(addr).unwrap();
154 let qtum_addr = qtum.fromhexaddress(ð_addr).unwrap();
155 assert_eq!(qtum_addr.to_string(), addr.to_string());
156 }
157
158 for addr in eth_addresses.iter() {
159 let qtum_addr = qtum.fromhexaddress(addr).unwrap();
160 let eth_addr = qtum.gethexaddress(&qtum_addr).unwrap();
161 assert_eq!(eth_addr.to_string(), addr.to_string());
162 }
163 }
164}