redgold_schema/
address.rs1use itertools::Itertools;
2use crate::structs::{Address, AddressDescriptor, AddressInfo, AddressType, ErrorInfo, Hash, OutputContract, PublicKey, SupportedCurrency, UtxoEntry, Weighting};
3use crate::{bytes_data, error_info, from_hex, ErrorInfoContext, RgResult, SafeOption};
4use crate::structs;
5use sha3::Sha3_224;
6
7use crate::proto_serde::ProtoSerde;
8use crate::structs::SupportedCurrency::Redgold;
9use sha3::Digest;
10
11impl Into<Address> for structs::PublicKey {
13 fn into(self) -> Address {
14 Address::from_struct_public(&self).expect("some")
15 }
16}
17
18impl Into<Address> for Vec<u8> {
19 fn into(self) -> Address {
20 Address::address_data(self).expect("some")
21 }
22}
23
24
25impl AddressDescriptor {
26 pub fn from_multisig_public_keys_and_threshold(public_keys: &Vec<PublicKey>, threshold: i64) -> AddressDescriptor {
27 let mut pks = public_keys.clone();
28 pks.sort_by_key(|k| k.vec());
29 let mut descriptor = AddressDescriptor::default();
30 descriptor.public_keys = pks.clone();
31 let mut contract = OutputContract::default();
32 contract.threshold = Some(Weighting::from_int_basis(threshold, pks.len() as i64));
33 descriptor.contract = Some(contract);
34 descriptor
35 }
36
37 pub fn to_address(&self) -> Address {
38 Address::from_multisig_public_keys_and_threshold(
39 &self.public_keys, self.contract.as_ref().unwrap().threshold.as_ref().unwrap().value
40 )
41 }
42}
43
44
45impl Address {
46
47 pub fn from_multisig_public_keys_and_threshold(public_keys: &Vec<PublicKey>, threshold: i64) -> Address {
48 let descriptor = AddressDescriptor::from_multisig_public_keys_and_threshold(public_keys, threshold);
49 let bytes = descriptor.to_hashed().bytes;
50
51 Self {
52 address: bytes,
53 address_type: AddressType::MultisigContract as i32,
54 currency: Redgold as i32,
55 }
56 }
57
58 pub fn mark_bitcoin_external(&mut self) -> &mut Self {
59 self.currency = SupportedCurrency::Bitcoin as i32;
60 self
61 }
62
63 pub fn mark_ethereum_external(&mut self) -> &mut Self {
64 self.currency = SupportedCurrency::Ethereum as i32;
65 self
66 }
67
68 pub fn mark_external(&mut self) -> &mut Self {
69 match self.address_type() {
70 AddressType::BitcoinExternalString => self.mark_bitcoin_external(),
71 AddressType::EthereumExternalString => self.mark_ethereum_external(),
72 AddressType::SolanaExternalString => {
73 self.set_currency(SupportedCurrency::Solana);
74 self
75 },
76 AddressType::MoneroExternalString => {
77 self.set_currency(SupportedCurrency::Monero);
78 self
79 },
80 _ => self
81 }
82 }
83
84 pub fn as_external(&self) -> Address {
85 let mut address = self.clone();
86 address.mark_external();
87 address.clone()
88 }
89
90 pub fn as_internal(&self) -> Address {
91 let mut address = self.clone();
92 address.set_currency(Redgold);
93 address
94 }
95
96 pub fn script_hash(input: impl AsRef<[u8]>) -> RgResult<Self> {
97 let mut new = Self::from_bytes(Self::hash(input.as_ref()))?;
98 new.address_type = AddressType::ScriptHash as i32;
99 Ok(new)
100 }
101
102 pub fn from_bitcoin_external(address: &String) -> Address {
103 let mut ret = Self::from_bitcoin(address);
104 ret.currency = SupportedCurrency::Bitcoin as i32;
105 ret
106 }
107
108 pub fn from_bitcoin(address: &String) -> Address {
112 Self {
113 address: bytes_data(address.clone().into_bytes()),
114 address_type: AddressType::BitcoinExternalString as i32,
115 currency: Redgold as i32,
117 }
118 }
119 pub fn from_eth_direct(address: impl Into<String>) -> Address {
120 let address = address.into();
121 Self {
122 address: bytes_data(address.clone().into_bytes()),
123 address_type: AddressType::EthereumExternalString as i32,
124 currency: Redgold as i32,
125 }
126 }
127
128 pub fn from_monero(address: &String) -> Address {
129 Self {
130 address: bytes_data(address.clone().into_bytes()),
131 address_type: AddressType::MoneroExternalString as i32,
132 currency: Redgold as i32,
133 }
134 }
135 pub fn from_solana(address: &String) -> Address {
136 Self {
137 address: bytes_data(address.clone().into_bytes()),
138 address_type: AddressType::SolanaExternalString as i32,
139 currency: Redgold as i32,
140 }
141 }
142
143 pub fn from_type(address: &String, t: AddressType) -> Address {
144 Self {
145 address: bytes_data(address.clone().into_bytes()),
146 address_type: t as i32,
147 currency: Redgold as i32,
148 }
149 }
150
151 pub fn from_monero_external(address: impl AsRef<str>) -> Address {
152 let address = address.as_ref().to_string();
153 let mut ret = Self::from_monero(&address);
154 ret.currency = SupportedCurrency::Monero as i32;
155 ret
156 }
157
158 pub fn from_solana_external(address: &String) -> Address {
159 let mut ret = Self::from_monero(address);
160 ret.currency = SupportedCurrency::Solana as i32;
161 ret
162 }
163
164 pub fn from_eth_external_exact(address: impl Into<String>) -> Address {
165 let address = address.into();
166 let mut ret = Self::from_eth_direct(address);
167 ret.currency = SupportedCurrency::Ethereum as i32;
168 ret
169 }
170
171 pub fn is_bitcoin(&self) -> bool {
172 self.address_type == AddressType::BitcoinExternalString as i32
173 }
174
175 pub fn address_typed(&self) -> RgResult<AddressType> {
176 AddressType::from_i32(self.address_type).ok_msg("Invalid address type")
177 }
178
179 pub fn raw_bytes(&self) -> RgResult<Vec<u8>> {
180 Ok(self.address.safe_get()?.value.clone())
181 }
182
183 pub fn external_string_address(&self) -> RgResult<String> {
184 String::from_utf8(self.raw_bytes()?)
185 .error_info("Unable to convert bitcoin address bytes to utf8 string")
186 }
187
188 pub fn render_string(&self) -> Result<String, ErrorInfo> {
189
190 let address_string = match self.address_typed()? {
191 AddressType::BitcoinExternalString => {
192 self.external_string_address()?
193 }
194 AddressType::EthereumExternalString => {
195 self.external_string_address()?
196 }
197 AddressType::MoneroExternalString => {
198 self.external_string_address()?
199 }
200 AddressType::SolanaExternalString => {
201 self.external_string_address()?
202 }
203 _ => {
204 self.hex()
205 }
206 };
207 Ok(address_string)
208 }
209 pub fn from_bytes(bytes: Vec<u8>) -> Result<Address, ErrorInfo> {
210 let addr = Self::new_raw(bytes);
211 addr.verify_checksum()?;
212 Ok(addr)
213 }
214
215 pub fn from_byte_calculate(vec: &Vec<u8>) -> Result<Address, ErrorInfo> {
216 Self::from_bytes(Self::hash(&vec))
217 }
218
219
220 pub fn from_struct_public(pk: &structs::PublicKey) -> Result<Address, ErrorInfo> {
221 Self::from_byte_calculate(&pk.vec())
222 }
223
224 pub fn with_checksum(bytes: Vec<u8>) -> Vec<u8> {
225 let checksum_bytes = Hash::digest(bytes.clone()).raw_bytes().unwrap();
226 let mut res: Vec<u8> = Vec::new();
227 res.extend_from_slice(&bytes);
228 res.extend_from_slice(&checksum_bytes[0..4]);
229 res
230 }
231
232 fn hash(buf: &[u8]) -> Vec<u8> {
233 let bytes = Sha3_224::digest(buf).to_vec();
234 Self::with_checksum(bytes)
235 }
236
237 pub fn verify_length(&self) -> Result<(), ErrorInfo> {
238 Ok(())
243 }
244
245 pub fn verify_checksum(&self) -> Result<(), ErrorInfo> {
246 self.verify_length()?;
247 let bytes = self.raw_bytes()?;
248 if Self::with_checksum(bytes[0..28].to_vec()) != bytes {
249 Err(error_info("Invalid address checksum bytes"))?;
250 }
251 Ok(())
252 }
253
254 pub fn validated(self) -> RgResult<Self> {
255 self.verify_length()?;
256 self.verify_checksum()?;
257 Ok(self)
258 }
259
260 pub fn str_to_address(s: String) -> Vec<u8> {
261 hex::decode(s).expect("hex")
262 }
264
265 pub fn address_to_str(a: &Vec<u8>) -> String {
266 hex::encode(a)
270 }
271
272 pub fn address_data(address: Vec<u8>) -> Option<Address> {
273 Some(Self::new_raw(address))
274 }
275
276 pub fn new_raw(address: Vec<u8>) -> Address {
277 Address {
278 address: bytes_data(address),
279 address_type: AddressType::Sha3224ChecksumPublic as i32,
280 currency: SupportedCurrency::Redgold as i32,
281 }
282 }
283
284 pub fn raw_from_hex(hex: impl Into<String>) -> RgResult<Address> {
285 Self::new_raw(from_hex(hex.into())?).validated()
286 }
287
288 pub fn currency_or(&self) -> SupportedCurrency {
289 self.currency()
290 }
291}
292
293
294
295impl AddressInfo {
296 pub fn from_utxo_entries(address: Address, entries: Vec<UtxoEntry>) -> Self {
297 let mut bal: i64 = 0;
298 for r in &entries {
299 if let Some(o) = &r.output {
300 if let Some(d) = &o.data {
301 if let Some(a) = &d.amount {
302 bal += a.amount;
303 }
304 }
305 }
306 }
307 AddressInfo {
308 address: Some(address.clone()),
309 utxo_entries: entries,
310 balance: bal,
311 recent_transactions: vec![],
312 balances: vec![]
313 }
314 }
315}