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
use bitcoin_address;
use bitcoin_utils::{
self, get_pubkey_hash_from_p2wpkh_address, get_public_key_hash_from_address,
get_script_hash_from_p2sh_address,
};
use electrs_request::{
BlockchainRelayFeeCommand, BlockchainScriptHashGetBalanceCommand,
BlockchainScriptHashListUnspentCommand, Client as ElectrsRequestClient,
};
use hex_utilities::convert_big_endian_hex_to_little_endian;
pub struct Client {
electrs_request_client: ElectrsRequestClient,
}
impl Client {
pub fn new(electrum_server_address: &str) -> Self {
let electrs_request_client = ElectrsRequestClient::new(electrum_server_address);
Client {
electrs_request_client,
}
}
}
#[derive(Debug)]
pub struct AddressBalance {
pub confirmed: u64,
pub unconfirmed: u64,
}
fn get_script_hash_for_p2pkh_address(p2pkh_address: &str) -> String {
let p2pkh_address = p2pkh_address.to_string();
let p2pkh_pk_hash = get_public_key_hash_from_address(&p2pkh_address);
let p2pkh_script = format!("{}{}{}", "76a914", p2pkh_pk_hash, "88ac");
let p2pkh_script_hash = bitcoin_utils::sha256_hex(&p2pkh_script);
p2pkh_script_hash
}
fn get_script_hash_for_p2sh_address(p2sh_address: &str) -> String {
let p2sh_address = p2sh_address.to_string();
let p2sh_script_hash = get_script_hash_from_p2sh_address(&p2sh_address);
let p2sh_script = format!("{}{}{}", "a914", p2sh_script_hash, "87");
let p2sh_script_hash_sha256 = bitcoin_utils::sha256_hex(&p2sh_script);
p2sh_script_hash_sha256
}
fn get_script_hash_for_p2wpkh_address(p2wpkh_address: &str) -> String {
let p2wpkh_address = p2wpkh_address.to_string();
let p2wpkh_pk_hash = get_public_key_hash_from_address(&p2wpkh_address);
let p2wpkh_script = format!("{}{}", "0014", p2wpkh_pk_hash);
let p2wpkh_script_hash = bitcoin_utils::sha256_hex(&p2wpkh_script);
p2wpkh_script_hash
}
fn get_script_hash_for_address(address: &str) -> String {
let address = &address.to_string();
if bitcoin_address::is_p2pkh(address) {
get_script_hash_for_p2pkh_address(address)
} else if bitcoin_address::is_p2sh(address) {
get_script_hash_for_p2sh_address(address)
} else if bitcoin_address::is_p2wpkh(address) {
get_script_hash_for_p2wpkh_address(address)
} else {
panic!("Address type not supported: {}", address);
}
}
pub fn get_relay_fee(client: &Client) -> f64 {
let relay_fee_response = BlockchainRelayFeeCommand::new()
.call(&client.electrs_request_client)
.unwrap();
relay_fee_response.0
}
pub fn get_balance_for_address(address: &str, client: &Client) -> AddressBalance {
let script_hash = get_script_hash_for_address(address);
let script_hash_le = convert_big_endian_hex_to_little_endian(&script_hash);
let balance_response = BlockchainScriptHashGetBalanceCommand::new(&script_hash_le)
.call(&client.electrs_request_client)
.unwrap();
AddressBalance {
unconfirmed: balance_response.unconfirmed,
confirmed: balance_response.confirmed,
}
}
#[derive(Debug)]
pub struct Utxo {
pub height: u64,
pub tx_hash: String,
pub tx_pos: u64,
pub value: u64,
}
pub fn get_utxos_for_address(address: &str, client: &Client) -> Vec<Utxo> {
let script_hash = get_script_hash_for_address(address);
let script_hash_le = convert_big_endian_hex_to_little_endian(&script_hash);
let list_unspent_response = BlockchainScriptHashListUnspentCommand::new(&script_hash_le)
.call(&client.electrs_request_client)
.unwrap();
let utxos = list_unspent_response
.0
.iter()
.map(|unspent| Utxo {
height: unspent.height,
tx_hash: unspent.tx_hash.clone(),
tx_pos: unspent.tx_pos,
value: unspent.value,
})
.collect();
utxos
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
}
}