Skip to content

Commit 4e9d230

Browse files
authored
Merge pull request #85 from lightningdevkit/on-chain-conf-txs
List pending on-chain receives
2 parents f532b30 + 12bb19d commit 4e9d230

1 file changed

Lines changed: 88 additions & 15 deletions

File tree

orange-sdk/src/lib.rs

Lines changed: 88 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use ldk_node::lightning::ln::msgs::SocketAddress;
2727
use ldk_node::lightning::util::logger::Logger as _;
2828
use ldk_node::lightning::{log_debug, log_error, log_info, log_trace, log_warn};
2929
use ldk_node::lightning_invoice::Bolt11Invoice;
30-
use ldk_node::payment::{PaymentDirection, PaymentKind};
30+
use ldk_node::payment::{PaymentDetails, PaymentDirection, PaymentKind};
3131
use ldk_node::{BuildError, ChannelDetails, NodeError};
3232

3333
use crate::dyn_store::DynStore;
@@ -525,6 +525,29 @@ impl From<NodeError> for WalletError {
525525
}
526526
}
527527

528+
fn should_surface_lightning_payment_without_metadata(status: TxStatus, kind: &PaymentKind) -> bool {
529+
status == TxStatus::Completed || matches!(kind, PaymentKind::Onchain { .. })
530+
}
531+
532+
fn lightning_payment_without_metadata_to_transaction(
533+
payment: &PaymentDetails, fee: Option<Amount>,
534+
) -> Option<Transaction> {
535+
let status = payment.status.into();
536+
if !should_surface_lightning_payment_without_metadata(status, &payment.kind) {
537+
return None;
538+
}
539+
540+
Some(Transaction {
541+
id: PaymentId::SelfCustodial(payment.id.0),
542+
status,
543+
outbound: payment.direction == PaymentDirection::Outbound,
544+
amount: payment.amount_msat.map(|a| Amount::from_milli_sats(a).unwrap()),
545+
fee,
546+
payment_type: payment.into(),
547+
time_since_epoch: Duration::from_secs(payment.latest_update_timestamp),
548+
})
549+
}
550+
528551
/// Represents a single-use Bitcoin URI for receiving payments.
529552
#[derive(Debug, Clone, PartialEq, Eq)]
530553
pub struct SingleUseReceiveUri {
@@ -1031,22 +1054,18 @@ impl Wallet {
10311054
payment.id
10321055
);
10331056

1034-
let status = payment.status.into();
1035-
if status != TxStatus::Completed {
1036-
// We don't bother to surface pending inbound transactions (i.e. issued but
1037-
// unpaid invoices) in our transaction list, in part because these may be
1038-
// failed rebalances.
1057+
if let Some(transaction) =
1058+
lightning_payment_without_metadata_to_transaction(&payment, fee)
1059+
{
1060+
res.push(transaction)
1061+
} else {
1062+
// We don't bother to surface pending inbound Lightning transactions (i.e.
1063+
// issued but unpaid invoices) in our transaction list, in part because these
1064+
// may be failed rebalances. On-chain payments, however, only exist once the
1065+
// transaction has been observed on-chain or in the mempool, so surface them
1066+
// with their real pending status.
10391067
continue;
10401068
}
1041-
res.push(Transaction {
1042-
id: PaymentId::SelfCustodial(payment.id.0),
1043-
status,
1044-
outbound: payment.direction == PaymentDirection::Outbound,
1045-
amount: payment.amount_msat.map(|a| Amount::from_milli_sats(a).unwrap()),
1046-
fee,
1047-
payment_type: (&payment).into(),
1048-
time_since_epoch: Duration::from_secs(payment.latest_update_timestamp),
1049-
})
10501069
}
10511070
}
10521071

@@ -1725,6 +1744,10 @@ impl Wallet {
17251744
mod tests {
17261745
use super::*;
17271746
use ldk_node::bip39::Mnemonic;
1747+
use ldk_node::bitcoin::Txid;
1748+
use ldk_node::lightning::ln::channelmanager::PaymentId as LightningPaymentId;
1749+
use ldk_node::lightning::types::payment::PaymentHash;
1750+
use ldk_node::payment::{ConfirmationStatus, PaymentStatus};
17281751

17291752
#[test]
17301753
fn seed_debug_redacts_seed64_bytes() {
@@ -1744,4 +1767,54 @@ mod tests {
17441767
assert!(!debug.contains("abandon"));
17451768
assert!(!debug.contains("test passphrase"));
17461769
}
1770+
1771+
#[test]
1772+
fn pending_onchain_lightning_payments_without_metadata_are_listed() {
1773+
let kind = PaymentKind::Onchain {
1774+
txid: Txid::from_byte_array([42; 32]),
1775+
status: ConfirmationStatus::Unconfirmed,
1776+
};
1777+
1778+
assert!(should_surface_lightning_payment_without_metadata(TxStatus::Pending, &kind));
1779+
}
1780+
1781+
#[test]
1782+
fn pending_onchain_lightning_payment_without_metadata_becomes_transaction() {
1783+
let txid = Txid::from_byte_array([42; 32]);
1784+
let payment = PaymentDetails {
1785+
id: LightningPaymentId([24; 32]),
1786+
kind: PaymentKind::Onchain { txid, status: ConfirmationStatus::Unconfirmed },
1787+
amount_msat: Some(123_000),
1788+
fee_paid_msat: None,
1789+
direction: PaymentDirection::Inbound,
1790+
status: PaymentStatus::Pending,
1791+
latest_update_timestamp: 456,
1792+
};
1793+
1794+
let transaction =
1795+
lightning_payment_without_metadata_to_transaction(&payment, Some(Amount::ZERO))
1796+
.expect("pending on-chain payments should be surfaced");
1797+
1798+
assert_eq!(transaction.id, PaymentId::SelfCustodial([24; 32]));
1799+
assert_eq!(transaction.status, TxStatus::Pending);
1800+
assert!(!transaction.outbound);
1801+
assert_eq!(transaction.amount, Some(Amount::from_sats(123).expect("valid amount")));
1802+
assert_eq!(transaction.fee, Some(Amount::ZERO));
1803+
assert_eq!(transaction.payment_type, PaymentType::IncomingOnChain { txid: Some(txid) });
1804+
assert_eq!(transaction.time_since_epoch, Duration::from_secs(456));
1805+
}
1806+
1807+
#[test]
1808+
fn pending_non_onchain_lightning_payments_without_metadata_are_hidden() {
1809+
let kind = PaymentKind::Spontaneous { hash: PaymentHash([42; 32]), preimage: None };
1810+
1811+
assert!(!should_surface_lightning_payment_without_metadata(TxStatus::Pending, &kind));
1812+
}
1813+
1814+
#[test]
1815+
fn completed_lightning_payments_without_metadata_are_listed() {
1816+
let kind = PaymentKind::Spontaneous { hash: PaymentHash([42; 32]), preimage: None };
1817+
1818+
assert!(should_surface_lightning_payment_without_metadata(TxStatus::Completed, &kind));
1819+
}
17471820
}

0 commit comments

Comments
 (0)