diff --git a/.gitignore b/.gitignore index 683f811..ed47e2c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /target +*/target .env .direnv harbor.sqlite diff --git a/harbor-client/src/lib.rs b/harbor-client/src/lib.rs index 3280d68..f77b4e2 100644 --- a/harbor-client/src/lib.rs +++ b/harbor-client/src/lib.rs @@ -11,12 +11,14 @@ use bip39::Mnemonic; use bitcoin::address::NetworkUnchecked; use bitcoin::{Address, Network, Txid}; use fedimint_core::config::{ClientConfig, FederationId}; +use fedimint_core::core::ModuleKind; use fedimint_core::invite_code::InviteCode; use fedimint_core::Amount; use fedimint_ln_client::{LightningClientModule, PayType}; use fedimint_ln_common::config::FeeToAmount; use fedimint_ln_common::lightning_invoice::{Bolt11Invoice, Bolt11InvoiceDescription, Description}; use fedimint_wallet_client::WalletClientModule; +use futures::future::join_all; use futures::{channel::mpsc::Sender, SinkExt}; use log::{error, trace}; use std::collections::HashMap; @@ -172,7 +174,6 @@ impl HarborCore { } let amount = Amount::from_msats(invoice.amount_milli_satoshis().expect("must have amount")); - // todo go through all clients and select the first one that has enough balance let client = self.get_client(federation_id).await.fedimint_client; let lightning_module = client .get_first_module::() @@ -293,13 +294,11 @@ impl HarborCore { address: Address, sats: Option, ) -> anyhow::Result<()> { - // todo go through all clients and select the first one that has enough balance let client = self.get_client(federation_id).await.fedimint_client; let onchain = client .get_first_module::() .expect("must have wallet module"); - // todo add manual fee selection let (fees, amount) = match sats { Some(sats) => { let amount = bitcoin::Amount::from_sat(sats); @@ -433,20 +432,35 @@ impl HarborCore { let clients = self.clients.read().await; // Tell the UI about any clients we have - clients - .values() - .map(|c| FederationItem { + join_all(clients.values().map(|c| async { + let balance = c.fedimint_client.get_balance().await; + let config = c.fedimint_client.config().await; + + let guardians: Vec = config + .global + .api_endpoints + .values() + .map(|url| url.name.clone()) + .collect(); + + let module_kinds = config + .modules + .into_values() + .map(|module_config| module_config.kind().to_owned()) + .collect::>(); + + FederationItem { id: c.fedimint_client.federation_id(), name: c .fedimint_client .get_meta("federation_name") .unwrap_or("Unknown".to_string()), - // TODO: get the balance per fedimint - balance: 420, - guardians: None, - module_kinds: None, - }) - .collect::>() + balance: balance.sats_round_down(), + guardians: Some(guardians), + module_kinds: Some(module_kinds), + } + })) + .await } pub async fn get_seed_words(&self) -> String { diff --git a/harbor-ui/src/main.rs b/harbor-ui/src/main.rs index 634ab4a..93522e9 100644 --- a/harbor-ui/src/main.rs +++ b/harbor-ui/src/main.rs @@ -448,8 +448,14 @@ impl HarborWallet { let amount = if self.is_max { None } else { - // TODO: error handling - Some(self.send_amount_input_str.parse::().unwrap()) + match self.send_amount_input_str.parse::() { + Ok(amount) => Some(amount), + Err(e) => { + eprintln!("Error parsing amount: {e}"); + self.send_failure_reason = Some(e.to_string()); + return Task::none(); + } + } }; Task::perform( Self::async_send_onchain( @@ -553,7 +559,7 @@ impl HarborWallet { UnlockStatus::Unlocking => Task::none(), _ => { self.unlock_failure_reason = None; - let id = Uuid::new_v4(); // todo use this id somewhere + let id = Uuid::new_v4(); Task::perform( Self::async_unlock(self.ui_handle.clone(), id, password), |_| Message::Noop, @@ -564,7 +570,7 @@ impl HarborWallet { UnlockStatus::Unlocking => Task::none(), _ => { self.unlock_failure_reason = None; - let id = Uuid::new_v4(); // todo use this id somewhere + let id = Uuid::new_v4(); Task::perform( Self::async_init(self.ui_handle.clone(), id, password), |_| Message::Noop, @@ -574,7 +580,7 @@ impl HarborWallet { Message::AddFederation(invite_code) => { let invite = InviteCode::from_str(&invite_code); if let Ok(invite) = invite { - let id = Uuid::new_v4(); // todo use this id somewhere + let id = Uuid::new_v4(); Task::perform( Self::async_add_federation(self.ui_handle.clone(), id, invite), |_| Message::Noop, @@ -629,7 +635,7 @@ impl HarborWallet { ]), Message::ShowSeedWords(show) => { if show { - let id = Uuid::new_v4(); // todo use this id somewhere + let id = Uuid::new_v4(); Task::perform( Self::async_get_seed_words(self.ui_handle.clone(), id), |_| Message::Noop, @@ -716,7 +722,6 @@ impl HarborWallet { }) } CoreUIMsg::FederationInfo(config) => { - // todo update the UI with the new config let id = config.calculate_federation_id(); let name = config.meta::("federation_name"); let guardians: Vec = config @@ -737,7 +742,6 @@ impl HarborWallet { _ => "Unknown".to_string(), }; - // TODO: what to do about balance in this case? Maybe it should be Option? let item = FederationItem { id, name,