Skip to content
Prev Previous commit
Support Signer with the new HWIImplementation option
  • Loading branch information
ben-kaufman committed Sep 26, 2024
commit b2c59ca877d5496776a0ee1ed94271607900757d
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ pip install -r requirements.txt
use bitcoin::Network;
use bitcoin::bip32::DerivationPath;
use hwi::error::Error;
use hwi::HWIClient;
use hwi::types::HWIClient;
use hwi::implementations::python_implementation::PythonHWIImplementation;
use std::str::FromStr;

Expand Down
12 changes: 4 additions & 8 deletions src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use serde_json::value::Value;

use crate::error::Error;
use crate::types::{
HWIAddress, HWIAddressType, HWIChain, HWIDescriptor, HWIDevice, HWIDeviceInternal,
HWIAddress, HWIAddressType, HWIChain, HWIClient, HWIDescriptor, HWIDevice, HWIDeviceInternal,
HWIDeviceType, HWIExtendedPubKey, HWIImplementation, HWIKeyPoolElement,
HWIPartiallySignedTransaction, HWISignature, HWIStatus, HWIWordCount, LogLevel, ToDescriptor,
};
Expand All @@ -22,14 +22,10 @@ macro_rules! deserialize_obj {
}};
}

pub struct HWIClient<T: HWIImplementation> {
implementation: T,
}

impl<T: HWIImplementation> HWIClient<T> {
/// Lists all HW devices currently connected.
/// ```no_run
/// # use hwi::HWIClient;
/// # use hwi::types::HWIClient;
/// # use hwi::implementations::python_implementation::PythonHWIImplementation;
/// # use hwi::error::Error;
/// # fn main() -> Result<(), Error> {
Expand All @@ -54,7 +50,7 @@ impl<T: HWIImplementation> HWIClient<T> {
///
/// Setting `expert` to `true` will enable additional output for some commands.
/// ```
/// # use hwi::HWIClient;
/// # use hwi::types::HWIClient;
/// # use hwi::types::*;
/// # use hwi::error::Error;
/// # use hwi::implementations::python_implementation::PythonHWIImplementation;
Expand Down Expand Up @@ -88,7 +84,7 @@ impl<T: HWIImplementation> HWIClient<T> {
///
/// Setting `expert` to `true` will enable additional output for some commands.
/// ```no_run
/// # use hwi::HWIClient;
/// # use hwi::types::HWIClient;
/// # use hwi::types::*;
/// # use hwi::error::Error;
/// # use hwi::implementations::python_implementation::PythonHWIImplementation;
Expand Down
11 changes: 6 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@
//! use bitcoin::bip32::{ChildNumber, DerivationPath};
//! use hwi::error::Error;
//! use hwi::implementations::python_implementation::PythonHWIImplementation;
//! use hwi::interface::HWIClient;
//! use hwi::types;
//! use std::str::FromStr;
//!
//! fn main() -> Result<(), Error> {
//! // Find information about devices
//! let mut devices = HWIClient::<PythonHWIImplementation>::enumerate()?;
//! let mut devices = types::HWIClient::<PythonHWIImplementation>::enumerate()?;
//! if devices.is_empty() {
//! panic!("No device found!");
//! }
Expand Down Expand Up @@ -79,7 +78,6 @@
extern crate serial_test;
extern crate core;

pub use interface::HWIClient;
#[cfg(feature = "signer")]
pub use signer::HWISigner;

Expand All @@ -97,8 +95,9 @@ mod tests {
use crate::error::Error;
use crate::implementations::binary_implementation::BinaryHWIImplementation;
use crate::implementations::python_implementation::PythonHWIImplementation;
use crate::types::{self, HWIBinaryExecutor, HWIDeviceType, HWIImplementation, TESTNET};
use crate::HWIClient;
use crate::types::{
self, HWIBinaryExecutor, HWIClient, HWIDeviceType, HWIImplementation, TESTNET,
};
use std::collections::BTreeMap;
use std::str::FromStr;

Expand All @@ -112,6 +111,8 @@ mod tests {

#[cfg(feature = "miniscript")]
use miniscript::{Descriptor, DescriptorPublicKey};

#[derive(Debug)]
struct HWIBinaryExecutorImpl;

impl HWIBinaryExecutor for HWIBinaryExecutorImpl {
Expand Down
19 changes: 9 additions & 10 deletions src/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,37 @@ use bdk_wallet::bitcoin::secp256k1::{All, Secp256k1};
use bdk_wallet::bitcoin::Psbt;

use crate::error::Error;
use crate::types::{HWIChain, HWIDevice};
use crate::HWIClient;
use crate::types::{HWIChain, HWIClient, HWIDevice, HWIImplementation};

use bdk_wallet::signer::{SignerCommon, SignerError, SignerId, TransactionSigner};

#[derive(Debug)]
/// Custom signer for Hardware Wallets
///
/// This ignores `sign_options` and leaves the decisions up to the hardware wallet.
pub struct HWISigner {
pub struct HWISigner<T: HWIImplementation> {
fingerprint: Fingerprint,
client: HWIClient,
client: HWIClient<T>,
}

impl HWISigner {
impl<T: HWIImplementation> HWISigner<T> {
/// Create an instance from the specified device and chain
pub fn from_device(device: &HWIDevice, chain: HWIChain) -> Result<HWISigner, Error> {
let client = HWIClient::get_client(device, false, chain)?;
Ok(HWISigner {
pub fn from_device(device: &HWIDevice, chain: HWIChain) -> Result<Self, Error> {
let client = HWIClient::<T>::get_client(device, false, chain)?;
Ok(Self {
fingerprint: device.fingerprint,
client,
})
}
}

impl SignerCommon for HWISigner {
impl<T: HWIImplementation> SignerCommon for HWISigner<T> {
fn id(&self, _secp: &Secp256k1<All>) -> SignerId {
SignerId::Fingerprint(self.fingerprint)
}
}

impl TransactionSigner for HWISigner {
impl<T: HWIImplementation> TransactionSigner for HWISigner<T> {
fn sign_transaction(
&self,
psbt: &mut Psbt,
Expand Down
11 changes: 8 additions & 3 deletions src/types.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use core::fmt;
use std::convert::TryFrom;
use std::fmt::{Display, Formatter};
use std::fmt::{Debug, Display, Formatter};
use std::ops::Deref;
use std::str::FromStr;

Expand Down Expand Up @@ -320,7 +320,7 @@ pub enum HWIWordCount {
W24 = 24,
}

pub trait HWIImplementation {
pub trait HWIImplementation: Debug + Send + Sync {
fn enumerate() -> Result<String, Error>;
fn get_client(device: &HWIDevice, expert: bool, chain: HWIChain) -> Result<Self, Error>
where
Expand Down Expand Up @@ -368,6 +368,11 @@ pub trait HWIImplementation {
fn install_hwilib(version: String) -> Result<(), Error>;
}

pub trait HWIBinaryExecutor {
#[derive(Clone, Eq, PartialEq, Debug, Copy)]
pub struct HWIClient<T: HWIImplementation> {
pub implementation: T,
}

pub trait HWIBinaryExecutor: Debug + Send + Sync {
fn execute_command(args: Vec<String>) -> Result<String, Error>;
}