Skip to content

Commit 5faa35d

Browse files
committed
feat(hwi): add hwi sign subcommand
- add signing psbt with hardware wallet
1 parent 178d2c1 commit 5faa35d

File tree

4 files changed

+28
-65
lines changed

4 files changed

+28
-65
lines changed

Cargo.lock

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/commands.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -410,12 +410,6 @@ pub enum OfflineWalletSubCommand {
410410
#[arg(env = "BASE64_PSBT", required = true)]
411411
psbt: Vec<String>,
412412
},
413-
#[cfg(feature = "hwi")]
414-
/// Hardware wallet interface operations.
415-
Hwi {
416-
#[clap(subcommand)]
417-
subcommand: HwiSubCommand,
418-
},
419413
}
420414

421415
/// Wallet subcommands that needs a blockchain backend.
@@ -539,6 +533,11 @@ pub enum HwiSubCommand {
539533
Register,
540534
/// Generate address
541535
Address,
536+
/// Sign PSBT with hardware wallet
537+
Sign {
538+
/// The base64-encoded PSBT to sign
539+
psbt: String,
540+
},
542541
}
543542

544543
/// Subcommands available in REPL mode.

src/handlers.rs

Lines changed: 7 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ use bdk_redb::Store as RedbStore;
2121
use bdk_wallet::bip39::{Language, Mnemonic};
2222
use bdk_wallet::bitcoin::base64::Engine;
2323
use bdk_wallet::bitcoin::base64::prelude::BASE64_STANDARD;
24+
#[cfg(feature = "hwi")]
25+
use bdk_wallet::bitcoin::hex::DisplayHex;
2426
use bdk_wallet::bitcoin::{
2527
Address, Amount, FeeRate, Network, Psbt, Sequence, Txid,
2628
bip32::{DerivationPath, KeySource},
@@ -29,8 +31,6 @@ use bdk_wallet::bitcoin::{
2931
secp256k1::Secp256k1,
3032
};
3133
use bdk_wallet::chain::ChainPosition;
32-
#[cfg(feature = "hwi")]
33-
use bdk_wallet::bitcoin::hex::DisplayHex;
3434
use bdk_wallet::descriptor::Segwitv0;
3535
use bdk_wallet::keys::{
3636
DerivableKey, DescriptorKey, DescriptorKey::Secret, ExtendedKey, GeneratableKey, GeneratedKey,
@@ -99,7 +99,7 @@ const NUMS_UNSPENDABLE_KEY_HEX: &str =
9999
/// Execute an offline wallet sub-command
100100
///
101101
/// Offline wallet sub-commands are described in [`OfflineWalletSubCommand`].
102-
pub async fn handle_offline_wallet_subcommand(
102+
pub fn handle_offline_wallet_subcommand(
103103
wallet: &mut Wallet,
104104
wallet_opts: &WalletOpts,
105105
cli_opts: &CliOpts,
@@ -593,56 +593,6 @@ pub async fn handle_offline_wallet_subcommand(
593593
&json!({ "psbt": BASE64_STANDARD.encode(final_psbt.serialize()) }),
594594
)?)
595595
}
596-
#[cfg(feature = "hwi")]
597-
Hwi { subcommand } => match subcommand {
598-
HwiSubCommand::Devices => {
599-
let device = crate::utils::connect_to_hardware_wallet(
600-
wallet.network(),
601-
wallet_opts,
602-
Some(wallet),
603-
)
604-
.await?;
605-
let device = if let Some(device) = device {
606-
json!({
607-
"type": device.device_kind().to_string(),
608-
"fingerprint": device.get_master_fingerprint().await?.to_string(),
609-
"model": device.device_kind().to_string(),
610-
})
611-
} else {
612-
json!(null)
613-
};
614-
Ok(json!({ "devices": device }))
615-
}
616-
HwiSubCommand::Register => {
617-
let policy = wallet_opts.ext_descriptor.clone().ok_or_else(|| {
618-
Error::Generic(
619-
"External descriptor required for wallet registration".to_string(),
620-
)
621-
})?;
622-
let wallet_name = wallet_opts.wallet.clone().ok_or_else(|| {
623-
Error::Generic("Wallet name is required for wallet registration".to_string())
624-
})?;
625-
626-
let device = crate::utils::connect_to_hardware_wallet(
627-
wallet.network(),
628-
wallet_opts,
629-
Some(wallet),
630-
)
631-
.await?;
632-
let hmac = if let Some(device) = device {
633-
let hmac = device.register_wallet(&wallet_name, &policy).await?;
634-
hmac.map(|h| h.to_lower_hex_string())
635-
} else {
636-
None
637-
};
638-
//TODO: return status of wallet registration
639-
Ok(json!({ "hmac": hmac }))
640-
}
641-
HwiSubCommand::Address => {
642-
let address = wallet.next_unused_address(KeychainKind::External);
643-
Ok(json!({ "address": address.address }))
644-
}
645-
},
646596
}
647597
}
648598

@@ -1366,7 +1316,7 @@ pub(crate) async fn handle_command(cli_opts: CliOpts) -> Result<String, Error> {
13661316
offline_subcommand.clone(),
13671317
)?
13681318
};
1369-
Ok(result)
1319+
Ok(result?)
13701320
}
13711321
CliSubCommand::Wallet {
13721322
wallet,
@@ -1512,9 +1462,9 @@ async fn respond(
15121462
ReplSubCommand::Wallet {
15131463
subcommand: WalletSubCommand::OfflineWalletSubCommand(offline_subcommand),
15141464
} => {
1515-
let value = handle_offline_wallet_subcommand(wallet, wallet_opts, cli_opts, offline_subcommand)
1516-
.await
1517-
.map_err(|e| e.to_string())?;
1465+
let value =
1466+
handle_offline_wallet_subcommand(wallet, wallet_opts, cli_opts, offline_subcommand)
1467+
.map_err(|e| e.to_string())?;
15181468
Some(value)
15191469
}
15201470
ReplSubCommand::Wallet {

src/utils.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use bdk_kyoto::{
2424
BuilderExt, Info, LightClient, Receiver, ScanType::Sync, UnboundedReceiver, Warning,
2525
builder::Builder,
2626
};
27+
use bdk_wallet::bitcoin::{Address, Network, OutPoint, ScriptBuf};
2728
use bdk_wallet::{
2829
KeychainKind,
2930
bitcoin::bip32::{DerivationPath, Xpub},
@@ -35,17 +36,16 @@ use bdk_wallet::{
3536
template::DescriptorTemplate,
3637
};
3738
use cli_table::{Cell, CellStruct, Style, Table};
38-
use bdk_wallet::bitcoin::{Address, Network, OutPoint, ScriptBuf};
3939
#[cfg(feature = "hwi")]
4040
use {
4141
async_hwi::jade::{self, Jade},
4242
async_hwi::ledger::{HidApi, LedgerSimulator},
4343
async_hwi::specter::{Specter, SpecterSimulator},
44+
async_hwi::{HWI, coldcard},
4445
async_hwi::{
4546
bitbox::api::runtime,
4647
bitbox::{BitBox02, PairingBitbox02WithLocalCache},
4748
},
48-
async_hwi::{coldcard, HWI},
4949
};
5050

5151
#[cfg(any(

0 commit comments

Comments
 (0)