@@ -168,6 +168,7 @@ static struct command_result *json_pay(struct command *cmd, const char *buf,
168
168
const char * invstr ;
169
169
struct amount_msat * msat ;
170
170
struct amount_msat * maxfee ;
171
+ struct amount_msat * inv_msat ;
171
172
u32 * maxdelay ;
172
173
u32 * retryfor ;
173
174
const char * description ;
@@ -188,6 +189,9 @@ static struct command_result *json_pay(struct command *cmd, const char *buf,
188
189
* than zero. */
189
190
u64 * base_prob_success_millionths ;
190
191
192
+ u64 invexpiry ;
193
+ struct sha256 * payment_hash = NULL ;
194
+
191
195
if (!param (cmd , buf , params ,
192
196
p_req ("invstring" , param_invstring , & invstr ),
193
197
p_opt ("amount_msat" , param_msat , & msat ),
@@ -205,9 +209,6 @@ static struct command_result *json_pay(struct command *cmd, const char *buf,
205
209
p_opt ("label" , param_string , & label ),
206
210
p_opt ("exclude" , param_route_exclusion_array , & exclusions ),
207
211
208
- // FIXME add support for offers
209
- // p_opt("localofferid", param_sha256, &local_offer_id),
210
-
211
212
p_opt_dev ("dev_use_shadow" , param_bool , & use_shadow , true),
212
213
213
214
// MCF options
@@ -236,38 +237,56 @@ static struct command_result *json_pay(struct command *cmd, const char *buf,
236
237
237
238
/* === Parse invoice === */
238
239
239
- // FIXME: add support for bolt12 invoices
240
- if (bolt12_has_prefix (invstr ))
241
- return command_fail (cmd , JSONRPC2_INVALID_PARAMS ,
242
- "BOLT12 invoices are not yet supported." );
243
-
244
240
char * fail ;
245
- struct bolt11 * b11 =
246
- bolt11_decode (tmpctx , invstr , plugin_feature_set (cmd -> plugin ),
247
- description , chainparams , & fail );
248
- if (b11 == NULL )
249
- return command_fail (cmd , JSONRPC2_INVALID_PARAMS ,
250
- "Invalid bolt11: %s" , fail );
241
+ struct bolt11 * b11 ;
242
+ struct tlv_invoice * b12 ;
243
+
244
+ if (bolt12_has_prefix (invstr )) {
245
+ b12 = invoice_decode (tmpctx , invstr , strlen (invstr ),
246
+ plugin_feature_set (cmd -> plugin ),
247
+ chainparams , & fail );
248
+ if (b12 == NULL )
249
+ return command_fail (cmd , JSONRPC2_INVALID_PARAMS ,
250
+ "Invalid bolt12 invoice: %s" , fail );
251
251
252
- /* Sanity check */
253
- if (feature_offered (b11 -> features , OPT_VAR_ONION ) &&
254
- !b11 -> payment_secret )
255
- return command_fail (cmd , JSONRPC2_INVALID_PARAMS ,
256
- "Invalid bolt11:"
257
- " sets feature var_onion with no secret" );
252
+ invexpiry = invoice_expiry (b12 );
253
+ if (b12 -> invoice_amount ) {
254
+ inv_msat = tal (tmpctx , struct amount_msat );
255
+ * inv_msat = amount_msat (* b12 -> invoice_amount );
256
+ }
257
+ payment_hash = b12 -> invoice_payment_hash ;
258
+ } else {
259
+ b11 = bolt11_decode (tmpctx , invstr ,
260
+ plugin_feature_set (cmd -> plugin ),
261
+ description , chainparams , & fail );
262
+ if (b11 == NULL )
263
+ return command_fail (cmd , JSONRPC2_INVALID_PARAMS ,
264
+ "Invalid bolt11 invoice: %s" , fail );
258
265
259
- if ( b11 -> msat ) {
260
- // amount is written in the invoice
261
- if ( msat )
266
+ /* Sanity check */
267
+ if ( feature_offered ( b11 -> features , OPT_VAR_ONION ) &&
268
+ ! b11 -> payment_secret )
262
269
return command_fail (
263
270
cmd , JSONRPC2_INVALID_PARAMS ,
264
- "amount_msat parameter unnecessary" );
265
- msat = b11 -> msat ;
266
- } else {
267
- // amount is not written in the invoice
268
- if (!msat )
271
+ "Invalid bolt11 invoice:"
272
+ " sets feature var_onion with no secret" );
273
+ inv_msat = b11 -> msat ;
274
+ invexpiry = b11 -> timestamp + b11 -> expiry ;
275
+ payment_hash = & b11 -> payment_hash ;
276
+ }
277
+
278
+ /* === Set default values for non-trivial constraints === */
279
+
280
+ // Obtain amount from invoice or from arguments
281
+ if (msat && inv_msat )
282
+ return command_fail (cmd , JSONRPC2_INVALID_PARAMS ,
283
+ "amount_msat parameter cannot be specified "
284
+ "on an invoice with an amount" );
285
+ if (!msat ) {
286
+ if (!inv_msat )
269
287
return command_fail (cmd , JSONRPC2_INVALID_PARAMS ,
270
288
"amount_msat parameter required" );
289
+ msat = tal_dup (tmpctx , struct amount_msat , inv_msat );
271
290
}
272
291
273
292
// Default max fee is 5 sats, or 0.5%, whichever is *higher*
@@ -277,46 +296,93 @@ static struct command_result *json_pay(struct command *cmd, const char *buf,
277
296
fee = AMOUNT_MSAT (5000 );
278
297
maxfee = tal_dup (tmpctx , struct amount_msat , & fee );
279
298
}
299
+ assert (msat );
300
+ assert (maxfee );
301
+ assert (maxdelay );
302
+ assert (retryfor );
303
+ assert (use_shadow );
304
+ assert (base_fee_penalty_millionths );
305
+ assert (prob_cost_factor_millionths );
306
+ assert (riskfactor_millionths );
307
+ assert (min_prob_success_millionths );
308
+ assert (base_prob_success_millionths );
309
+
310
+ /* === Is it expired? === */
280
311
281
312
const u64 now_sec = time_now ().ts .tv_sec ;
282
- if (now_sec > ( b11 -> timestamp + b11 -> expiry ) )
313
+ if (now_sec > invexpiry )
283
314
return command_fail (cmd , PAY_INVOICE_EXPIRED ,
284
315
"Invoice expired" );
285
316
286
317
/* === Get payment === */
287
318
288
319
// one payment_hash one payment is not assumed, it is enforced
320
+ assert (payment_hash );
289
321
struct payment * payment =
290
- payment_map_get (pay_plugin -> payment_map , b11 -> payment_hash );
322
+ payment_map_get (pay_plugin -> payment_map , * payment_hash );
291
323
292
324
if (!payment )
293
325
{
294
- payment = payment_new (
295
- tmpctx ,
296
- & b11 -> payment_hash ,
297
- take (invstr ),
298
- take (label ),
299
- take (description ),
300
- b11 -> payment_secret ,
301
- b11 -> metadata ,
302
- cast_const2 (const struct route_info * * , b11 -> routes ),
303
- & b11 -> receiver_id ,
304
- * msat ,
305
- * maxfee ,
306
- * maxdelay ,
307
- * retryfor ,
308
- b11 -> min_final_cltv_expiry ,
309
- * base_fee_penalty_millionths ,
310
- * prob_cost_factor_millionths ,
311
- * riskfactor_millionths ,
312
- * min_prob_success_millionths ,
313
- * base_prob_success_millionths ,
314
- use_shadow ,
315
- cast_const2 (const struct route_exclusion * * , exclusions ));
316
-
326
+ payment = payment_new (tmpctx , payment_hash , invstr );
317
327
if (!payment )
318
328
return command_fail (cmd , PLUGIN_ERROR ,
319
329
"failed to create a new payment" );
330
+
331
+ struct payment_info * pinfo = & payment -> payment_info ;
332
+ pinfo -> label = tal_strdup_or_null (payment , label );
333
+ pinfo -> description = tal_strdup_or_null (payment , description );
334
+
335
+ if (b11 ) {
336
+ pinfo -> payment_secret =
337
+ tal_steal (payment , b11 -> payment_secret );
338
+ pinfo -> payment_metadata =
339
+ tal_steal (payment , b11 -> metadata );
340
+ pinfo -> routehints = tal_steal (payment , b11 -> routes );
341
+ pinfo -> destination = b11 -> receiver_id ;
342
+ pinfo -> final_cltv = b11 -> min_final_cltv_expiry ;
343
+
344
+ pinfo -> blinded_paths = NULL ;
345
+ pinfo -> blinded_payinfos = NULL ;
346
+ } else {
347
+ pinfo -> payment_secret = NULL ;
348
+ pinfo -> routehints = NULL ;
349
+ pinfo -> payment_metadata = NULL ;
350
+
351
+ pinfo -> blinded_paths =
352
+ tal_steal (payment , b12 -> invoice_paths );
353
+ pinfo -> blinded_payinfos =
354
+ tal_steal (payment , b12 -> invoice_blindedpay );
355
+
356
+ node_id_from_pubkey (& pinfo -> destination ,
357
+ b12 -> invoice_node_id );
358
+
359
+ /* FIXME: there is a different cltv_final for each
360
+ * blinded path, can we send this information to
361
+ * askrene? */
362
+ u32 max_final_cltv = 0 ;
363
+ for (size_t i = 0 ; i < tal_count (pinfo -> blinded_payinfos );
364
+ i ++ ) {
365
+ u32 final_cltv =
366
+ pinfo -> blinded_payinfos [i ]-> cltv_expiry_delta ;
367
+ if (max_final_cltv < final_cltv )
368
+ max_final_cltv = final_cltv ;
369
+ }
370
+ pinfo -> final_cltv = max_final_cltv ;
371
+ }
372
+
373
+ if (!payment_set_constraints (
374
+ payment , * msat , * maxfee , * maxdelay , * retryfor ,
375
+ * base_fee_penalty_millionths ,
376
+ * prob_cost_factor_millionths , * riskfactor_millionths ,
377
+ * min_prob_success_millionths ,
378
+ * base_prob_success_millionths , use_shadow ,
379
+ cast_const2 (const struct route_exclusion * * ,
380
+ exclusions )) ||
381
+ !payment_refresh (payment ))
382
+ return command_fail (
383
+ cmd , PLUGIN_ERROR ,
384
+ "failed to update the payment parameters" );
385
+
320
386
if (!payment_register_command (payment , cmd ))
321
387
return command_fail (cmd , PLUGIN_ERROR ,
322
388
"failed to register command" );
@@ -337,20 +403,17 @@ static struct command_result *json_pay(struct command *cmd, const char *buf,
337
403
}
338
404
339
405
if (payment -> status == PAYMENT_FAIL ) {
340
- // FIXME: should we refuse to pay if the invoices are different?
341
- // or should we consider this a new payment?
342
- if (!payment_update (payment ,
343
- * maxfee ,
344
- * maxdelay ,
345
- * retryfor ,
346
- b11 -> min_final_cltv_expiry ,
347
- * base_fee_penalty_millionths ,
348
- * prob_cost_factor_millionths ,
349
- * riskfactor_millionths ,
350
- * min_prob_success_millionths ,
351
- * base_prob_success_millionths ,
352
- use_shadow ,
353
- cast_const2 (const struct route_exclusion * * , exclusions )))
406
+ // FIXME: fail if invstring does not match
407
+ // FIXME: fail if payment_hash does not match
408
+ if (!payment_set_constraints (
409
+ payment , * msat , * maxfee , * maxdelay , * retryfor ,
410
+ * base_fee_penalty_millionths ,
411
+ * prob_cost_factor_millionths , * riskfactor_millionths ,
412
+ * min_prob_success_millionths ,
413
+ * base_prob_success_millionths , use_shadow ,
414
+ cast_const2 (const struct route_exclusion * * ,
415
+ exclusions )) ||
416
+ !payment_refresh (payment ))
354
417
return command_fail (
355
418
cmd , PLUGIN_ERROR ,
356
419
"failed to update the payment parameters" );
0 commit comments