@@ -37,17 +37,7 @@ use bdk_wallet::{
3737} ;
3838use cli_table:: { Cell , CellStruct , Style , Table } ;
3939#[ cfg( feature = "hwi" ) ]
40- use {
41- crate :: commands:: HwiOpts ,
42- async_hwi:: jade:: { self , Jade } ,
43- async_hwi:: ledger:: { HidApi , Ledger , LedgerSimulator , TransportHID } ,
44- async_hwi:: specter:: { Specter , SpecterSimulator } ,
45- async_hwi:: { HWI , coldcard} ,
46- async_hwi:: {
47- bitbox:: api:: runtime,
48- bitbox:: { BitBox02 , PairingBitbox02WithLocalCache } ,
49- } ,
50- } ;
40+ use std:: marker:: Sync as MarkerSync ;
5141
5242#[ cfg( any(
5343 feature = "electrum" ,
@@ -661,109 +651,61 @@ pub fn load_wallet_config(
661651}
662652
663653#[ cfg( feature = "hwi" ) ]
664- pub async fn connect_to_hardware_wallet (
654+ pub async fn get_hwi_device (
665655 network : Network ,
666- hwi_opts : & HwiOpts ,
667- ) -> Result < Option < Box < dyn HWI + Send > > , Error > {
668- if let Ok ( device) = SpecterSimulator :: try_connect ( ) . await {
669- return Ok ( Some ( device. into ( ) ) ) ;
670- }
671-
672- if let Ok ( devices) = Specter :: enumerate ( ) . await {
673- if let Some ( device) = devices. into_iter ( ) . next ( ) {
674- return Ok ( Some ( device. into ( ) ) ) ;
675- }
676- }
677-
678- match Jade :: enumerate ( ) . await {
679- Err ( e) => {
680- println ! ( "Jade enumeration error: {e:?}" ) ;
681- }
682- Ok ( devices) => {
683- for device in devices {
684- let device = device. with_network ( network) ;
685- if let Ok ( info) = device. get_info ( ) . await {
686- if info. jade_state == jade:: api:: JadeState :: Locked {
687- if let Err ( e) = device. auth ( ) . await {
688- eprintln ! ( "Jade auth error: {:?}" , e) ;
689- continue ;
690- }
656+ hwi_opts : & crate :: commands:: HwiOpts ,
657+ ) -> Result < Option < Arc < dyn async_hwi:: HWI + Send + MarkerSync > > , Error > {
658+ use async_hwi:: ledger:: { HidApi , Ledger , TransportHID } ;
659+ use async_hwi:: service:: { HwiService , SigningDevice , SigningDeviceMsg } ;
660+ use crossbeam:: channel;
661+ use std:: time:: { Duration , Instant } ;
662+
663+ let ( sender, receiver) = channel:: unbounded :: < SigningDeviceMsg > ( ) ;
664+ let service = HwiService :: new ( network, Some ( tokio:: runtime:: Handle :: current ( ) ) ) ;
665+ service. start ( sender) ;
666+
667+ let timeout = Duration :: from_secs ( 5 ) ;
668+ let start = Instant :: now ( ) ;
669+
670+ while start. elapsed ( ) < timeout {
671+ if let Ok ( SigningDeviceMsg :: Update ) = receiver. recv_timeout ( Duration :: from_millis ( 200 ) ) {
672+ let devices = service. list ( ) ;
673+ for ( _, signing_device) in devices {
674+ if let SigningDevice :: Supported ( supported) = signing_device {
675+ let device = supported. device ( ) . clone ( ) ;
676+
677+ if device. device_kind ( ) == async_hwi:: DeviceKind :: Ledger {
678+ let wallet_name = hwi_opts. wallet . clone ( ) . ok_or_else ( || {
679+ Error :: Generic ( "Wallet name required for Ledger" . to_string ( ) )
680+ } ) ?;
681+ let policy = hwi_opts. ext_descriptor . clone ( ) . ok_or_else ( || {
682+ Error :: Generic ( "Descriptor required for Ledger policy" . to_string ( ) )
683+ } ) ?;
684+
685+ let api = HidApi :: new ( ) . map_err ( |e| Error :: Generic ( e. to_string ( ) ) ) ?;
686+ let detected = Ledger :: < TransportHID > :: enumerate ( & api)
687+ . next ( )
688+ . ok_or_else ( || Error :: Generic ( "Ledger lost" . to_string ( ) ) ) ?;
689+
690+ let mut ledger = Ledger :: < TransportHID > :: connect ( & api, detected)
691+ . map_err ( |e| Error :: Generic ( e. to_string ( ) ) ) ?;
692+
693+ ledger = ledger
694+ . with_wallet ( wallet_name, & policy, None )
695+ . map_err ( |e| Error :: Generic ( e. to_string ( ) ) ) ?;
696+
697+ service. stop ( ) ;
698+ return Ok ( Some ( Arc :: new ( ledger) ) ) ;
691699 }
692- return Ok ( Some ( device. into ( ) ) ) ;
693- }
694- }
695- }
696- }
697-
698- if let Ok ( device) = LedgerSimulator :: try_connect ( ) . await {
699- return Ok ( Some ( device. into ( ) ) ) ;
700- }
701700
702- let api = Box :: new ( HidApi :: new ( ) . map_err ( |e| Error :: Generic ( e. to_string ( ) ) ) ?) ;
703-
704- for device_info in api. device_list ( ) {
705- let ext_descriptor = hwi_opts. ext_descriptor . clone ( ) . ok_or_else ( || {
706- Error :: Generic ( "External descriptor is required for connecting to bitbox and coldcard hardware devices" . to_string ( ) )
707- } ) ?;
708- let wallet_name = hwi_opts. wallet . clone ( ) . ok_or_else ( || {
709- Error :: Generic (
710- "Wallet name is required for connecting to bitbox and coldcard hardware devices"
711- . to_string ( ) ,
712- )
713- } ) ?;
714- if async_hwi:: bitbox:: is_bitbox02 ( device_info) {
715- if let Ok ( device) = device_info
716- . open_device ( & api)
717- . map_err ( |e| Error :: Generic ( e. to_string ( ) ) )
718- {
719- if let Ok ( device) =
720- PairingBitbox02WithLocalCache :: < runtime:: TokioRuntime > :: connect ( device, None )
721- . await
722- {
723- if let Ok ( ( device, _) ) = device. wait_confirm ( ) . await {
724- let mut bb02 = BitBox02 :: from ( device) . with_network ( network) ;
725- bb02 = bb02
726- . with_policy ( & ext_descriptor. as_str ( ) )
727- . map_err ( Error :: HwiError ) ?;
728- return Ok ( Some ( bb02. into ( ) ) ) ;
729- }
730- }
731- }
732- }
733- if device_info. vendor_id ( ) == coldcard:: api:: COINKITE_VID
734- && device_info. product_id ( ) == coldcard:: api:: CKCC_PID
735- {
736- if let Some ( sn) = device_info. serial_number ( ) {
737- if let Ok ( ( cc, _) ) = coldcard:: api:: Coldcard :: open ( & api, sn, None )
738- . map_err ( |e| Error :: Generic ( e. to_string ( ) ) )
739- {
740- let mut hw = coldcard:: Coldcard :: from ( cc) ;
741- hw = hw. with_wallet_name ( wallet_name. to_string ( ) ) ;
742- return Ok ( Some ( hw. into ( ) ) ) ;
701+ service. stop ( ) ;
702+ return Ok ( Some ( device) ) ;
743703 }
744704 }
745705 }
706+ tokio:: task:: yield_now ( ) . await ;
746707 }
747708
748- for detected in Ledger :: < TransportHID > :: enumerate ( & api) {
749- let ext_descriptor = hwi_opts. ext_descriptor . clone ( ) . ok_or_else ( || {
750- Error :: Generic (
751- "External descriptor required for connecting to ledger hardware device" . to_string ( ) ,
752- )
753- } ) ?;
754- let wallet_name = hwi_opts. wallet . clone ( ) . ok_or_else ( || {
755- Error :: Generic (
756- "Wallet name is required for connecting to ledger hardware device" . to_string ( ) ,
757- )
758- } ) ?;
759-
760- if let Ok ( mut device) = Ledger :: < TransportHID > :: connect ( & api, detected) {
761- device = device
762- . with_wallet ( wallet_name, & ext_descriptor, None )
763- . map_err ( Error :: HwiError ) ?;
764- return Ok ( Some ( device. into ( ) ) ) ;
765- }
766- }
767-
709+ service. stop ( ) ;
768710 Ok ( None )
769711}
0 commit comments