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 let Some ( amount) = self . offer . amount ( ) {
162
+ if self . invoice_request . amount_msats . is_none ( ) {
163
+ return Err ( SemanticError :: MissingAmount ) ;
164
+ }
165
+
166
+ if let Amount :: Currency { .. } = amount {
167
+ return Err ( SemanticError :: UnsupportedCurrency ) ;
168
+ }
169
+ }
170
+
171
+ if self . offer . expects_quantity ( ) && self . invoice_request . quantity . is_none ( ) {
172
+ return Err ( SemanticError :: InvalidQuantity ) ;
173
+ }
174
+
175
+ let amount_msats = self . invoice_request . amount_msats . unwrap_or ( self . offer . amount_msats ( ) ) ;
176
+ let quantity = self . invoice_request . quantity . unwrap_or ( 1 ) ;
177
+ if amount_msats < self . offer . expected_invoice_amount_msats ( quantity) {
178
+ return Err ( SemanticError :: InsufficientAmount ) ;
179
+ }
180
+
181
+ let InvoiceRequestBuilder { offer, invoice_request } = self ;
182
+ Ok ( UnsignedInvoiceRequest { offer, invoice_request } )
183
+ }
184
+ }
185
+
186
+ /// A semantically valid [`InvoiceRequest`] that hasn't been signed.
187
+ pub struct UnsignedInvoiceRequest < ' a > {
188
+ offer : & ' a Offer ,
189
+ invoice_request : InvoiceRequestContents ,
190
+ }
191
+
192
+ impl < ' a > UnsignedInvoiceRequest < ' a > {
193
+ /// Signs the invoice request using the given function.
194
+ pub fn sign < F > ( self , sign : F ) -> Result < InvoiceRequest , secp256k1:: Error >
195
+ where F : FnOnce ( & Message ) -> Signature
196
+ {
197
+ // Use the offer bytes instead of the offer TLV stream as the offer may have contained
198
+ // unknown TLV records, which are not stored in `OfferContents`.
199
+ let ( payer_tlv_stream, _offer_tlv_stream, invoice_request_tlv_stream) =
200
+ self . invoice_request . as_tlv_stream ( ) ;
201
+ let offer_bytes = WithoutLength ( & self . offer . bytes ) ;
202
+ let unsigned_tlv_stream = ( payer_tlv_stream, offer_bytes, invoice_request_tlv_stream) ;
203
+
204
+ let mut bytes = Vec :: new ( ) ;
205
+ unsigned_tlv_stream. write ( & mut bytes) . unwrap ( ) ;
206
+
207
+ let pubkey = self . invoice_request . payer_id ;
208
+ let signature = Some ( merkle:: sign_message ( sign, SIGNATURE_TAG , & bytes, pubkey) ?) ;
209
+
210
+ // Append the signature TLV record to the bytes.
211
+ let signature_tlv_stream = SignatureTlvStreamRef {
212
+ signature : signature. as_ref ( ) ,
213
+ } ;
214
+ signature_tlv_stream. write ( & mut bytes) . unwrap ( ) ;
215
+
216
+ Ok ( InvoiceRequest {
217
+ bytes,
218
+ contents : self . invoice_request ,
219
+ signature,
220
+ } )
221
+ }
222
+ }
223
+
26
224
/// An `InvoiceRequest` is a request for an `Invoice` formulated from an [`Offer`].
27
225
///
28
226
/// An offer may provided choices such as quantity, amount, chain, features, etc. An invoice request
@@ -59,17 +257,14 @@ impl InvoiceRequest {
59
257
}
60
258
61
259
/// A chain from [`Offer::chains`] that the offer is valid for.
62
- ///
63
- /// [`Offer::chains`]: crate::offers::offer::Offer::chains
64
260
pub fn chain ( & self ) -> ChainHash {
65
- self . contents . chain . unwrap_or_else ( || self . contents . offer . implied_chain ( ) )
261
+ self . contents . chain ( )
66
262
}
67
263
68
264
/// The amount to pay in msats (i.e., the minimum lightning-payable unit for [`chain`]), which
69
265
/// must be greater than or equal to [`Offer::amount`], converted if necessary.
70
266
///
71
267
/// [`chain`]: Self::chain
72
- /// [`Offer::amount`]: crate::offers::offer::Offer::amount
73
268
pub fn amount_msats ( & self ) -> Option < u64 > {
74
269
self . contents . amount_msats
75
270
}
@@ -80,8 +275,6 @@ impl InvoiceRequest {
80
275
}
81
276
82
277
/// 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
278
pub fn quantity ( & self ) -> Option < u64 > {
86
279
self . contents . quantity
87
280
}
@@ -104,12 +297,43 @@ impl InvoiceRequest {
104
297
}
105
298
}
106
299
300
+ impl InvoiceRequestContents {
301
+ fn chain ( & self ) -> ChainHash {
302
+ self . chain . unwrap_or_else ( || self . offer . implied_chain ( ) )
303
+ }
304
+
305
+ pub ( super ) fn as_tlv_stream ( & self ) -> PartialInvoiceRequestTlvStreamRef {
306
+ let payer = PayerTlvStreamRef {
307
+ metadata : self . payer . 0 . as_ref ( ) ,
308
+ } ;
309
+
310
+ let offer = self . offer . as_tlv_stream ( ) ;
311
+
312
+ let invoice_request = InvoiceRequestTlvStreamRef {
313
+ chain : self . chain . as_ref ( ) ,
314
+ amount : self . amount_msats ,
315
+ features : self . features . as_ref ( ) ,
316
+ quantity : self . quantity ,
317
+ payer_id : Some ( & self . payer_id ) ,
318
+ payer_note : self . payer_note . as_ref ( ) ,
319
+ } ;
320
+
321
+ ( payer, offer, invoice_request)
322
+ }
323
+ }
324
+
107
325
impl Writeable for InvoiceRequest {
108
326
fn write < W : Writer > ( & self , writer : & mut W ) -> Result < ( ) , io:: Error > {
109
327
WithoutLength ( & self . bytes ) . write ( writer)
110
328
}
111
329
}
112
330
331
+ impl Writeable for InvoiceRequestContents {
332
+ fn write < W : Writer > ( & self , writer : & mut W ) -> Result < ( ) , io:: Error > {
333
+ self . as_tlv_stream ( ) . write ( writer)
334
+ }
335
+ }
336
+
113
337
impl TryFrom < Vec < u8 > > for InvoiceRequest {
114
338
type Error = ParseError ;
115
339
@@ -135,6 +359,12 @@ type FullInvoiceRequestTlvStream =
135
359
136
360
type PartialInvoiceRequestTlvStream = ( PayerTlvStream , OfferTlvStream , InvoiceRequestTlvStream ) ;
137
361
362
+ type PartialInvoiceRequestTlvStreamRef < ' a > = (
363
+ PayerTlvStreamRef < ' a > ,
364
+ OfferTlvStreamRef < ' a > ,
365
+ InvoiceRequestTlvStreamRef < ' a > ,
366
+ ) ;
367
+
138
368
impl TryFrom < ParsedInvoiceRequest > for InvoiceRequest {
139
369
type Error = ParseError ;
140
370
@@ -149,8 +379,7 @@ impl TryFrom<ParsedInvoiceRequest> for InvoiceRequest {
149
379
) ?;
150
380
151
381
if let Some ( signature) = & signature {
152
- let tag = concat ! ( "lightning" , "invoice_request" , "signature" ) ;
153
- merkle:: verify_signature ( signature, tag, & bytes, contents. payer_id ) ?;
382
+ merkle:: verify_signature ( signature, SIGNATURE_TAG , & bytes, contents. payer_id ) ?;
154
383
}
155
384
156
385
Ok ( InvoiceRequest { bytes, contents, signature } )
0 commit comments