Coverage Report

Created: 2024-10-10 10:38

/home/darosior/projects/bdk/crates/hwi/src/signer.rs
Line
Count
Source (jump to first uncovered line)
1
use bdk_wallet::bitcoin::bip32::Fingerprint;
2
use bdk_wallet::bitcoin::secp256k1::{All, Secp256k1};
3
use bdk_wallet::bitcoin::Psbt;
4
5
use hwi::error::Error;
6
use hwi::types::{HWIChain, HWIDevice};
7
use hwi::HWIClient;
8
9
use bdk_wallet::signer::{SignerCommon, SignerError, SignerId, TransactionSigner};
10
11
#[derive(Debug)]
12
/// Custom signer for Hardware Wallets
13
///
14
/// This ignores `sign_options` and leaves the decisions up to the hardware wallet.
15
pub struct HWISigner {
16
    fingerprint: Fingerprint,
17
    client: HWIClient,
18
}
19
20
impl HWISigner {
21
    /// Create a instance from the specified device and chain
22
0
    pub fn from_device(device: &HWIDevice, chain: HWIChain) -> Result<HWISigner, Error> {
23
0
        let client = HWIClient::get_client(device, false, chain)?;
24
0
        Ok(HWISigner {
25
0
            fingerprint: device.fingerprint,
26
0
            client,
27
0
        })
28
0
    }
29
}
30
31
impl SignerCommon for HWISigner {
32
0
    fn id(&self, _secp: &Secp256k1<All>) -> SignerId {
33
0
        SignerId::Fingerprint(self.fingerprint)
34
0
    }
35
}
36
37
impl TransactionSigner for HWISigner {
38
0
    fn sign_transaction(
39
0
        &self,
40
0
        psbt: &mut Psbt,
41
0
        _sign_options: &bdk_wallet::SignOptions,
42
0
        _secp: &Secp256k1<All>,
43
0
    ) -> Result<(), SignerError> {
44
0
        psbt.combine(
45
0
            self.client
46
0
                .sign_tx(psbt)
47
0
                .map_err(|e| {
48
0
                    SignerError::External(format!("While signing with hardware wallet: {}", e))
49
0
                })?
50
                .psbt,
51
        )
52
0
        .expect("Failed to combine HW signed psbt with passed PSBT");
53
0
        Ok(())
54
0
    }
55
}
56
57
// TODO: re-enable this once we have the `get_funded_wallet` test util
58
// #[cfg(test)]
59
// mod tests {
60
//     #[test]
61
//     fn test_hardware_signer() {
62
//         use std::sync::Arc;
63
//
64
//         use bdk_wallet::tests::get_funded_wallet;
65
//         use bdk_wallet::signer::SignerOrdering;
66
//         use bdk_wallet::bitcoin::Network;
67
//         use crate::HWISigner;
68
//         use hwi::HWIClient;
69
//
70
//         let mut devices = HWIClient::enumerate().unwrap();
71
//         if devices.is_empty() {
72
//             panic!("No devices found!");
73
//         }
74
//         let device = devices.remove(0).unwrap();
75
//         let client = HWIClient::get_client(&device, true, Network::Regtest.into()).unwrap();
76
//         let descriptors = client.get_descriptors::<String>(None).unwrap();
77
//         let custom_signer = HWISigner::from_device(&device, Network::Regtest.into()).unwrap();
78
//
79
//         let (mut wallet, _) = get_funded_wallet(&descriptors.internal[0]);
80
//         wallet.add_signer(
81
//             bdk_wallet::KeychainKind::External,
82
//             SignerOrdering(200),
83
//             Arc::new(custom_signer),
84
//         );
85
//
86
//         let addr = wallet.get_address(bdk_wallet::AddressIndex::LastUnused);
87
//         let mut builder = wallet.build_tx();
88
//         builder.drain_to(addr.script_pubkey()).drain_wallet();
89
//         let (mut psbt, _) = builder.finish().unwrap();
90
//
91
//         let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
92
//         assert!(finalized);
93
//     }
94
// }