From 7a434156e5073aa498fc4cde7d0f67c03b801ce8 Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Tue, 28 May 2024 14:58:34 +0200 Subject: [PATCH] feat: Handle error when requesting a hodl invoice If we can't receive a hodl invoice the app gracefully handles that scenario and shows an according message instead of the invoice. --- .../trade/application/order_service.dart | 4 ++-- .../channel_funding_screen.dart | 13 +++++++++---- mobile/native/src/hodl_invoice.rs | 1 + .../native/src/unfunded_channel_opening_order.rs | 16 +++++++++++----- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/mobile/lib/features/trade/application/order_service.dart b/mobile/lib/features/trade/application/order_service.dart index 712c5baf4..6b354790d 100644 --- a/mobile/lib/features/trade/application/order_service.dart +++ b/mobile/lib/features/trade/application/order_service.dart @@ -7,9 +7,9 @@ import 'package:get_10101/ffi.dart' as rust; class ExternalFunding { final String bitcoinAddress; - final String paymentRequest; + final String? paymentRequest; - const ExternalFunding({required this.bitcoinAddress, required this.paymentRequest}); + const ExternalFunding({required this.bitcoinAddress, this.paymentRequest}); static ExternalFunding fromApi(rust.ExternalFunding funding) { return ExternalFunding( diff --git a/mobile/lib/features/trade/channel_creation_flow/channel_funding_screen.dart b/mobile/lib/features/trade/channel_creation_flow/channel_funding_screen.dart index 8aa99cea2..0888a02c1 100644 --- a/mobile/lib/features/trade/channel_creation_flow/channel_funding_screen.dart +++ b/mobile/lib/features/trade/channel_creation_flow/channel_funding_screen.dart @@ -67,8 +67,12 @@ class _ChannelFunding extends State { final qrCode = switch (selectedBox) { FundingType.lightning => CustomQrCode( - data: widget.funding.paymentRequest, - embeddedImage: const AssetImage("assets/10101_logo_icon_white_background.png"), + data: widget.funding.paymentRequest ?? "https://x.com/get10101", + embeddedImage: widget.funding.paymentRequest != null + ? const AssetImage("assets/10101_logo_icon_white_background.png") + : const AssetImage("assets/coming_soon.png"), + embeddedImageSizeHeight: widget.funding.paymentRequest != null ? 50 : 350, + embeddedImageSizeWidth: widget.funding.paymentRequest != null ? 50 : 350, dimension: 300, ), FundingType.onchain => CustomQrCode( @@ -87,9 +91,10 @@ class _ChannelFunding extends State { }; final qrCodeSubTitle = switch (selectedBox) { - FundingType.lightning => widget.funding.paymentRequest, + FundingType.lightning => + widget.funding.paymentRequest ?? "Currently not available. Try again later.", FundingType.onchain => widget.funding.bitcoinAddress, - FundingType.unified || FundingType.external => "Follow us on social media for updates", + FundingType.unified || FundingType.external => "Follow us on social media for updates.", }; return Scaffold( diff --git a/mobile/native/src/hodl_invoice.rs b/mobile/native/src/hodl_invoice.rs index 94f0f5ff0..6a531f217 100644 --- a/mobile/native/src/hodl_invoice.rs +++ b/mobile/native/src/hodl_invoice.rs @@ -7,6 +7,7 @@ use bitcoin::Amount; use reqwest::Url; use xxi_node::commons; +#[derive(Clone)] pub struct HodlInvoice { pub payment_request: String, pub pre_image: String, diff --git a/mobile/native/src/unfunded_channel_opening_order.rs b/mobile/native/src/unfunded_channel_opening_order.rs index 58474181a..684644131 100644 --- a/mobile/native/src/unfunded_channel_opening_order.rs +++ b/mobile/native/src/unfunded_channel_opening_order.rs @@ -12,7 +12,8 @@ use xxi_node::commons::ChannelOpeningParams; pub struct ExternalFunding { pub bitcoin_address: String, - pub payment_request: String, + /// The payment request of the hodl invoice. Could be none if the lnd node is down. + pub payment_request: Option, } /// handles orders which would open a channel where the user does not have funds in his wallets @@ -39,8 +40,12 @@ pub async fn submit_unfunded_channel_opening_order( + crate::dlc::estimated_funding_tx_fee()?; let funding_amount = Amount::from_sat(estimated_margin + trader_reserve) + fees; - let hodl_invoice = hodl_invoice::get_hodl_invoice_from_coordinator(funding_amount).await?; - let pre_image = hodl_invoice.pre_image; + let hodl_invoice = hodl_invoice::get_hodl_invoice_from_coordinator(funding_amount) + .await + .inspect_err(|e| tracing::error!("Failed to get hodl invoice. Error: {e:#}")) + .ok(); + + let payment_request = hodl_invoice.clone().map(|invoice| invoice.payment_request); // abort previous watcher before starting new task. abort_watcher().await?; @@ -48,6 +53,7 @@ pub async fn submit_unfunded_channel_opening_order( let runtime = crate::state::get_or_create_tokio_runtime()?; let watch_handle = runtime.spawn({ let bitcoin_address = bitcoin_address.clone(); + let pre_image = hodl_invoice.map(|invoice| invoice.pre_image); async move { event::publish(&EventInternal::FundingChannelNotification( FundingChannelTask::Pending, @@ -63,7 +69,7 @@ pub async fn submit_unfunded_channel_opening_order( _ = watcher::watch_lightning_payment() => { // received lightning payment. tracing::info!(%funding_amount, "Found lighting payment."); - Some(pre_image) + pre_image } }; @@ -109,7 +115,7 @@ pub async fn submit_unfunded_channel_opening_order( Ok(ExternalFunding { bitcoin_address: bitcoin_address.to_string(), - payment_request: hodl_invoice.payment_request, + payment_request, }) }