@@ -13,7 +13,7 @@ use std::sync::Arc;
1313use hex:: prelude:: * ;
1414use ldk_node:: lightning:: offers:: invoice:: Bolt12Invoice ;
1515use ldk_node:: lightning_invoice:: Bolt11Invoice ;
16- use ldk_node:: lightning_types:: features:: Bolt11InvoiceFeatures ;
16+ use ldk_node:: lightning_types:: features:: { Bolt11InvoiceFeatures , Bolt12InvoiceFeatures } ;
1717use ldk_server_grpc:: api:: { DecodeInvoiceRequest , DecodeInvoiceResponse } ;
1818use ldk_server_grpc:: types:: { Bolt11HopHint , Bolt11RouteHint } ;
1919
@@ -47,11 +47,29 @@ fn decode_invoice(invoice: &str) -> Result<DecodeInvoiceResponse, LdkServerError
4747///
4848/// Unlike offers and BOLT11 invoices, a BOLT12 invoice has no human-readable string
4949/// encoding — it is exchanged as raw bytes — so the input is expected to be hex-encoded.
50- /// Only the `kind` field is populated for a BOLT12 invoice.
50+ /// Fields that do not apply to BOLT12 invoices (e.g. `payment_secret`, `route_hints`) are
51+ /// left at their default empty values.
5152fn decode_bolt12_invoice ( invoice : & str ) -> Option < DecodeInvoiceResponse > {
5253 let bytes = Vec :: < u8 > :: from_hex ( invoice) . ok ( ) ?;
53- Bolt12Invoice :: try_from ( bytes) . ok ( ) ?;
54- Some ( DecodeInvoiceResponse { kind : INVOICE_KIND_BOLT12 . to_string ( ) , ..Default :: default ( ) } )
54+ let invoice = Bolt12Invoice :: try_from ( bytes) . ok ( ) ?;
55+
56+ let features = decode_features ( invoice. invoice_features ( ) . le_flags ( ) , |bytes| {
57+ Bolt12InvoiceFeatures :: from_le_bytes ( bytes) . to_string ( )
58+ } ) ;
59+
60+ Some ( DecodeInvoiceResponse {
61+ destination : invoice. signing_pubkey ( ) . to_string ( ) ,
62+ payment_hash : invoice. payment_hash ( ) . 0 . to_lower_hex_string ( ) ,
63+ amount_msat : Some ( invoice. amount_msats ( ) ) ,
64+ timestamp : invoice. created_at ( ) . as_secs ( ) ,
65+ expiry : invoice. relative_expiry ( ) . as_secs ( ) ,
66+ description : invoice. description ( ) . map ( |d| d. to_string ( ) ) ,
67+ fallback_address : invoice. fallbacks ( ) . into_iter ( ) . next ( ) . map ( |a| a. to_string ( ) ) ,
68+ features,
69+ is_expired : invoice. is_expired ( ) ,
70+ kind : INVOICE_KIND_BOLT12 . to_string ( ) ,
71+ ..Default :: default ( )
72+ } )
5573}
5674
5775fn decode_bolt11_invoice ( invoice : & Bolt11Invoice ) -> DecodeInvoiceResponse {
@@ -152,11 +170,18 @@ mod tests {
152170 PublicKey :: from_secret_key ( & secp, & SecretKey :: from_slice ( & [ byte; 32 ] ) . unwrap ( ) )
153171 }
154172
173+ /// The keypair the sample BOLT12 invoice is signed with; its public key is the
174+ /// invoice's `signing_pubkey`.
175+ fn signing_keypair ( ) -> Keypair {
176+ let secp = Secp256k1 :: new ( ) ;
177+ Keypair :: from_secret_key ( & secp, & SecretKey :: from_slice ( & [ 43 ; 32 ] ) . unwrap ( ) )
178+ }
179+
155180 /// Builds a signed BOLT12 invoice and returns it hex-encoded, matching how a BOLT12
156181 /// invoice would be supplied to `DecodeInvoice`.
157182 fn sample_bolt12_invoice_hex ( ) -> String {
158183 let secp = Secp256k1 :: new ( ) ;
159- let keys = Keypair :: from_secret_key ( & secp , & SecretKey :: from_slice ( & [ 43 ; 32 ] ) . unwrap ( ) ) ;
184+ let keys = signing_keypair ( ) ;
160185
161186 let payment_paths = vec ! [ BlindedPaymentPath :: from_blinded_path_and_payinfo(
162187 pubkey( 40 ) ,
@@ -203,8 +228,11 @@ mod tests {
203228 }
204229
205230 #[ test]
206- fn decodes_bolt12_invoice_with_bolt12_kind ( ) {
231+ fn decodes_bolt12_invoice_and_populates_fields ( ) {
207232 let response = decode_invoice ( & sample_bolt12_invoice_hex ( ) ) . unwrap ( ) ;
208233 assert_eq ! ( response. kind, INVOICE_KIND_BOLT12 ) ;
234+ assert_eq ! ( response. destination, signing_keypair( ) . public_key( ) . to_string( ) ) ;
235+ assert_eq ! ( response. payment_hash, "2a" . repeat( 32 ) ) ;
236+ assert_eq ! ( response. amount_msat, Some ( 1_000 ) ) ;
209237 }
210238}
0 commit comments