diff --git a/src/bridge.rs b/src/bridge.rs index bdf7b00..746ab59 100644 --- a/src/bridge.rs +++ b/src/bridge.rs @@ -1,3 +1,4 @@ +use bitcoin::Txid; use fedimint_core::api::InviteCode; use fedimint_core::Amount; use fedimint_ln_common::lightning_invoice::Bolt11Invoice; @@ -5,22 +6,32 @@ use tokio::sync::mpsc; #[derive(Debug, Clone)] pub enum UICoreMsg { - Test(u64), - FakeSend(u64), - Send(Bolt11Invoice), - Receive(u64), + SendLightning(Bolt11Invoice), + ReceiveLightning(Amount), AddFederation(InviteCode), Unlock(String), } +#[derive(Debug, Clone, PartialEq)] +pub enum SendSuccessMsg { + Lightning { preimage: [u8; 32] }, + Onchain { txid: Txid }, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum ReceiveSuccessMsg { + Lightning, + Onchain { txid: Txid }, +} + #[derive(Debug, Clone)] pub enum CoreUIMsg { Sending, - SendSuccess, + SendSuccess(SendSuccessMsg), SendFailure(String), ReceiveInvoiceGenerating, ReceiveInvoiceGenerated(Bolt11Invoice), - ReceiveSuccess, + ReceiveSuccess(ReceiveSuccessMsg), ReceiveFailed(String), BalanceUpdated(Amount), AddFederationFailed(String), @@ -45,16 +56,12 @@ impl UIHandle { self.ui_to_core_tx.send(msg).await.unwrap(); } - pub async fn fake_send(&self, amount: u64) { - self.msg_send(UICoreMsg::FakeSend(amount)).await; - } - pub async fn send(&self, invoice: Bolt11Invoice) { - self.msg_send(UICoreMsg::Send(invoice)).await; + self.msg_send(UICoreMsg::SendLightning(invoice)).await; } pub async fn receive(&self, amount: u64) { - self.msg_send(UICoreMsg::Receive(amount)).await; + self.msg_send(UICoreMsg::ReceiveLightning(Amount::from_sats(amount))).await; } pub async fn unlock(&self, password: String) { diff --git a/src/core.rs b/src/core.rs index fb0a84e..8ac4c10 100644 --- a/src/core.rs +++ b/src/core.rs @@ -10,7 +10,7 @@ use std::collections::HashMap; use std::path::PathBuf; use std::str::FromStr; use std::sync::atomic::AtomicBool; -use std::{sync::Arc, time::Duration}; +use std::sync::Arc; use iced::{ futures::{channel::mpsc::Sender, SinkExt}, @@ -18,7 +18,6 @@ use iced::{ }; use log::error; use tokio::sync::RwLock; -use tokio::time::sleep; use crate::{ bridge::{self, CoreUIMsg, UICoreMsg}, @@ -64,32 +63,12 @@ impl HarborCore { self.msg(CoreUIMsg::BalanceUpdated(self.balance)).await; } - async fn fake_send(&mut self, amount: u64) { - self.msg(CoreUIMsg::Sending).await; - sleep(Duration::from_secs(1)).await; - println!("Sending {amount}"); - - let amount = Amount::from_sats(amount); - if amount > self.balance { - self.msg(CoreUIMsg::SendFailure("Insufficient funds".to_string())) - .await; - return; - } - - // Save it in our struct - self.balance = self.balance.saturating_sub(amount); - // Tell the UI we did a good job - self.msg(CoreUIMsg::SendSuccess).await; - // Tell the UI the new balance - self.msg(CoreUIMsg::BalanceUpdated(self.balance)).await; - } - // todo for now just use the first client, but eventually we'll want to have a way to select a client async fn get_client(&self) -> FedimintClient { self.clients.read().await.values().next().unwrap().clone() } - async fn send(&self, invoice: Bolt11Invoice) -> anyhow::Result<()> { + async fn send_lightning(&self, invoice: Bolt11Invoice) -> anyhow::Result<()> { // todo go through all clients and select the first one that has enough balance let client = self.get_client().await.fedimint_client; let lightning_module = client.get_first_module::(); @@ -118,7 +97,7 @@ impl HarborCore { Ok(()) } - async fn receive(&self, amount: u64) -> anyhow::Result { + async fn receive_lightning(&self, amount: Amount) -> anyhow::Result { let client = self.get_client().await.fedimint_client; let lightning_module = client.get_first_module::(); @@ -129,7 +108,7 @@ impl HarborCore { let desc = Description::new(String::new()).expect("empty string is valid"); let (op_id, invoice, _) = lightning_module .create_bolt11_invoice( - Amount::from_sats(amount), + amount, Bolt11InvoiceDescription::Direct(&desc), None, (), @@ -223,7 +202,7 @@ pub fn run_core() -> Subscription { balance += client.fedimint_client.get_balance().await; } - let mut core = HarborCore { + let core = HarborCore { balance, tx, mnemonic, @@ -248,24 +227,17 @@ pub fn run_core() -> Subscription { if let Some(msg) = msg { match msg { - UICoreMsg::Test(counter) => { - println!("{counter}"); - } - UICoreMsg::FakeSend(amount) => { - core.fake_send(amount).await; - } - UICoreMsg::Send(invoice) => { + UICoreMsg::SendLightning(invoice) => { log::info!("Got UICoreMsg::Send"); core.msg(CoreUIMsg::Sending).await; - if let Err(e) = core.send(invoice).await { + if let Err(e) = core.send_lightning(invoice).await { error!("Error sending: {e}"); core.msg(CoreUIMsg::SendFailure(e.to_string())).await; } - core.msg(CoreUIMsg::SendSuccess).await; } - UICoreMsg::Receive(amount) => { + UICoreMsg::ReceiveLightning(amount) => { core.msg(CoreUIMsg::ReceiveInvoiceGenerating).await; - match core.receive(amount).await { + match core.receive_lightning(amount).await { Err(e) => { core.msg(CoreUIMsg::ReceiveFailed(e.to_string())).await; } diff --git a/src/fedimint_client.rs b/src/fedimint_client.rs index 4bc8673..1adae92 100644 --- a/src/fedimint_client.rs +++ b/src/fedimint_client.rs @@ -1,6 +1,7 @@ -use crate::bridge::CoreUIMsg; +use crate::bridge::{CoreUIMsg, ReceiveSuccessMsg, SendSuccessMsg}; use crate::Message; use bip39::Mnemonic; +use bitcoin::hashes::hex::FromHex; use bitcoin::Network; use fedimint_bip39::Bip39RootSecretStrategy; use fedimint_client::oplog::UpdateStreamOrOutcome; @@ -204,7 +205,9 @@ pub(crate) async fn spawn_invoice_receive_subscription( LnReceiveState::Claimed => { info!("Payment claimed"); sender - .send(Message::CoreMessage(CoreUIMsg::ReceiveSuccess)) + .send(Message::CoreMessage(CoreUIMsg::ReceiveSuccess( + ReceiveSuccessMsg::Lightning, + ))) .await .unwrap(); @@ -247,10 +250,13 @@ pub(crate) async fn spawn_invoice_payment_subscription( .await .unwrap(); } - LnPayState::Success { preimage: _ } => { + LnPayState::Success { preimage } => { info!("Payment success"); + let preimage: [u8; 32] = + FromHex::from_hex(&preimage).expect("Invalid preimage"); + let params = SendSuccessMsg::Lightning { preimage }; sender - .send(Message::CoreMessage(CoreUIMsg::SendSuccess)) + .send(Message::CoreMessage(CoreUIMsg::SendSuccess(params))) .await .unwrap(); @@ -293,10 +299,13 @@ pub(crate) async fn spawn_internal_payment_subscription( .await .unwrap(); } - InternalPayState::Preimage(_preimage) => { + InternalPayState::Preimage(preimage) => { info!("Payment success"); + let params = SendSuccessMsg::Lightning { + preimage: preimage.0, + }; sender - .send(Message::CoreMessage(CoreUIMsg::SendSuccess)) + .send(Message::CoreMessage(CoreUIMsg::SendSuccess(params))) .await .unwrap(); diff --git a/src/main.rs b/src/main.rs index e094073..6747ba5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ use iced::widget::row; use iced::Element; use iced::{clipboard, program, Color}; use iced::{Command, Font}; +use log::info; use crate::components::focus_input_id; @@ -138,16 +139,6 @@ impl HarborWallet { run_core() } - // We can't use self in these async functions because lifetimes are hard - #[allow(dead_code)] // TODO: remove - async fn async_fake_send(ui_handle: Option>, amount: u64) { - if let Some(ui_handle) = ui_handle { - ui_handle.clone().fake_send(amount).await; - } else { - panic!("UI handle is None"); - } - } - async fn async_send(ui_handle: Option>, invoice: Bolt11Invoice) { println!("Got to async_send"); if let Some(ui_handle) = ui_handle { @@ -273,7 +264,8 @@ impl HarborWallet { self.send_status = SendStatus::Sending; Command::none() } - CoreUIMsg::SendSuccess => { + CoreUIMsg::SendSuccess(params) => { + info!("Send success: {params:?}"); self.send_status = SendStatus::Idle; Command::none() } @@ -282,11 +274,14 @@ impl HarborWallet { self.send_failure_reason = Some(reason); Command::none() } - CoreUIMsg::ReceiveSuccess => Command::none(), + CoreUIMsg::ReceiveSuccess(params) => { + info!("Receive success: {params:?}"); + self.receive_status = ReceiveStatus::Idle; + Command::none() + }, CoreUIMsg::ReceiveFailed(reason) => { - // todo use receive failure reason - self.send_status = SendStatus::Idle; - self.send_failure_reason = Some(reason); + self.receive_status = ReceiveStatus::Idle; + self.receive_failure_reason = Some(reason); Command::none() } CoreUIMsg::BalanceUpdated(balance) => {