@@ -22,17 +22,20 @@ use bitcoin::hashes::Hash;
2222use bitcoin:: secp256k1:: PublicKey ;
2323pub use bitcoin:: { Address , BlockHash , FeeRate , Network , OutPoint , ScriptBuf , Txid } ;
2424pub use lightning:: chain:: channelmonitor:: BalanceSource ;
25+ use lightning:: events:: PaidBolt12Invoice as LdkPaidBolt12Invoice ;
2526pub use lightning:: events:: { ClosureReason , PaymentFailureReason } ;
2627use lightning:: ln:: channelmanager:: PaymentId ;
28+ use lightning:: ln:: msgs:: DecodeError ;
2729pub use lightning:: ln:: types:: ChannelId ;
2830use lightning:: offers:: invoice:: Bolt12Invoice as LdkBolt12Invoice ;
2931pub use lightning:: offers:: offer:: OfferId ;
3032use lightning:: offers:: offer:: { Amount as LdkAmount , Offer as LdkOffer } ;
3133use lightning:: offers:: refund:: Refund as LdkRefund ;
34+ use lightning:: offers:: static_invoice:: StaticInvoice as LdkStaticInvoice ;
3235use lightning:: onion_message:: dns_resolution:: HumanReadableName as LdkHumanReadableName ;
3336pub use lightning:: routing:: gossip:: { NodeAlias , NodeId , RoutingFees } ;
3437pub use lightning:: routing:: router:: RouteParametersConfig ;
35- use lightning:: util:: ser:: Writeable ;
38+ use lightning:: util:: ser:: { Readable , Writeable , Writer } ;
3639use lightning_invoice:: { Bolt11Invoice as LdkBolt11Invoice , Bolt11InvoiceDescriptionRef } ;
3740pub use lightning_invoice:: { Description , SignedRawBolt11Invoice } ;
3841pub use lightning_liquidity:: lsps0:: ser:: LSPSDateTime ;
@@ -686,6 +689,170 @@ impl AsRef<LdkBolt12Invoice> for Bolt12Invoice {
686689 }
687690}
688691
692+ /// A `StaticInvoice` is used for async payments where the recipient may be offline.
693+ ///
694+ /// Unlike [`Bolt12Invoice`], a `StaticInvoice` does not support proof of payment
695+ /// because the payment hash is not derived from a preimage known only to the recipient.
696+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
697+ pub struct StaticInvoice {
698+ pub ( crate ) inner : LdkStaticInvoice ,
699+ }
700+
701+ impl StaticInvoice {
702+ pub fn from_str ( invoice_str : & str ) -> Result < Self , Error > {
703+ invoice_str. parse ( )
704+ }
705+
706+ /// Returns the [`OfferId`] of the underlying [`Offer`] this invoice corresponds to.
707+ ///
708+ /// [`Offer`]: lightning::offers::offer::Offer
709+ pub fn offer_id ( & self ) -> OfferId {
710+ OfferId ( self . inner . offer_id ( ) . 0 )
711+ }
712+
713+ /// Whether the offer this invoice corresponds to has expired.
714+ pub fn is_offer_expired ( & self ) -> bool {
715+ self . inner . is_offer_expired ( )
716+ }
717+
718+ /// A typically transient public key corresponding to the key used to sign the invoice.
719+ pub fn signing_pubkey ( & self ) -> PublicKey {
720+ self . inner . signing_pubkey ( )
721+ }
722+
723+ /// The public key used by the recipient to sign invoices.
724+ pub fn issuer_signing_pubkey ( & self ) -> Option < PublicKey > {
725+ self . inner . issuer_signing_pubkey ( )
726+ }
727+
728+ /// A complete description of the purpose of the originating offer.
729+ pub fn invoice_description ( & self ) -> Option < String > {
730+ self . inner . description ( ) . map ( |printable| printable. to_string ( ) )
731+ }
732+
733+ /// The issuer of the offer.
734+ pub fn issuer ( & self ) -> Option < String > {
735+ self . inner . issuer ( ) . map ( |printable| printable. to_string ( ) )
736+ }
737+
738+ /// The minimum amount required for a successful payment of a single item.
739+ pub fn amount ( & self ) -> Option < OfferAmount > {
740+ self . inner . amount ( ) . map ( |amount| amount. into ( ) )
741+ }
742+
743+ /// The chain that must be used when paying the invoice.
744+ pub fn chain ( & self ) -> Vec < u8 > {
745+ self . inner . chain ( ) . to_bytes ( ) . to_vec ( )
746+ }
747+
748+ /// Opaque bytes set by the originating [`Offer`].
749+ ///
750+ /// [`Offer`]: lightning::offers::offer::Offer
751+ pub fn metadata ( & self ) -> Option < Vec < u8 > > {
752+ self . inner . metadata ( ) . cloned ( )
753+ }
754+
755+ /// Seconds since the Unix epoch when an invoice should no longer be requested.
756+ ///
757+ /// If `None`, the offer does not expire.
758+ pub fn absolute_expiry_seconds ( & self ) -> Option < u64 > {
759+ self . inner . absolute_expiry ( ) . map ( |duration| duration. as_secs ( ) )
760+ }
761+
762+ /// Writes `self` out to a `Vec<u8>`.
763+ pub fn encode ( & self ) -> Vec < u8 > {
764+ self . inner . encode ( )
765+ }
766+ }
767+
768+ impl std:: str:: FromStr for StaticInvoice {
769+ type Err = Error ;
770+
771+ fn from_str ( invoice_str : & str ) -> Result < Self , Self :: Err > {
772+ if let Some ( bytes_vec) = hex_utils:: to_vec ( invoice_str) {
773+ if let Ok ( invoice) = LdkStaticInvoice :: try_from ( bytes_vec) {
774+ return Ok ( StaticInvoice { inner : invoice } ) ;
775+ }
776+ }
777+ Err ( Error :: InvalidInvoice )
778+ }
779+ }
780+
781+ impl From < LdkStaticInvoice > for StaticInvoice {
782+ fn from ( invoice : LdkStaticInvoice ) -> Self {
783+ StaticInvoice { inner : invoice }
784+ }
785+ }
786+
787+ impl Deref for StaticInvoice {
788+ type Target = LdkStaticInvoice ;
789+ fn deref ( & self ) -> & Self :: Target {
790+ & self . inner
791+ }
792+ }
793+
794+ impl AsRef < LdkStaticInvoice > for StaticInvoice {
795+ fn as_ref ( & self ) -> & LdkStaticInvoice {
796+ self . deref ( )
797+ }
798+ }
799+
800+ /// Represents a BOLT12 invoice that was paid.
801+ ///
802+ /// This is used in [`Event::PaymentSuccessful`] to provide proof of payment for BOLT12 payments.
803+ ///
804+ /// Note: Due to UniFFI limitations with Object types in enum variants, this is exposed as a
805+ /// struct with optional fields. Check which field is `Some` to determine the invoice type:
806+ /// - `bolt12_invoice`: A standard BOLT12 invoice (supports proof of payment)
807+ /// - `static_invoice`: A static invoice for async payments (does NOT support proof of payment)
808+ ///
809+ /// [`Event::PaymentSuccessful`]: crate::Event::PaymentSuccessful
810+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
811+ pub struct PaidBolt12Invoice {
812+ /// The paid BOLT12 invoice, if this is a regular BOLT12 invoice.
813+ pub bolt12_invoice : Option < Arc < Bolt12Invoice > > ,
814+ /// The paid static invoice, if this is a static invoice (async payment).
815+ pub static_invoice : Option < Arc < StaticInvoice > > ,
816+ }
817+
818+ impl From < LdkPaidBolt12Invoice > for PaidBolt12Invoice {
819+ fn from ( ldk_invoice : LdkPaidBolt12Invoice ) -> Self {
820+ match ldk_invoice {
821+ LdkPaidBolt12Invoice :: Bolt12Invoice ( invoice) => PaidBolt12Invoice {
822+ bolt12_invoice : Some ( Arc :: new ( Bolt12Invoice { inner : invoice } ) ) ,
823+ static_invoice : None ,
824+ } ,
825+ LdkPaidBolt12Invoice :: StaticInvoice ( invoice) => PaidBolt12Invoice {
826+ bolt12_invoice : None ,
827+ static_invoice : Some ( Arc :: new ( StaticInvoice { inner : invoice } ) ) ,
828+ } ,
829+ }
830+ }
831+ }
832+
833+ impl Writeable for PaidBolt12Invoice {
834+ fn write < W : Writer > ( & self , writer : & mut W ) -> Result < ( ) , lightning:: io:: Error > {
835+ // Convert our struct back to LDK's enum and delegate serialization
836+ let ldk_invoice: LdkPaidBolt12Invoice = if let Some ( inv) = & self . bolt12_invoice {
837+ LdkPaidBolt12Invoice :: Bolt12Invoice ( inv. inner . clone ( ) )
838+ } else if let Some ( inv) = & self . static_invoice {
839+ LdkPaidBolt12Invoice :: StaticInvoice ( inv. inner . clone ( ) )
840+ } else {
841+ // This should never happen as PaidBolt12Invoice always has one variant set
842+ return Ok ( ( ) ) ;
843+ } ;
844+ ldk_invoice. write ( writer)
845+ }
846+ }
847+
848+ impl Readable for PaidBolt12Invoice {
849+ fn read < R : lightning:: io:: Read > ( reader : & mut R ) -> Result < Self , DecodeError > {
850+ // Read using LDK's deserialization, then convert to our type
851+ let ldk_invoice: LdkPaidBolt12Invoice = Readable :: read ( reader) ?;
852+ Ok ( PaidBolt12Invoice :: from ( ldk_invoice) )
853+ }
854+ }
855+
689856impl UniffiCustomTypeConverter for OfferId {
690857 type Builtin = String ;
691858
0 commit comments