99//!
1010//! [BOLT 12]: https://github.com/lightning/bolts/blob/master/12-offer-encoding.md
1111
12+ use std:: collections:: HashMap ;
1213use std:: num:: NonZeroU64 ;
13- use std:: sync:: { Arc , RwLock } ;
14+ use std:: sync:: { Arc , Mutex , RwLock } ;
1415use std:: time:: { Duration , SystemTime , UNIX_EPOCH } ;
1516
16- use lightning:: blinded_path:: message:: BlindedMessagePath ;
17+ use lightning:: blinded_path:: message:: { BlindedMessagePath , OffersContext } ;
1718use lightning:: ln:: channelmanager:: { OptionalOfferPaymentParams , PaymentId } ;
1819use lightning:: ln:: outbound_payment:: Retry ;
1920use lightning:: offers:: offer:: { Amount , Offer as LdkOffer , OfferFromHrn , Quantity } ;
@@ -51,6 +52,14 @@ type HumanReadableName = lightning::onion_message::dns_resolution::HumanReadable
5152#[ cfg( feature = "uniffi" ) ]
5253type HumanReadableName = Arc < crate :: ffi:: HumanReadableName > ;
5354
55+ /// Holds a pending BOLT12 invoice and its associated context, for use with manual invoice
56+ /// handling. See [`Config::manually_handle_bolt12_invoices`].
57+ ///
58+ /// [`Config::manually_handle_bolt12_invoices`]: crate::config::Config::manually_handle_bolt12_invoices
59+ pub ( crate ) type PendingBolt12InvoiceContexts = Arc <
60+ Mutex < HashMap < PaymentId , ( lightning:: offers:: invoice:: Bolt12Invoice , Option < OffersContext > ) > > ,
61+ > ;
62+
5463/// A payment handler allowing to create and pay [BOLT 12] offers and refunds.
5564///
5665/// Should be retrieved by calling [`Node::bolt12_payment`].
@@ -66,13 +75,15 @@ pub struct Bolt12Payment {
6675 is_running : Arc < RwLock < bool > > ,
6776 logger : Arc < Logger > ,
6877 async_payments_role : Option < AsyncPaymentsRole > ,
78+ pending_bolt12_invoice_contexts : PendingBolt12InvoiceContexts ,
6979}
7080
7181impl Bolt12Payment {
7282 pub ( crate ) fn new (
7383 channel_manager : Arc < ChannelManager > , keys_manager : Arc < KeysManager > ,
7484 payment_store : Arc < PaymentStore > , config : Arc < Config > , is_running : Arc < RwLock < bool > > ,
7585 logger : Arc < Logger > , async_payments_role : Option < AsyncPaymentsRole > ,
86+ pending_bolt12_invoice_contexts : PendingBolt12InvoiceContexts ,
7687 ) -> Self {
7788 Self {
7889 channel_manager,
@@ -82,6 +93,7 @@ impl Bolt12Payment {
8293 is_running,
8394 logger,
8495 async_payments_role,
96+ pending_bolt12_invoice_contexts,
8597 }
8698 }
8799
@@ -577,6 +589,70 @@ impl Bolt12Payment {
577589 ) -> Result < Vec < BlindedMessagePath > , Error > {
578590 self . blinded_paths_for_async_recipient_internal ( recipient_id)
579591 }
592+
593+ /// Pays a BOLT12 invoice that was previously received via an
594+ /// [`Event::Bolt12InvoiceReceived`] event.
595+ ///
596+ /// This is only relevant when [`Config::manually_handle_bolt12_invoices`] is set to `true`.
597+ ///
598+ /// Returns an [`Error::InvalidPaymentId`] if no pending invoice is found for the given
599+ /// `payment_id`.
600+ ///
601+ /// [`Event::Bolt12InvoiceReceived`]: crate::Event::Bolt12InvoiceReceived
602+ /// [`Config::manually_handle_bolt12_invoices`]: crate::config::Config::manually_handle_bolt12_invoices
603+ pub fn send_payment_for_bolt12_invoice ( & self , payment_id : PaymentId ) -> Result < ( ) , Error > {
604+ let ( invoice, context) = self
605+ . pending_bolt12_invoice_contexts
606+ . lock ( )
607+ . unwrap ( )
608+ . remove ( & payment_id)
609+ . ok_or ( Error :: InvalidPaymentId ) ?;
610+
611+ self . channel_manager . send_payment_for_bolt12_invoice ( & invoice, context. as_ref ( ) ) . map_err (
612+ |e| {
613+ log_error ! ( self . logger, "Failed to send payment for BOLT12 invoice: {:?}" , e) ;
614+ Error :: PaymentSendingFailed
615+ } ,
616+ ) ?;
617+
618+ log_info ! (
619+ self . logger,
620+ "Initiated payment for manually-handled BOLT12 invoice with payment_id {}" ,
621+ payment_id
622+ ) ;
623+ Ok ( ( ) )
624+ }
625+
626+ /// Abandons a BOLT12 invoice that was previously received via an
627+ /// [`Event::Bolt12InvoiceReceived`] event.
628+ ///
629+ /// This is only relevant when [`Config::manually_handle_bolt12_invoices`] is set to `true`.
630+ /// Use this to reject an invoice you don't want to pay. This will result in an
631+ /// [`Event::PaymentFailed`] being emitted.
632+ ///
633+ /// Returns an [`Error::InvalidPaymentId`] if no pending invoice is found for the given
634+ /// `payment_id`.
635+ ///
636+ /// [`Event::Bolt12InvoiceReceived`]: crate::Event::Bolt12InvoiceReceived
637+ /// [`Event::PaymentFailed`]: crate::Event::PaymentFailed
638+ /// [`Config::manually_handle_bolt12_invoices`]: crate::config::Config::manually_handle_bolt12_invoices
639+ pub fn abandon_bolt12_invoice ( & self , payment_id : PaymentId ) -> Result < ( ) , Error > {
640+ let _removed = self
641+ . pending_bolt12_invoice_contexts
642+ . lock ( )
643+ . unwrap ( )
644+ . remove ( & payment_id)
645+ . ok_or ( Error :: InvalidPaymentId ) ?;
646+
647+ self . channel_manager . abandon_payment ( payment_id) ;
648+
649+ log_info ! (
650+ self . logger,
651+ "Abandoned manually-handled BOLT12 invoice with payment_id {}" ,
652+ payment_id
653+ ) ;
654+ Ok ( ( ) )
655+ }
580656}
581657
582658#[ cfg( feature = "uniffi" ) ]
@@ -614,4 +690,68 @@ impl Bolt12Payment {
614690 paths. write ( & mut bytes) . or ( Err ( Error :: InvalidBlindedPaths ) ) ?;
615691 Ok ( bytes)
616692 }
693+
694+ /// Pays a BOLT12 invoice that was previously received via an
695+ /// [`Event::Bolt12InvoiceReceived`] event.
696+ ///
697+ /// This is only relevant when [`Config::manually_handle_bolt12_invoices`] is set to `true`.
698+ ///
699+ /// Returns an [`Error::InvalidPaymentId`] if no pending invoice is found for the given
700+ /// `payment_id`.
701+ ///
702+ /// [`Event::Bolt12InvoiceReceived`]: crate::Event::Bolt12InvoiceReceived
703+ /// [`Config::manually_handle_bolt12_invoices`]: crate::config::Config::manually_handle_bolt12_invoices
704+ pub fn send_payment_for_bolt12_invoice ( & self , payment_id : PaymentId ) -> Result < ( ) , Error > {
705+ let ( invoice, context) = self
706+ . pending_bolt12_invoice_contexts
707+ . lock ( )
708+ . unwrap ( )
709+ . remove ( & payment_id)
710+ . ok_or ( Error :: InvalidPaymentId ) ?;
711+
712+ self . channel_manager . send_payment_for_bolt12_invoice ( & invoice, context. as_ref ( ) ) . map_err (
713+ |e| {
714+ log_error ! ( self . logger, "Failed to send payment for BOLT12 invoice: {:?}" , e) ;
715+ Error :: PaymentSendingFailed
716+ } ,
717+ ) ?;
718+
719+ log_info ! (
720+ self . logger,
721+ "Initiated payment for manually-handled BOLT12 invoice with payment_id {}" ,
722+ payment_id
723+ ) ;
724+ Ok ( ( ) )
725+ }
726+
727+ /// Abandons a BOLT12 invoice that was previously received via an
728+ /// [`Event::Bolt12InvoiceReceived`] event.
729+ ///
730+ /// This is only relevant when [`Config::manually_handle_bolt12_invoices`] is set to `true`.
731+ /// Use this to reject an invoice you don't want to pay. This will result in an
732+ /// [`Event::PaymentFailed`] being emitted.
733+ ///
734+ /// Returns an [`Error::InvalidPaymentId`] if no pending invoice is found for the given
735+ /// `payment_id`.
736+ ///
737+ /// [`Event::Bolt12InvoiceReceived`]: crate::Event::Bolt12InvoiceReceived
738+ /// [`Event::PaymentFailed`]: crate::Event::PaymentFailed
739+ /// [`Config::manually_handle_bolt12_invoices`]: crate::config::Config::manually_handle_bolt12_invoices
740+ pub fn abandon_bolt12_invoice ( & self , payment_id : PaymentId ) -> Result < ( ) , Error > {
741+ let _removed = self
742+ . pending_bolt12_invoice_contexts
743+ . lock ( )
744+ . unwrap ( )
745+ . remove ( & payment_id)
746+ . ok_or ( Error :: InvalidPaymentId ) ?;
747+
748+ self . channel_manager . abandon_payment ( payment_id) ;
749+
750+ log_info ! (
751+ self . logger,
752+ "Abandoned manually-handled BOLT12 invoice with payment_id {}" ,
753+ payment_id
754+ ) ;
755+ Ok ( ( ) )
756+ }
617757}
0 commit comments