|
77 | 77 | /// Execute an offline wallet sub-command |
78 | 78 | /// |
79 | 79 | /// Offline wallet sub-commands are described in [`OfflineWalletSubCommand`]. |
80 | | -pub async fn handle_offline_wallet_subcommand( |
| 80 | +pub fn handle_offline_wallet_subcommand( |
81 | 81 | wallet: &mut Wallet, |
82 | 82 | wallet_opts: &WalletOpts, |
83 | 83 | offline_subcommand: OfflineWalletSubCommand, |
@@ -330,56 +330,6 @@ pub async fn handle_offline_wallet_subcommand( |
330 | 330 | )?; |
331 | 331 | Ok(json!({ "psbt": BASE64_STANDARD.encode(final_psbt.serialize()) })) |
332 | 332 | } |
333 | | - #[cfg(feature = "hwi")] |
334 | | - Hwi { subcommand } => match subcommand { |
335 | | - HwiSubCommand::Devices => { |
336 | | - let device = crate::utils::connect_to_hardware_wallet( |
337 | | - wallet.network(), |
338 | | - wallet_opts, |
339 | | - Some(wallet), |
340 | | - ) |
341 | | - .await?; |
342 | | - let device = if let Some(device) = device { |
343 | | - json!({ |
344 | | - "type": device.device_kind().to_string(), |
345 | | - "fingerprint": device.get_master_fingerprint().await?.to_string(), |
346 | | - "model": device.device_kind().to_string(), |
347 | | - }) |
348 | | - } else { |
349 | | - json!(null) |
350 | | - }; |
351 | | - Ok(json!({ "devices": device })) |
352 | | - } |
353 | | - HwiSubCommand::Register => { |
354 | | - let policy = wallet_opts.ext_descriptor.clone().ok_or_else(|| { |
355 | | - Error::Generic( |
356 | | - "External descriptor required for wallet registration".to_string(), |
357 | | - ) |
358 | | - })?; |
359 | | - let wallet_name = wallet_opts.wallet.clone().ok_or_else(|| { |
360 | | - Error::Generic("Wallet name is required for wallet registration".to_string()) |
361 | | - })?; |
362 | | - |
363 | | - let device = crate::utils::connect_to_hardware_wallet( |
364 | | - wallet.network(), |
365 | | - wallet_opts, |
366 | | - Some(wallet), |
367 | | - ) |
368 | | - .await?; |
369 | | - let hmac = if let Some(device) = device { |
370 | | - let hmac = device.register_wallet(&wallet_name, &policy).await?; |
371 | | - hmac.map(|h| h.to_lower_hex_string()) |
372 | | - } else { |
373 | | - None |
374 | | - }; |
375 | | - //TODO: return status of wallet registration |
376 | | - Ok(json!({ "hmac": hmac })) |
377 | | - } |
378 | | - HwiSubCommand::Address => { |
379 | | - let address = wallet.next_unused_address(KeychainKind::External); |
380 | | - Ok(json!({ "address": address.address })) |
381 | | - } |
382 | | - }, |
383 | 333 | } |
384 | 334 | } |
385 | 335 |
|
@@ -793,6 +743,138 @@ pub(crate) fn handle_compile_subcommand( |
793 | 743 | Ok(json!({"descriptor": descriptor.to_string()})) |
794 | 744 | } |
795 | 745 |
|
| 746 | +/// Handle hardware wallet operations |
| 747 | +#[cfg(feature = "hwi")] |
| 748 | +pub async fn handle_hwi_subcommand( |
| 749 | + network: Network, |
| 750 | + wallet_opts: &WalletOpts, |
| 751 | + subcommand: HwiSubCommand, |
| 752 | +) -> Result<serde_json::Value, Error> { |
| 753 | + match subcommand { |
| 754 | + HwiSubCommand::Devices => { |
| 755 | + let devices = crate::utils::connect_to_hardware_wallet( |
| 756 | + wallet.network(), |
| 757 | + wallet_opts, |
| 758 | + Some(wallet), |
| 759 | + ) |
| 760 | + .await?; |
| 761 | + let device = if let Some(device) = device { |
| 762 | + json!({ |
| 763 | + "type": device.device_kind().to_string(), |
| 764 | + "fingerprint": device.get_master_fingerprint().await?.to_string(), |
| 765 | + "model": device.device_kind().to_string(), |
| 766 | + }) |
| 767 | + } else { |
| 768 | + json!(null) |
| 769 | + }; |
| 770 | + Ok(json!({ "devices": device })) |
| 771 | + } |
| 772 | + HwiSubCommand::Register => { |
| 773 | + let policy = wallet_opts.ext_descriptor.clone().ok_or_else(|| { |
| 774 | + Error::Generic("External descriptor required for wallet registration".to_string()) |
| 775 | + })?; |
| 776 | + let wallet_name = wallet_opts.wallet.clone().ok_or_else(|| { |
| 777 | + Error::Generic("Wallet name is required for wallet registration".to_string()) |
| 778 | + })?; |
| 779 | + |
| 780 | + let home_dir = prepare_home_dir(None)?; |
| 781 | + let database_path = prepare_wallet_db_dir(&wallet_opts.wallet, &home_dir)?; |
| 782 | + #[cfg(feature = "sqlite")] |
| 783 | + let wallet = { |
| 784 | + let mut persister = match &wallet_opts.database_type { |
| 785 | + DatabaseType::Sqlite => { |
| 786 | + let db_file = database_path.join("wallet.sqlite"); |
| 787 | + let connection = Connection::open(db_file)?; |
| 788 | + log::debug!("Sqlite database opened successfully"); |
| 789 | + connection |
| 790 | + } |
| 791 | + }; |
| 792 | + let mut wallet = new_persisted_wallet(network, &mut persister, wallet_opts)?; |
| 793 | + wallet.persist(&mut persister)?; |
| 794 | + wallet |
| 795 | + }; |
| 796 | + #[cfg(not(feature = "sqlite"))] |
| 797 | + let wallet = new_wallet(network, wallet_opts)?; |
| 798 | + |
| 799 | + let device = crate::utils::connect_to_hardware_wallet( |
| 800 | + wallet.network(), |
| 801 | + wallet_opts, |
| 802 | + Some(wallet), |
| 803 | + ) |
| 804 | + .await?; |
| 805 | + let hmac = if let Some(device) = device { |
| 806 | + let hmac = device.register_wallet(&wallet_name, &policy).await?; |
| 807 | + hmac.map(|h| h.to_lower_hex_string()) |
| 808 | + } else { |
| 809 | + None |
| 810 | + }; |
| 811 | + Ok(json!({ "hmac": hmac })) |
| 812 | + } |
| 813 | + HwiSubCommand::Address => { |
| 814 | + let home_dir = prepare_home_dir(None)?; |
| 815 | + let database_path = prepare_wallet_db_dir(&wallet_opts.wallet, &home_dir)?; |
| 816 | + #[cfg(feature = "sqlite")] |
| 817 | + let wallet = { |
| 818 | + let mut persister = match &wallet_opts.database_type { |
| 819 | + DatabaseType::Sqlite => { |
| 820 | + let db_file = database_path.join("wallet.sqlite"); |
| 821 | + let connection = Connection::open(db_file)?; |
| 822 | + log::debug!("Sqlite database opened successfully"); |
| 823 | + connection |
| 824 | + } |
| 825 | + }; |
| 826 | + let mut wallet = new_persisted_wallet(network, &mut persister, wallet_opts)?; |
| 827 | + wallet.persist(&mut persister)?; |
| 828 | + wallet |
| 829 | + }; |
| 830 | + #[cfg(not(feature = "sqlite"))] |
| 831 | + let wallet = new_wallet(network, wallet_opts)?; |
| 832 | + |
| 833 | + let address = wallet.next_unused_address(KeychainKind::External); |
| 834 | + Ok(json!({ "address": address.address })) |
| 835 | + } |
| 836 | + HwiSubCommand::Sign { psbt } => { |
| 837 | + let home_dir = prepare_home_dir(None)?; |
| 838 | + let database_path = prepare_wallet_db_dir(&wallet_opts.wallet, &home_dir)?; |
| 839 | + #[cfg(feature = "sqlite")] |
| 840 | + let wallet = { |
| 841 | + let mut persister = match &wallet_opts.database_type { |
| 842 | + DatabaseType::Sqlite => { |
| 843 | + let db_file = database_path.join("wallet.sqlite"); |
| 844 | + let connection = Connection::open(db_file)?; |
| 845 | + log::debug!("Sqlite database opened successfully"); |
| 846 | + connection |
| 847 | + } |
| 848 | + }; |
| 849 | + let mut wallet = new_persisted_wallet(network, &mut persister, wallet_opts)?; |
| 850 | + wallet.persist(&mut persister)?; |
| 851 | + wallet |
| 852 | + }; |
| 853 | + #[cfg(not(feature = "sqlite"))] |
| 854 | + let wallet = new_wallet(network, wallet_opts)?; |
| 855 | + |
| 856 | + let mut psbt = Psbt::from_str(&psbt) |
| 857 | + .map_err(|e| Error::Generic(format!("Failed to parse PSBT: {e}")))?; |
| 858 | + let device = crate::utils::connect_to_hardware_wallet( |
| 859 | + wallet.network(), |
| 860 | + wallet_opts, |
| 861 | + Some(wallet), |
| 862 | + ) |
| 863 | + .await?; |
| 864 | + let signed_psbt = if let Some(device) = device { |
| 865 | + device |
| 866 | + .sign_tx(&mut psbt) |
| 867 | + .await |
| 868 | + .map_err(|e| Error::Generic(format!("Failed to sign PSBT: {e}")))?; |
| 869 | + Some(psbt.to_string()) |
| 870 | + } else { |
| 871 | + None |
| 872 | + }; |
| 873 | + Ok(json!({ "psbt": signed_psbt })) |
| 874 | + } |
| 875 | + } |
| 876 | +} |
| 877 | + |
796 | 878 | /// The global top level handler. |
797 | 879 | pub(crate) async fn handle_command(cli_opts: CliOpts) -> Result<String, Error> { |
798 | 880 | let network = cli_opts.network; |
@@ -837,7 +919,7 @@ pub(crate) async fn handle_command(cli_opts: CliOpts) -> Result<String, Error> { |
837 | 919 | wallet.persist(&mut persister)?; |
838 | 920 | result |
839 | 921 | }; |
840 | | - // #[cfg(not(any(feature = "sqlite")))] |
| 922 | + #[cfg(not(any(feature = "sqlite")))] |
841 | 923 | let result = { |
842 | 924 | let wallet = new_wallet(network, &wallet_opts)?; |
843 | 925 | let blockchain_client = |
@@ -870,8 +952,7 @@ pub(crate) async fn handle_command(cli_opts: CliOpts) -> Result<String, Error> { |
870 | 952 |
|
871 | 953 | let mut wallet = new_persisted_wallet(network, &mut persister, &wallet_opts)?; |
872 | 954 | let result = |
873 | | - handle_offline_wallet_subcommand(&mut wallet, &wallet_opts, offline_subcommand) |
874 | | - .await?; |
| 955 | + handle_offline_wallet_subcommand(&mut wallet, &wallet_opts, offline_subcommand); |
875 | 956 | wallet.persist(&mut persister)?; |
876 | 957 | result |
877 | 958 | }; |
@@ -996,7 +1077,6 @@ async fn respond( |
996 | 1077 | subcommand: WalletSubCommand::OfflineWalletSubCommand(offline_subcommand), |
997 | 1078 | } => { |
998 | 1079 | let value = handle_offline_wallet_subcommand(wallet, wallet_opts, offline_subcommand) |
999 | | - .await |
1000 | 1080 | .map_err(|e| e.to_string())?; |
1001 | 1081 | Some(value) |
1002 | 1082 | } |
|
0 commit comments