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 io;
17
58
use ln:: features:: OfferFeatures ;
18
- use offers:: merkle:: { SignatureTlvStream , self } ;
19
- use offers:: offer:: { Amount , OfferContents , OfferTlvStream } ;
59
+ use offers:: merkle:: { SignatureTlvStream , SignatureTlvStreamRef , self } ;
60
+ use offers:: offer:: { Amount , Offer , OfferContents , OfferTlvStream , OfferTlvStreamRef } ;
20
61
use offers:: parse:: { ParseError , SemanticError } ;
21
- use offers:: payer:: { PayerContents , PayerTlvStream } ;
62
+ use offers:: payer:: { PayerContents , PayerTlvStream , PayerTlvStreamRef } ;
22
63
use util:: ser:: { HighZeroBytesDroppedBigSize , Readable , WithoutLength , Writeable , Writer } ;
23
64
24
65
use 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 [`InvoiceReques::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 be
135
+ /// between [`Offer::quantity_min`] and [`Offer::quantity_max`], inclusive.
136
+ ///
137
+ /// Successive calls to this method will override the previous setting.
138
+ ///
139
+ /// [`quantity_range`]: Self::quantity_range
140
+ pub fn quantity ( mut self , quantity : u64 ) -> Result < Self , SemanticError > {
141
+ if !self . offer . is_valid_quantity ( quantity) {
142
+ return Err ( SemanticError :: InvalidQuantity ) ;
143
+ }
144
+
145
+ self . invoice_request . quantity = Some ( quantity) ;
146
+ Ok ( self )
147
+ }
148
+
149
+ /// Sets a note for the invoice request.
150
+ ///
151
+ /// Successive calls to this method will override the previous setting.
152
+ pub fn payer_note ( mut self , payer_note : String ) -> Self {
153
+ self . invoice_request . payer_note = Some ( payer_note) ;
154
+ self
155
+ }
156
+
157
+ /// Builds an [`InvoiceRequest`] after checking for valid semantics.
158
+ pub fn build ( self ) -> Result < UnsignedInvoiceRequest < ' a > , SemanticError > {
159
+ if !self . offer . supports_chain ( self . invoice_request . chain ( ) ) {
160
+ return Err ( SemanticError :: UnsupportedChain ) ;
161
+ }
162
+
163
+ if self . offer . amount ( ) . is_some ( ) && self . invoice_request . amount_msats . is_none ( ) {
164
+ return Err ( SemanticError :: MissingAmount ) ;
165
+ }
166
+
167
+ if self . offer . expects_quantity ( ) && self . invoice_request . quantity . is_none ( ) {
168
+ return Err ( SemanticError :: InvalidQuantity ) ;
169
+ }
170
+
171
+ let amount_msats = self . invoice_request . amount_msats . unwrap_or ( self . offer . amount_msats ( ) ) ;
172
+ let quantity = self . invoice_request . quantity . unwrap_or ( 1 ) ;
173
+ if amount_msats < self . offer . base_invoice_amount_msats ( quantity) {
174
+ return Err ( SemanticError :: InsufficientAmount ) ;
175
+ }
176
+
177
+ let InvoiceRequestBuilder { offer, invoice_request } = self ;
178
+ Ok ( UnsignedInvoiceRequest { offer, invoice_request } )
179
+ }
180
+ }
181
+
182
+ /// A semantically valid [`InvoiceRequest`] that hasn't been signed.
183
+ pub struct UnsignedInvoiceRequest < ' a > {
184
+ offer : & ' a Offer ,
185
+ invoice_request : InvoiceRequestContents ,
186
+ }
187
+
188
+ impl < ' a > UnsignedInvoiceRequest < ' a > {
189
+ /// Signs the invoice request using the given function.
190
+ pub fn sign < F > ( self , sign : F ) -> Result < InvoiceRequest , secp256k1:: Error >
191
+ where F : FnOnce ( & Message ) -> Signature
192
+ {
193
+ // Use the offer bytes instead of the offer TLV stream as the offer may have contained
194
+ // unknown TLV records, which are not stored in `OfferContents`.
195
+ let ( payer_tlv_stream, _offer_tlv_stream, invoice_request_tlv_stream) =
196
+ self . invoice_request . as_tlv_stream ( ) ;
197
+ let offer_bytes = WithoutLength ( & self . offer . bytes ) ;
198
+ let unsigned_tlv_stream = ( payer_tlv_stream, offer_bytes, invoice_request_tlv_stream) ;
199
+
200
+ let mut bytes = Vec :: new ( ) ;
201
+ unsigned_tlv_stream. write ( & mut bytes) . unwrap ( ) ;
202
+
203
+ let pubkey = self . invoice_request . payer_id ;
204
+ let signature = Some ( merkle:: sign_message ( sign, SIGNATURE_TAG , & bytes, pubkey) ?) ;
205
+
206
+ // Append the signature TLV record to the bytes.
207
+ let signature_tlv_stream = SignatureTlvStreamRef {
208
+ signature : signature. as_ref ( ) ,
209
+ } ;
210
+ signature_tlv_stream. write ( & mut bytes) . unwrap ( ) ;
211
+
212
+ Ok ( InvoiceRequest {
213
+ bytes,
214
+ contents : self . invoice_request ,
215
+ signature,
216
+ } )
217
+ }
218
+ }
219
+
26
220
/// An `InvoiceRequest` is a request for an `Invoice` formulated from an [`Offer`].
27
221
///
28
222
/// An offer may provided choices such as quantity, amount, chain, features, etc. An invoice request
@@ -62,7 +256,7 @@ impl InvoiceRequest {
62
256
///
63
257
/// [`Offer::chains`]: crate::offers::offer::Offer::chains
64
258
pub fn chain ( & self ) -> ChainHash {
65
- self . contents . chain . unwrap_or_else ( || self . contents . offer . implied_chain ( ) )
259
+ self . contents . chain ( )
66
260
}
67
261
68
262
/// The amount to pay in msats (i.e., the minimum lightning-payable unit for [`chain`]), which
@@ -106,12 +300,43 @@ impl InvoiceRequest {
106
300
}
107
301
}
108
302
303
+ impl InvoiceRequestContents {
304
+ fn chain ( & self ) -> ChainHash {
305
+ self . chain . unwrap_or_else ( || self . offer . implied_chain ( ) )
306
+ }
307
+
308
+ pub ( super ) fn as_tlv_stream ( & self ) -> PartialInvoiceRequestTlvStreamRef {
309
+ let payer = PayerTlvStreamRef {
310
+ metadata : self . payer . 0 . as_ref ( ) ,
311
+ } ;
312
+
313
+ let offer = self . offer . as_tlv_stream ( ) ;
314
+
315
+ let invoice_request = InvoiceRequestTlvStreamRef {
316
+ chain : self . chain . as_ref ( ) ,
317
+ amount : self . amount_msats ,
318
+ features : self . features . as_ref ( ) ,
319
+ quantity : self . quantity ,
320
+ payer_id : Some ( & self . payer_id ) ,
321
+ payer_note : self . payer_note . as_ref ( ) ,
322
+ } ;
323
+
324
+ ( payer, offer, invoice_request)
325
+ }
326
+ }
327
+
109
328
impl Writeable for InvoiceRequest {
110
329
fn write < W : Writer > ( & self , writer : & mut W ) -> Result < ( ) , io:: Error > {
111
330
WithoutLength ( & self . bytes ) . write ( writer)
112
331
}
113
332
}
114
333
334
+ impl Writeable for InvoiceRequestContents {
335
+ fn write < W : Writer > ( & self , writer : & mut W ) -> Result < ( ) , io:: Error > {
336
+ self . as_tlv_stream ( ) . write ( writer)
337
+ }
338
+ }
339
+
115
340
impl TryFrom < Vec < u8 > > for InvoiceRequest {
116
341
type Error = ParseError ;
117
342
@@ -137,6 +362,12 @@ type FullInvoiceRequestTlvStream =
137
362
138
363
type PartialInvoiceRequestTlvStream = ( PayerTlvStream , OfferTlvStream , InvoiceRequestTlvStream ) ;
139
364
365
+ type PartialInvoiceRequestTlvStreamRef < ' a > = (
366
+ PayerTlvStreamRef < ' a > ,
367
+ OfferTlvStreamRef < ' a > ,
368
+ InvoiceRequestTlvStreamRef < ' a > ,
369
+ ) ;
370
+
140
371
impl TryFrom < ParsedInvoiceRequest > for InvoiceRequest {
141
372
type Error = ParseError ;
142
373
@@ -151,8 +382,7 @@ impl TryFrom<ParsedInvoiceRequest> for InvoiceRequest {
151
382
) ?;
152
383
153
384
if let Some ( signature) = & signature {
154
- let tag = concat ! ( "lightning" , "invoice_request" , "signature" ) ;
155
- merkle:: verify_signature ( signature, tag, & bytes, contents. payer_id ) ?;
385
+ merkle:: verify_signature ( signature, SIGNATURE_TAG , & bytes, contents. payer_id ) ?;
156
386
}
157
387
158
388
Ok ( InvoiceRequest { bytes, contents, signature } )
0 commit comments