@@ -12,12 +12,14 @@ use crate::types::ChannelManager;
12
12
13
13
use lightning:: ln:: channelmanager:: { PaymentId , Retry } ;
14
14
use lightning:: offers:: invoice:: Bolt12Invoice ;
15
- use lightning:: offers:: offer:: { Amount , Offer } ;
15
+ use lightning:: offers:: offer:: { Amount , Offer , Quantity } ;
16
16
use lightning:: offers:: parse:: Bolt12SemanticError ;
17
17
use lightning:: offers:: refund:: Refund ;
18
+ use lightning:: util:: string:: UntrustedString ;
18
19
19
20
use rand:: RngCore ;
20
21
22
+ use std:: num:: NonZeroU64 ;
21
23
use std:: sync:: { Arc , RwLock } ;
22
24
use std:: time:: { Duration , SystemTime , UNIX_EPOCH } ;
23
25
@@ -47,13 +49,15 @@ impl Bolt12Payment {
47
49
///
48
50
/// If `payer_note` is `Some` it will be seen by the recipient and reflected back in the invoice
49
51
/// response.
50
- pub fn send ( & self , offer : & Offer , payer_note : Option < String > ) -> Result < PaymentId , Error > {
52
+ ///
53
+ /// If `quantity` is `Some` it represents the number of items requested.
54
+ pub fn send (
55
+ & self , offer : & Offer , quantity : Option < u64 > , payer_note : Option < String > ,
56
+ ) -> Result < PaymentId , Error > {
51
57
let rt_lock = self . runtime . read ( ) . unwrap ( ) ;
52
58
if rt_lock. is_none ( ) {
53
59
return Err ( Error :: NotRunning ) ;
54
60
}
55
-
56
- let quantity = None ;
57
61
let mut random_bytes = [ 0u8 ; 32 ] ;
58
62
rand:: thread_rng ( ) . fill_bytes ( & mut random_bytes) ;
59
63
let payment_id = PaymentId ( random_bytes) ;
@@ -76,7 +80,7 @@ impl Bolt12Payment {
76
80
& offer,
77
81
quantity,
78
82
None ,
79
- payer_note,
83
+ payer_note. clone ( ) ,
80
84
payment_id,
81
85
retry_strategy,
82
86
max_total_routing_fee_msat,
@@ -95,6 +99,8 @@ impl Bolt12Payment {
95
99
preimage : None ,
96
100
secret : None ,
97
101
offer_id : offer. id ( ) ,
102
+ payer_note : payer_note. map ( UntrustedString ) ,
103
+ quantity,
98
104
} ;
99
105
let payment = PaymentDetails :: new (
100
106
payment_id,
@@ -117,6 +123,8 @@ impl Bolt12Payment {
117
123
preimage : None ,
118
124
secret : None ,
119
125
offer_id : offer. id ( ) ,
126
+ payer_note : payer_note. map ( UntrustedString ) ,
127
+ quantity,
120
128
} ;
121
129
let payment = PaymentDetails :: new (
122
130
payment_id,
@@ -143,14 +151,13 @@ impl Bolt12Payment {
143
151
/// If `payer_note` is `Some` it will be seen by the recipient and reflected back in the invoice
144
152
/// response.
145
153
pub fn send_using_amount (
146
- & self , offer : & Offer , payer_note : Option < String > , amount_msat : u64 ,
154
+ & self , offer : & Offer , amount_msat : u64 , quantity : Option < u64 > , payer_note : Option < String > ,
147
155
) -> Result < PaymentId , Error > {
148
156
let rt_lock = self . runtime . read ( ) . unwrap ( ) ;
149
157
if rt_lock. is_none ( ) {
150
158
return Err ( Error :: NotRunning ) ;
151
159
}
152
160
153
- let quantity = None ;
154
161
let mut random_bytes = [ 0u8 ; 32 ] ;
155
162
rand:: thread_rng ( ) . fill_bytes ( & mut random_bytes) ;
156
163
let payment_id = PaymentId ( random_bytes) ;
@@ -177,7 +184,7 @@ impl Bolt12Payment {
177
184
& offer,
178
185
quantity,
179
186
Some ( amount_msat) ,
180
- payer_note,
187
+ payer_note. clone ( ) ,
181
188
payment_id,
182
189
retry_strategy,
183
190
max_total_routing_fee_msat,
@@ -196,6 +203,8 @@ impl Bolt12Payment {
196
203
preimage : None ,
197
204
secret : None ,
198
205
offer_id : offer. id ( ) ,
206
+ payer_note : payer_note. map ( UntrustedString ) ,
207
+ quantity,
199
208
} ;
200
209
let payment = PaymentDetails :: new (
201
210
payment_id,
@@ -218,6 +227,8 @@ impl Bolt12Payment {
218
227
preimage : None ,
219
228
secret : None ,
220
229
offer_id : offer. id ( ) ,
230
+ payer_note : payer_note. map ( UntrustedString ) ,
231
+ quantity,
221
232
} ;
222
233
let payment = PaymentDetails :: new (
223
234
payment_id,
@@ -236,21 +247,32 @@ impl Bolt12Payment {
236
247
237
248
/// Returns a payable offer that can be used to request and receive a payment of the amount
238
249
/// given.
239
- pub fn receive ( & self , amount_msat : u64 , description : & str ) -> Result < Offer , Error > {
250
+ pub fn receive (
251
+ & self , amount_msat : u64 , description : & str , quantity : Option < u64 > ,
252
+ ) -> Result < Offer , Error > {
240
253
let offer_builder = self . channel_manager . create_offer_builder ( ) . map_err ( |e| {
241
254
log_error ! ( self . logger, "Failed to create offer builder: {:?}" , e) ;
242
255
Error :: OfferCreationFailed
243
256
} ) ?;
244
- let offer = offer_builder
245
- . amount_msats ( amount_msat)
246
- . description ( description. to_string ( ) )
247
- . build ( )
248
- . map_err ( |e| {
249
- log_error ! ( self . logger, "Failed to create offer: {:?}" , e) ;
250
- Error :: OfferCreationFailed
251
- } ) ?;
252
257
253
- Ok ( offer)
258
+ let mut offer =
259
+ offer_builder. amount_msats ( amount_msat) . description ( description. to_string ( ) ) ;
260
+
261
+ if let Some ( qty) = quantity {
262
+ if qty == 0 {
263
+ log_error ! ( self . logger, "Failed to create offer: quantity can't be zero." ) ;
264
+ return Err ( Error :: InvalidQuantity ) ;
265
+ } else {
266
+ offer = offer. supported_quantity ( Quantity :: Bounded ( NonZeroU64 :: new ( qty) . unwrap ( ) ) )
267
+ } ;
268
+ } ;
269
+
270
+ let finalized_offer = offer. build ( ) . map_err ( |e| {
271
+ log_error ! ( self . logger, "Failed to create offer: {:?}" , e) ;
272
+ Error :: OfferCreationFailed
273
+ } ) ?;
274
+
275
+ Ok ( finalized_offer)
254
276
}
255
277
256
278
/// Returns a payable offer that can be used to request and receive a payment for which the
@@ -281,8 +303,13 @@ impl Bolt12Payment {
281
303
let payment_hash = invoice. payment_hash ( ) ;
282
304
let payment_id = PaymentId ( payment_hash. 0 ) ;
283
305
284
- let kind =
285
- PaymentKind :: Bolt12Refund { hash : Some ( payment_hash) , preimage : None , secret : None } ;
306
+ let kind = PaymentKind :: Bolt12Refund {
307
+ hash : Some ( payment_hash) ,
308
+ preimage : None ,
309
+ secret : None ,
310
+ payer_note : refund. payer_note ( ) . map ( |note| UntrustedString ( note. 0 . to_string ( ) ) ) ,
311
+ quantity : refund. quantity ( ) ,
312
+ } ;
286
313
287
314
let payment = PaymentDetails :: new (
288
315
payment_id,
@@ -298,7 +325,10 @@ impl Bolt12Payment {
298
325
}
299
326
300
327
/// Returns a [`Refund`] object that can be used to offer a refund payment of the amount given.
301
- pub fn initiate_refund ( & self , amount_msat : u64 , expiry_secs : u32 ) -> Result < Refund , Error > {
328
+ pub fn initiate_refund (
329
+ & self , amount_msat : u64 , expiry_secs : u32 , quantity : Option < u64 > ,
330
+ payer_note : Option < String > ,
331
+ ) -> Result < Refund , Error > {
302
332
let mut random_bytes = [ 0u8 ; 32 ] ;
303
333
rand:: thread_rng ( ) . fill_bytes ( & mut random_bytes) ;
304
334
let payment_id = PaymentId ( random_bytes) ;
@@ -309,7 +339,7 @@ impl Bolt12Payment {
309
339
let retry_strategy = Retry :: Timeout ( LDK_PAYMENT_RETRY_TIMEOUT ) ;
310
340
let max_total_routing_fee_msat = None ;
311
341
312
- let refund = self
342
+ let mut refund_builder = self
313
343
. channel_manager
314
344
. create_refund_builder (
315
345
amount_msat,
@@ -321,17 +351,30 @@ impl Bolt12Payment {
321
351
. map_err ( |e| {
322
352
log_error ! ( self . logger, "Failed to create refund builder: {:?}" , e) ;
323
353
Error :: RefundCreationFailed
324
- } ) ?
325
- . build ( )
326
- . map_err ( |e| {
327
- log_error ! ( self . logger, "Failed to create refund: {:?}" , e) ;
328
- Error :: RefundCreationFailed
329
354
} ) ?;
330
355
331
- log_info ! ( self . logger, "Offering refund of {}msat" , amount_msat) ;
356
+ if let Some ( qty) = quantity {
357
+ refund_builder = refund_builder. quantity ( qty) ;
358
+ }
359
+
360
+ if let Some ( note) = payer_note. clone ( ) {
361
+ refund_builder = refund_builder. payer_note ( note) ;
362
+ }
363
+
364
+ let refund = refund_builder. build ( ) . map_err ( |e| {
365
+ log_error ! ( self . logger, "Failed to create refund: {:?}" , e) ;
366
+ Error :: RefundCreationFailed
367
+ } ) ?;
332
368
333
- let kind = PaymentKind :: Bolt12Refund { hash : None , preimage : None , secret : None } ;
369
+ log_info ! ( self . logger , "Offering refund of {}msat" , amount_msat ) ;
334
370
371
+ let kind = PaymentKind :: Bolt12Refund {
372
+ hash : None ,
373
+ preimage : None ,
374
+ secret : None ,
375
+ payer_note : payer_note. map ( |note| UntrustedString ( note) ) ,
376
+ quantity,
377
+ } ;
335
378
let payment = PaymentDetails :: new (
336
379
payment_id,
337
380
kind,
0 commit comments