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}