8
8
// licenses.
9
9
10
10
//! Data structures and encoding for `invoice_request` messages.
11
+ //!
12
+ //! An [`InvoiceRequest`] can be either built from a parsed [`Offer`] as an "offer to be paid" or
13
+ //! built directly as an "offer for money" (e.g., refund, ATM withdrawal). In the former case, it is
14
+ //! typically constructed by a customer and sent to the merchant who had published the corresponding
15
+ //! offer. In the latter case, an offer doesn't exist as a precursor to the request. Rather the
16
+ //! merchant would typically construct the invoice request and presents it to the customer.
17
+ //!
18
+ //! The recipient of the request responds with an `Invoice`.
19
+ //! ```
20
+ //! extern crate bitcoin;
21
+ //! extern crate lightning;
22
+ //!
23
+ //! use bitcoin::network::constants::Network;
24
+ //! use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, SecretKey};
25
+ //! use lightning::ln::features::OfferFeatures;
26
+ //! use lightning::offers::offer::Offer;
27
+ //! use lightning::util::ser::Writeable;
28
+ //!
29
+ //! # fn parse() -> Result<(), lightning::offers::parse::ParseError> {
30
+ //! let secp_ctx = Secp256k1::new();
31
+ //! let keys = KeyPair::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32])?);
32
+ //! let pubkey = PublicKey::from(keys);
33
+ //! let mut buffer = Vec::new();
34
+ //!
35
+ //! // "offer to be paid" flow
36
+ //! "lno1qcp4256ypq"
37
+ //! .parse::<Offer>()?
38
+ //! .request_invoice(pubkey)
39
+ //! .metadata(vec![42; 64])
40
+ //! .chain(Network::Testnet)?
41
+ //! .amount_msats(1000)
42
+ //! .quantity(5)?
43
+ //! .payer_note("foo".to_string())
44
+ //! .build()?
45
+ //! .sign(|digest| secp_ctx.sign_schnorr_no_aux_rand(digest, &keys))?
46
+ //! .write(&mut buffer)
47
+ //! .unwrap();
48
+ //! # Ok(())
49
+ //! # }
50
+ //! ```
11
51
12
52
use bitcoin:: blockdata:: constants:: ChainHash ;
13
- use bitcoin:: secp256k1:: PublicKey ;
53
+ use bitcoin:: network:: constants:: Network ;
54
+ use bitcoin:: secp256k1:: { Message , PublicKey , self } ;
14
55
use bitcoin:: secp256k1:: schnorr:: Signature ;
15
56
use core:: convert:: TryFrom ;
16
57
use crate :: io;
17
58
use crate :: ln:: features:: OfferFeatures ;
18
- use crate :: offers:: merkle:: { SignatureTlvStream , self } ;
19
- use crate :: offers:: offer:: { Amount , OfferContents , OfferTlvStream } ;
59
+ use crate :: offers:: merkle:: { SignatureTlvStream , SignatureTlvStreamRef , self } ;
60
+ use crate :: offers:: offer:: { Amount , Offer , OfferContents , OfferTlvStream , OfferTlvStreamRef } ;
20
61
use crate :: offers:: parse:: { ParseError , SemanticError } ;
21
- use crate :: offers:: payer:: { PayerContents , PayerTlvStream } ;
62
+ use crate :: offers:: payer:: { PayerContents , PayerTlvStream , PayerTlvStreamRef } ;
22
63
use crate :: util:: ser:: { HighZeroBytesDroppedBigSize , Readable , WithoutLength , Writeable , Writer } ;
23
64
24
65
use crate :: prelude:: * ;
25
66
67
+ const SIGNATURE_TAG : & ' static str = concat ! ( "lightning" , "invoice_request" , "signature" ) ;
68
+
69
+ /// Builds an [`InvoiceRequest`] from an [`Offer`] for the "offer to be paid" flow.
70
+ ///
71
+ /// See [module-level documentation] for usage.
72
+ ///
73
+ /// [module-level documentation]: self
74
+ pub struct InvoiceRequestBuilder < ' a > {
75
+ offer : & ' a Offer ,
76
+ invoice_request : InvoiceRequestContents ,
77
+ }
78
+
79
+ impl < ' a > InvoiceRequestBuilder < ' a > {
80
+ pub ( super ) fn new ( offer : & ' a Offer , payer_id : PublicKey ) -> Self {
81
+ Self {
82
+ offer,
83
+ invoice_request : InvoiceRequestContents {
84
+ payer : PayerContents ( None ) , offer : offer. contents . clone ( ) , chain : None ,
85
+ amount_msats : None , features : None , quantity : None , payer_id, payer_note : None ,
86
+ } ,
87
+ }
88
+ }
89
+
90
+ /// Sets the metadata for the invoice request. Useful for containing information about the
91
+ /// derivation of [`InvoiceRequest::payer_id`]. This should not leak any information such as
92
+ /// using a simple BIP-32 derivation path.
93
+ ///
94
+ /// Successive calls to this method will override the previous setting.
95
+ pub fn metadata ( mut self , metadata : Vec < u8 > ) -> Self {
96
+ self . invoice_request . payer = PayerContents ( Some ( metadata) ) ;
97
+ self
98
+ }
99
+
100
+ /// Sets the chain hash of the given [`Network`] for paying an invoice. If not called,
101
+ /// [`Network::Bitcoin`] is assumed. Must be supported by the offer.
102
+ ///
103
+ /// Successive calls to this method will override the previous setting.
104
+ pub fn chain ( mut self , network : Network ) -> Result < Self , SemanticError > {
105
+ let chain = ChainHash :: using_genesis_block ( network) ;
106
+ if !self . offer . supports_chain ( chain) {
107
+ return Err ( SemanticError :: UnsupportedChain )
108
+ }
109
+
110
+ self . invoice_request . chain = Some ( chain) ;
111
+ Ok ( self )
112
+ }
113
+
114
+ /// Sets the amount for paying an invoice. Must be at least the base invoice amount (i.e.,
115
+ /// [`Offer::amount`] times [`quantity`]).
116
+ ///
117
+ /// Successive calls to this method will override the previous setting.
118
+ ///
119
+ /// [`quantity`]: Self::quantity
120
+ pub fn amount_msats ( mut self , amount_msats : u64 ) -> Self {
121
+ self . invoice_request . amount_msats = Some ( amount_msats) ;
122
+ self
123
+ }
124
+
125
+ /// Sets the features for the invoice request.
126
+ ///
127
+ /// Successive calls to this method will override the previous setting.
128
+ #[ cfg( test) ]
129
+ pub fn features ( mut self , features : OfferFeatures ) -> Self {
130
+ self . invoice_request . features = Some ( features) ;
131
+ self
132
+ }
133
+
134
+ /// Sets a quantity of items for the invoice request. If not set, `1` is assumed. Must conform
135
+ /// to [`Offer::is_valid_quantity`].
136
+ ///
137
+ /// Successive calls to this method will override the previous setting.
138
+ pub fn quantity ( mut self , quantity : u64 ) -> Result < Self , SemanticError > {
139
+ if !self . offer . is_valid_quantity ( quantity) {
140
+ return Err ( SemanticError :: InvalidQuantity ) ;
141
+ }
142
+
143
+ self . invoice_request . quantity = Some ( quantity) ;
144
+ Ok ( self )
145
+ }
146
+
147
+ /// Sets a note for the invoice request.
148
+ ///
149
+ /// Successive calls to this method will override the previous setting.
150
+ pub fn payer_note ( mut self , payer_note : String ) -> Self {
151
+ self . invoice_request . payer_note = Some ( payer_note) ;
152
+ self
153
+ }
154
+
155
+ /// Builds an [`InvoiceRequest`] after checking for valid semantics.
156
+ pub fn build ( self ) -> Result < UnsignedInvoiceRequest < ' a > , SemanticError > {
157
+ if !self . offer . supports_chain ( self . invoice_request . chain ( ) ) {
158
+ return Err ( SemanticError :: UnsupportedChain ) ;
159
+ }
160
+
161
+ if self . offer . amount ( ) . is_some ( ) && self . invoice_request . amount_msats . is_none ( ) {
162
+ return Err ( SemanticError :: MissingAmount ) ;
163
+ }
164
+
165
+ if self . offer . expects_quantity ( ) && self . invoice_request . quantity . is_none ( ) {
166
+ return Err ( SemanticError :: InvalidQuantity ) ;
167
+ }
168
+
169
+ let amount_msats = self . invoice_request . amount_msats . unwrap_or ( self . offer . amount_msats ( ) ) ;
170
+ let quantity = self . invoice_request . quantity . unwrap_or ( 1 ) ;
171
+ if amount_msats < self . offer . expected_invoice_amount_msats ( quantity) {
172
+ return Err ( SemanticError :: InsufficientAmount ) ;
173
+ }
174
+
175
+ let InvoiceRequestBuilder { offer, invoice_request } = self ;
176
+ Ok ( UnsignedInvoiceRequest { offer, invoice_request } )
177
+ }
178
+ }
179
+
180
+ /// A semantically valid [`InvoiceRequest`] that hasn't been signed.
181
+ pub struct UnsignedInvoiceRequest < ' a > {
182
+ offer : & ' a Offer ,
183
+ invoice_request : InvoiceRequestContents ,
184
+ }
185
+
186
+ impl < ' a > UnsignedInvoiceRequest < ' a > {
187
+ /// Signs the invoice request using the given function.
188
+ pub fn sign < F > ( self , sign : F ) -> Result < InvoiceRequest , secp256k1:: Error >
189
+ where F : FnOnce ( & Message ) -> Signature
190
+ {
191
+ // Use the offer bytes instead of the offer TLV stream as the offer may have contained
192
+ // unknown TLV records, which are not stored in `OfferContents`.
193
+ let ( payer_tlv_stream, _offer_tlv_stream, invoice_request_tlv_stream) =
194
+ self . invoice_request . as_tlv_stream ( ) ;
195
+ let offer_bytes = WithoutLength ( & self . offer . bytes ) ;
196
+ let unsigned_tlv_stream = ( payer_tlv_stream, offer_bytes, invoice_request_tlv_stream) ;
197
+
198
+ let mut bytes = Vec :: new ( ) ;
199
+ unsigned_tlv_stream. write ( & mut bytes) . unwrap ( ) ;
200
+
201
+ let pubkey = self . invoice_request . payer_id ;
202
+ let signature = Some ( merkle:: sign_message ( sign, SIGNATURE_TAG , & bytes, pubkey) ?) ;
203
+
204
+ // Append the signature TLV record to the bytes.
205
+ let signature_tlv_stream = SignatureTlvStreamRef {
206
+ signature : signature. as_ref ( ) ,
207
+ } ;
208
+ signature_tlv_stream. write ( & mut bytes) . unwrap ( ) ;
209
+
210
+ Ok ( InvoiceRequest {
211
+ bytes,
212
+ contents : self . invoice_request ,
213
+ signature,
214
+ } )
215
+ }
216
+ }
217
+
26
218
/// An `InvoiceRequest` is a request for an `Invoice` formulated from an [`Offer`].
27
219
///
28
220
/// An offer may provided choices such as quantity, amount, chain, features, etc. An invoice request
@@ -59,17 +251,14 @@ impl InvoiceRequest {
59
251
}
60
252
61
253
/// A chain from [`Offer::chains`] that the offer is valid for.
62
- ///
63
- /// [`Offer::chains`]: crate::offers::offer::Offer::chains
64
254
pub fn chain ( & self ) -> ChainHash {
65
- self . contents . chain . unwrap_or_else ( || self . contents . offer . implied_chain ( ) )
255
+ self . contents . chain ( )
66
256
}
67
257
68
258
/// The amount to pay in msats (i.e., the minimum lightning-payable unit for [`chain`]), which
69
259
/// must be greater than or equal to [`Offer::amount`], converted if necessary.
70
260
///
71
261
/// [`chain`]: Self::chain
72
- /// [`Offer::amount`]: crate::offers::offer::Offer::amount
73
262
pub fn amount_msats ( & self ) -> Option < u64 > {
74
263
self . contents . amount_msats
75
264
}
@@ -80,8 +269,6 @@ impl InvoiceRequest {
80
269
}
81
270
82
271
/// The quantity of the offer's item conforming to [`Offer::is_valid_quantity`].
83
- ///
84
- /// [`Offer::is_valid_quantity`]: crate::offers::offer::Offer::is_valid_quantity
85
272
pub fn quantity ( & self ) -> Option < u64 > {
86
273
self . contents . quantity
87
274
}
@@ -104,12 +291,43 @@ impl InvoiceRequest {
104
291
}
105
292
}
106
293
294
+ impl InvoiceRequestContents {
295
+ fn chain ( & self ) -> ChainHash {
296
+ self . chain . unwrap_or_else ( || self . offer . implied_chain ( ) )
297
+ }
298
+
299
+ pub ( super ) fn as_tlv_stream ( & self ) -> PartialInvoiceRequestTlvStreamRef {
300
+ let payer = PayerTlvStreamRef {
301
+ metadata : self . payer . 0 . as_ref ( ) ,
302
+ } ;
303
+
304
+ let offer = self . offer . as_tlv_stream ( ) ;
305
+
306
+ let invoice_request = InvoiceRequestTlvStreamRef {
307
+ chain : self . chain . as_ref ( ) ,
308
+ amount : self . amount_msats ,
309
+ features : self . features . as_ref ( ) ,
310
+ quantity : self . quantity ,
311
+ payer_id : Some ( & self . payer_id ) ,
312
+ payer_note : self . payer_note . as_ref ( ) ,
313
+ } ;
314
+
315
+ ( payer, offer, invoice_request)
316
+ }
317
+ }
318
+
107
319
impl Writeable for InvoiceRequest {
108
320
fn write < W : Writer > ( & self , writer : & mut W ) -> Result < ( ) , io:: Error > {
109
321
WithoutLength ( & self . bytes ) . write ( writer)
110
322
}
111
323
}
112
324
325
+ impl Writeable for InvoiceRequestContents {
326
+ fn write < W : Writer > ( & self , writer : & mut W ) -> Result < ( ) , io:: Error > {
327
+ self . as_tlv_stream ( ) . write ( writer)
328
+ }
329
+ }
330
+
113
331
impl TryFrom < Vec < u8 > > for InvoiceRequest {
114
332
type Error = ParseError ;
115
333
@@ -135,6 +353,12 @@ type FullInvoiceRequestTlvStream =
135
353
136
354
type PartialInvoiceRequestTlvStream = ( PayerTlvStream , OfferTlvStream , InvoiceRequestTlvStream ) ;
137
355
356
+ type PartialInvoiceRequestTlvStreamRef < ' a > = (
357
+ PayerTlvStreamRef < ' a > ,
358
+ OfferTlvStreamRef < ' a > ,
359
+ InvoiceRequestTlvStreamRef < ' a > ,
360
+ ) ;
361
+
138
362
impl TryFrom < ParsedInvoiceRequest > for InvoiceRequest {
139
363
type Error = ParseError ;
140
364
@@ -149,8 +373,7 @@ impl TryFrom<ParsedInvoiceRequest> for InvoiceRequest {
149
373
) ?;
150
374
151
375
if let Some ( signature) = & signature {
152
- let tag = concat ! ( "lightning" , "invoice_request" , "signature" ) ;
153
- merkle:: verify_signature ( signature, tag, & bytes, contents. payer_id ) ?;
376
+ merkle:: verify_signature ( signature, SIGNATURE_TAG , & bytes, contents. payer_id ) ?;
154
377
}
155
378
156
379
Ok ( InvoiceRequest { bytes, contents, signature } )
0 commit comments