@@ -168,6 +168,7 @@ static struct command_result *json_pay(struct command *cmd, const char *buf,
168168 const char * invstr ;
169169 struct amount_msat * msat ;
170170 struct amount_msat * maxfee ;
171+ struct amount_msat * inv_msat ;
171172 u32 * maxdelay ;
172173 u32 * retryfor ;
173174 const char * description ;
@@ -188,6 +189,9 @@ static struct command_result *json_pay(struct command *cmd, const char *buf,
188189 * than zero. */
189190 u64 * base_prob_success_millionths ;
190191
192+ u64 invexpiry ;
193+ struct sha256 * payment_hash = NULL ;
194+
191195 if (!param (cmd , buf , params ,
192196 p_req ("invstring" , param_invstring , & invstr ),
193197 p_opt ("amount_msat" , param_msat , & msat ),
@@ -205,9 +209,6 @@ static struct command_result *json_pay(struct command *cmd, const char *buf,
205209 p_opt ("label" , param_string , & label ),
206210 p_opt ("exclude" , param_route_exclusion_array , & exclusions ),
207211
208- // FIXME add support for offers
209- // p_opt("localofferid", param_sha256, &local_offer_id),
210-
211212 p_opt_dev ("dev_use_shadow" , param_bool , & use_shadow , true),
212213
213214 // MCF options
@@ -236,38 +237,56 @@ static struct command_result *json_pay(struct command *cmd, const char *buf,
236237
237238 /* === Parse invoice === */
238239
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-
244240 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 );
251251
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 );
258265
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 )
262269 return command_fail (
263270 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 )
269287 return command_fail (cmd , JSONRPC2_INVALID_PARAMS ,
270288 "amount_msat parameter required" );
289+ msat = tal_dup (tmpctx , struct amount_msat , inv_msat );
271290 }
272291
273292 // 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,
277296 fee = AMOUNT_MSAT (5000 );
278297 maxfee = tal_dup (tmpctx , struct amount_msat , & fee );
279298 }
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? === */
280311
281312 const u64 now_sec = time_now ().ts .tv_sec ;
282- if (now_sec > ( b11 -> timestamp + b11 -> expiry ) )
313+ if (now_sec > invexpiry )
283314 return command_fail (cmd , PAY_INVOICE_EXPIRED ,
284315 "Invoice expired" );
285316
286317 /* === Get payment === */
287318
288319 // one payment_hash one payment is not assumed, it is enforced
320+ assert (payment_hash );
289321 struct payment * payment =
290- payment_map_get (pay_plugin -> payment_map , b11 -> payment_hash );
322+ payment_map_get (pay_plugin -> payment_map , * payment_hash );
291323
292324 if (!payment )
293325 {
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 );
317327 if (!payment )
318328 return command_fail (cmd , PLUGIN_ERROR ,
319329 "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+
320386 if (!payment_register_command (payment , cmd ))
321387 return command_fail (cmd , PLUGIN_ERROR ,
322388 "failed to register command" );
@@ -337,20 +403,17 @@ static struct command_result *json_pay(struct command *cmd, const char *buf,
337403 }
338404
339405 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 ))
354417 return command_fail (
355418 cmd , PLUGIN_ERROR ,
356419 "failed to update the payment parameters" );
0 commit comments