@@ -27,7 +27,7 @@ use ldk_node::lightning::ln::msgs::SocketAddress;
2727use ldk_node:: lightning:: util:: logger:: Logger as _;
2828use ldk_node:: lightning:: { log_debug, log_error, log_info, log_trace, log_warn} ;
2929use ldk_node:: lightning_invoice:: Bolt11Invoice ;
30- use ldk_node:: payment:: { PaymentDirection , PaymentKind } ;
30+ use ldk_node:: payment:: { PaymentDetails , PaymentDirection , PaymentKind } ;
3131use ldk_node:: { BuildError , ChannelDetails , NodeError } ;
3232
3333use 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 ) ]
530553pub 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 {
17251744mod 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