neo3/neo_types/
string.rs

1use bs58;
2use hex;
3use sha2::{Digest, Sha256};
4
5use neo3::prelude::ScriptHash;
6
7pub trait StringExt {
8	fn bytes_from_hex(&self) -> Result<Vec<u8>, hex::FromHexError>;
9
10	fn base64_decoded(&self) -> Result<Vec<u8>, base64::DecodeError>;
11
12	fn base64_encoded(&self) -> String;
13
14	fn base58_decoded(&self) -> Option<Vec<u8>>;
15
16	fn base58_check_decoded(&self) -> Option<Vec<u8>>;
17
18	fn base58_encoded(&self) -> String;
19
20	fn var_size(&self) -> usize;
21
22	fn is_valid_address(&self) -> bool;
23
24	fn is_valid_hex(&self) -> bool;
25
26	fn address_to_scripthash(&self) -> Result<ScriptHash, &'static str>;
27
28	fn reversed_hex(&self) -> String;
29}
30
31impl StringExt for String {
32	fn bytes_from_hex(&self) -> Result<Vec<u8>, hex::FromHexError> {
33		hex::decode(self.trim_start_matches("0x"))
34	}
35
36	fn base64_decoded(&self) -> Result<Vec<u8>, base64::DecodeError> {
37		base64::decode(self)
38	}
39
40	fn base64_encoded(&self) -> String {
41		base64::encode(self.as_bytes())
42	}
43
44	fn base58_decoded(&self) -> Option<Vec<u8>> {
45		bs58::decode(self).into_vec().ok()
46	}
47
48	fn base58_check_decoded(&self) -> Option<Vec<u8>> {
49		bs58::decode(self).into_vec().ok()
50	}
51
52	fn base58_encoded(&self) -> String {
53		bs58::encode(self.as_bytes()).into_string()
54	}
55
56	fn var_size(&self) -> usize {
57		let bytes = self.as_bytes();
58		let len = bytes.len();
59		if len < 0xFD {
60			1
61		} else if len <= 0xFFFF {
62			3
63		} else if len <= 0xFFFFFFFF {
64			5
65		} else {
66			9
67		}
68	}
69
70	fn is_valid_address(&self) -> bool {
71		if let Some(data) = self.base58_decoded() {
72			if data.len() == 25 && data[0] == 0x17 {
73				let checksum = &Sha256::digest(&Sha256::digest(&data[..21]))[..4];
74				checksum == &data[21..]
75			} else {
76				false
77			}
78		} else {
79			false
80		}
81	}
82
83	fn is_valid_hex(&self) -> bool {
84		self.len() % 2 == 0 && self.chars().all(|c| c.is_ascii_hexdigit())
85	}
86
87	fn address_to_scripthash(&self) -> Result<ScriptHash, &'static str> {
88		if self.is_valid_address() {
89			let data = self.base58_decoded().ok_or("Invalid address").unwrap();
90			let mut scripthash = data[1..21].to_vec();
91			scripthash.reverse();
92			Ok(ScriptHash::from_slice(&scripthash))
93		} else {
94			Err("Not a valid address")
95		}
96	}
97
98	fn reversed_hex(&self) -> String {
99		let mut bytes = self.bytes_from_hex().unwrap();
100		bytes.reverse();
101		hex::encode(bytes)
102	}
103}