From 550c039a77dd8ab9075d72022da19cd2d8ce73a2 Mon Sep 17 00:00:00 2001 From: Restioson Date: Tue, 15 Aug 2023 17:18:52 +0200 Subject: [PATCH] Show JIT channel fee in wallet history --- coordinator/src/node/channel_opening_fee.rs | 11 +++++----- coordinator/src/routes.rs | 8 +------ crates/ln-dlc-node/src/channel.rs | 4 ++++ .../wallet/domain/wallet_history.dart | 20 +++++++++++++++--- .../features/wallet/wallet_history_item.dart | 21 +++++++++++++------ mobile/native/src/api.rs | 20 ++++++++++++++---- mobile/native/src/ln_dlc/mod.rs | 19 +++++++++++++---- 7 files changed, 73 insertions(+), 30 deletions(-) diff --git a/coordinator/src/node/channel_opening_fee.rs b/coordinator/src/node/channel_opening_fee.rs index d158e2e0e..d0a0c3369 100644 --- a/coordinator/src/node/channel_opening_fee.rs +++ b/coordinator/src/node/channel_opening_fee.rs @@ -6,6 +6,7 @@ use bitcoin::hashes::hex::ToHex; use bitcoin::secp256k1::ThirtyTwoByteHash; use lightning::ln::PaymentHash; use lightning_invoice::Invoice; +use ln_dlc_node::channel::JIT_FEE_INVOICE_DESCRIPTION_PREFIX; use ln_dlc_node::PaymentInfo; impl Node { @@ -13,14 +14,12 @@ impl Node { &self, amount: u64, funding_txid: String, - description: Option, expiry: Option, ) -> Result { - let invoice = self.inner.create_invoice( - amount, - description.unwrap_or_default(), - expiry.unwrap_or(180), - )?; + let description = format!("{JIT_FEE_INVOICE_DESCRIPTION_PREFIX}{funding_txid}"); + let invoice = self + .inner + .create_invoice(amount, description, expiry.unwrap_or(180))?; let payment_hash = invoice.payment_hash().into_32(); let payment_hash_hex = payment_hash.to_hex(); diff --git a/coordinator/src/routes.rs b/coordinator/src/routes.rs index 9c168a247..f6ad49a77 100644 --- a/coordinator/src/routes.rs +++ b/coordinator/src/routes.rs @@ -208,7 +208,6 @@ pub struct InvoiceParams { pub struct OpenChannelFeeInvoiceParams { pub amount: u64, pub channel_funding_txid: String, - pub description: Option, pub expiry: Option, } @@ -237,12 +236,7 @@ pub async fn get_open_channel_fee_invoice( ) -> Result { let invoice = state .node - .channel_opening_fee_invoice( - params.amount, - params.channel_funding_txid, - params.description, - params.expiry, - ) + .channel_opening_fee_invoice(params.amount, params.channel_funding_txid, params.expiry) .await .map_err(|e| AppError::InternalServerError(format!("Failed to create invoice: {e:#}")))?; diff --git a/crates/ln-dlc-node/src/channel.rs b/crates/ln-dlc-node/src/channel.rs index 6d9a551c9..ad0c8d3d4 100644 --- a/crates/ln-dlc-node/src/channel.rs +++ b/crates/ln-dlc-node/src/channel.rs @@ -14,6 +14,10 @@ use std::str::FromStr; use time::OffsetDateTime; use uuid::Uuid; +/// The prefix used in the description field of an JIT channel opening invoice to be paid by the +/// client. +pub const JIT_FEE_INVOICE_DESCRIPTION_PREFIX: &str = "jit-channel-fee-"; + /// We introduce a shadow copy of the Lightning channel as LDK deletes channels from its /// [`ChannelManager`] as soon as they are closed. /// diff --git a/mobile/lib/features/wallet/domain/wallet_history.dart b/mobile/lib/features/wallet/domain/wallet_history.dart index 5416d33a4..6ba2b3abd 100644 --- a/mobile/lib/features/wallet/domain/wallet_history.dart +++ b/mobile/lib/features/wallet/domain/wallet_history.dart @@ -2,7 +2,7 @@ import 'package:get_10101/common/domain/model.dart'; import 'payment_flow.dart'; import 'package:get_10101/bridge_generated/bridge_definitions.dart' as rust; -enum WalletHistoryItemDataType { lightning, onChain, trade, orderMatchingFee } +enum WalletHistoryItemDataType { lightning, onChain, trade, orderMatchingFee, jitChannelFee } enum WalletHistoryStatus { pending, confirmed } @@ -13,10 +13,10 @@ class WalletHistoryItemData { final WalletHistoryStatus status; final DateTime timestamp; - // on-chain + // on-chain (payment txid) and jit fee (funding txid) final String? txid; - // lightning + // lightning and jit fee final String? paymentHash; // trade @@ -78,6 +78,20 @@ class WalletHistoryItemData { orderId: type.orderId); } + if (item.walletType is rust.WalletType_JitChannelFee) { + rust.WalletType_JitChannelFee type = item.walletType as rust.WalletType_JitChannelFee; + + return WalletHistoryItemData( + flow: flow, + amount: amount, + type: WalletHistoryItemDataType.jitChannelFee, + status: status, + timestamp: timestamp, + paymentHash: type.paymentHash, + txid: type.fundingTxid, + ); + } + return WalletHistoryItemData( flow: flow, amount: amount, diff --git a/mobile/lib/features/wallet/wallet_history_item.dart b/mobile/lib/features/wallet/wallet_history_item.dart index 8663853f4..af5119022 100644 --- a/mobile/lib/features/wallet/wallet_history_item.dart +++ b/mobile/lib/features/wallet/wallet_history_item.dart @@ -34,7 +34,8 @@ class WalletHistoryItem extends StatelessWidget { Icons.bar_chart, size: flowIconSize, ); - } else if (data.type == WalletHistoryItemDataType.orderMatchingFee) { + } else if (data.type == WalletHistoryItemDataType.orderMatchingFee || + data.type == WalletHistoryItemDataType.jitChannelFee) { return const Icon( Icons.toll, size: flowIconSize, @@ -66,6 +67,8 @@ class WalletHistoryItem extends StatelessWidget { } case WalletHistoryItemDataType.orderMatchingFee: return "Matching fee"; + case WalletHistoryItemDataType.jitChannelFee: + return "Channel opening fee"; } }(); @@ -74,6 +77,7 @@ class WalletHistoryItem extends StatelessWidget { case WalletHistoryItemDataType.lightning: case WalletHistoryItemDataType.trade: case WalletHistoryItemDataType.orderMatchingFee: + case WalletHistoryItemDataType.jitChannelFee: return "off-chain"; case WalletHistoryItemDataType.onChain: return "on-chain"; @@ -158,16 +162,21 @@ class WalletHistoryItem extends StatelessWidget { } Widget showItemDetails(String title, BuildContext context) { - var [label, id] = () { + List details = () { switch (data.type) { case WalletHistoryItemDataType.lightning: - return ["Payment hash", data.paymentHash ?? ""]; + return [HistoryDetail(label: "Payment hash", value: data.paymentHash ?? "")]; case WalletHistoryItemDataType.onChain: - return ["Transaction id", data.txid ?? ""]; + return [HistoryDetail(label: "Transaction id", value: data.txid ?? "")]; case WalletHistoryItemDataType.trade: case WalletHistoryItemDataType.orderMatchingFee: final orderId = data.orderId!.substring(0, 8); - return ["Order", orderId]; + return [HistoryDetail(label: "Order", value: orderId)]; + case WalletHistoryItemDataType.jitChannelFee: + return [ + HistoryDetail(label: "Payment hash", value: data.paymentHash ?? ""), + HistoryDetail(label: "Funding transaction id", value: data.txid ?? "") + ]; } }(); @@ -185,7 +194,7 @@ class WalletHistoryItem extends StatelessWidget { content: Column( mainAxisSize: MainAxisSize.min, children: [ - HistoryDetail(label: label, value: id), + ...details, HistoryDetail( label: "Amount", value: formatSats(Amount(data.amount.sats * directionMultiplier))), HistoryDetail(label: "Date and time", value: dateFormat.format(data.timestamp)), diff --git a/mobile/native/src/api.rs b/mobile/native/src/api.rs index fdaedabab..48c4ad558 100644 --- a/mobile/native/src/api.rs +++ b/mobile/native/src/api.rs @@ -71,10 +71,22 @@ pub struct WalletHistoryItem { #[derive(Clone, Debug)] pub enum WalletType { - OnChain { txid: String }, - Lightning { payment_hash: String }, - Trade { order_id: String }, - OrderMatchingFee { order_id: String }, + OnChain { + txid: String, + }, + Lightning { + payment_hash: String, + }, + Trade { + order_id: String, + }, + OrderMatchingFee { + order_id: String, + }, + JitChannelFee { + funding_txid: String, + payment_hash: String, + }, } #[derive(Clone, Debug, Default)] diff --git a/mobile/native/src/ln_dlc/mod.rs b/mobile/native/src/ln_dlc/mod.rs index f01cd14fb..b99497535 100644 --- a/mobile/native/src/ln_dlc/mod.rs +++ b/mobile/native/src/ln_dlc/mod.rs @@ -31,6 +31,7 @@ use itertools::Itertools; use lightning::ln::channelmanager::ChannelDetails; use lightning::util::events::Event; use lightning_invoice::Invoice; +use ln_dlc_node::channel::JIT_FEE_INVOICE_DESCRIPTION_PREFIX; use ln_dlc_node::config::app_config; use ln_dlc_node::node::rust_dlc_manager::subchannel::LNChannelManager; use ln_dlc_node::node::rust_dlc_manager::ChannelId; @@ -348,11 +349,21 @@ fn keep_wallet_balance_and_history_up_to_date(node: &Node) -> Result<()> { let payment_hash = hex::encode(details.payment_hash.0); let description = &details.description; - let wallet_type = match description.strip_prefix(FEE_INVOICE_DESCRIPTION_PREFIX_TAKER) { - Some(order_id) => api::WalletType::OrderMatchingFee { + let wallet_type = if let Some(order_id) = + description.strip_prefix(FEE_INVOICE_DESCRIPTION_PREFIX_TAKER) + { + api::WalletType::OrderMatchingFee { order_id: order_id.to_string(), - }, - None => api::WalletType::Lightning { payment_hash }, + } + } else if let Some(funding_txid) = + description.strip_prefix(JIT_FEE_INVOICE_DESCRIPTION_PREFIX) + { + api::WalletType::JitChannelFee { + funding_txid: funding_txid.to_string(), + payment_hash, + } + } else { + api::WalletType::Lightning { payment_hash } }; Some(api::WalletHistoryItem {