1use crate::error::{Error, Result};
2use bitcoin::{
3 address,
4 address::Payload,
5 bip32,
6 blockdata::script::Script,
7 hashes::{sha256d, Hash},
8 psbt,
9 secp256k1::ecdsa::{RecoverableSignature, RecoveryId},
10 Address, Network,
11};
12
13pub fn address_from_script(script: &Script, network: Network) -> Option<address::Address> {
15 let payload = Payload::from_script(script).ok()?;
16 Some(Address::new(network, payload))
17}
18
19pub fn psbt_find_input(psbt: &psbt::Psbt, txid: sha256d::Hash) -> Result<&psbt::Input> {
21 let inputs = &psbt.unsigned_tx.input;
22 let idx = inputs
23 .iter()
24 .position(|tx| *tx.previous_output.txid.as_raw_hash() == txid)
25 .ok_or(Error::TxRequestUnknownTxid(txid))?;
26 psbt.inputs.get(idx).ok_or(Error::TxRequestInvalidIndex(idx))
27}
28
29pub fn from_rev_bytes(rev_bytes: &[u8]) -> Option<sha256d::Hash> {
31 let mut bytes = rev_bytes.to_vec();
32 bytes.reverse();
33 sha256d::Hash::from_slice(&bytes).ok()
34}
35
36pub fn to_rev_bytes(hash: &sha256d::Hash) -> [u8; 32] {
38 let mut bytes = hash.to_byte_array();
39 bytes.reverse();
40 bytes
41}
42
43pub fn parse_recoverable_signature(
45 sig: &[u8],
46) -> Result<RecoverableSignature, bitcoin::secp256k1::Error> {
47 if sig.len() != 65 {
48 return Err(bitcoin::secp256k1::Error::InvalidSignature)
49 }
50
51 let rec_id = RecoveryId::from_i32(if sig[0] >= 31 {
53 (sig[0] - 31) as i32
54 } else {
55 (sig[0] - 27) as i32
56 })?;
57
58 RecoverableSignature::from_compact(&sig[1..], rec_id)
59}
60
61pub fn coin_name(network: Network) -> Result<String> {
63 match network {
64 Network::Bitcoin => Ok("Bitcoin".to_owned()),
65 Network::Testnet => Ok("Testnet".to_owned()),
66 _ => Err(Error::UnsupportedNetwork),
67 }
68}
69
70pub fn convert_path(path: &bip32::DerivationPath) -> Vec<u32> {
72 path.into_iter().map(|i| u32::from(*i)).collect()
73}