@@ -70,6 +70,9 @@ fail_invreq_level(struct command *cmd,
70
70
err -> error = tal_dup_arr (err , char , msg , strlen (msg ), 0 );
71
71
/* FIXME: Add suggested_value / erroneous_field! */
72
72
73
+ if (!invreq -> reply_path )
74
+ return command_hook_success (cmd );
75
+
73
76
payload = tlv_onionmsg_tlv_new (tmpctx );
74
77
payload -> invoice_error = tal_arr (payload , u8 , 0 );
75
78
towire_tlv_invoice_error (& payload -> invoice_error , err );
@@ -194,6 +197,13 @@ static struct command_result *createinvoice_done(struct command *cmd,
194
197
json_tok_full (buf , t ));
195
198
}
196
199
200
+ /* BOLT-recurrence #12:
201
+ * - if `invreq_recurrence_cancel` is present:
202
+ * - MUST NOT send an invoice in reply.
203
+ */
204
+ if (!ir -> reply_path )
205
+ return command_hook_success (cmd );
206
+
197
207
payload = tlv_onionmsg_tlv_new (tmpctx );
198
208
payload -> invoice = tal_steal (payload , rawinv );
199
209
return send_onion_reply (cmd , ir -> reply_path , payload );
@@ -206,13 +216,19 @@ static struct command_result *createinvoice_error(struct command *cmd,
206
216
struct invreq * ir )
207
217
{
208
218
u32 code ;
219
+ const char * status ;
209
220
210
221
/* If it already exists, we can reuse its bolt12 directly. */
211
222
if (json_scan (tmpctx , buf , err ,
212
- "{code:%}" , JSON_SCAN (json_to_u32 , & code )) == NULL
223
+ "{code:%,data:{status:%}}" ,
224
+ JSON_SCAN (json_to_u32 , & code ),
225
+ JSON_SCAN_TAL (tmpctx , json_strdup , & status )) == NULL
213
226
&& code == INVOICE_LABEL_ALREADY_EXISTS ) {
214
- return createinvoice_done (cmd , method , buf ,
215
- json_get_member (buf , err , "data" ), ir );
227
+ if (streq (status , "unpaid" ))
228
+ return createinvoice_done (cmd , method , buf ,
229
+ json_get_member (buf , err , "data" ), ir );
230
+ if (streq (status , "expired" ))
231
+ return fail_invreq (cmd , ir , "invoice expired (cancelled?)" );
216
232
}
217
233
return error (cmd , method , buf , err , ir );
218
234
}
@@ -359,6 +375,18 @@ static struct command_result *add_blindedpaths(struct command *cmd,
359
375
found_best_peer , ir );
360
376
}
361
377
378
+ static struct command_result * cancel_invoice (struct command * cmd ,
379
+ struct invreq * ir )
380
+ {
381
+ /* We create an invoice, so we can mark the cancellation, but with
382
+ * expiry 0. And we don't send it to them! */
383
+ * ir -> inv -> invoice_relative_expiry = 0 ;
384
+
385
+ /* In case they set a reply path! */
386
+ ir -> reply_path = tal_free (ir -> reply_path );
387
+ return create_invoicereq (cmd , ir );
388
+ }
389
+
362
390
static struct command_result * check_period (struct command * cmd ,
363
391
struct invreq * ir ,
364
392
u64 basetime )
@@ -470,6 +498,10 @@ static struct command_result *check_period(struct command *cmd,
470
498
}
471
499
}
472
500
501
+ /* If this is actually a cancel, we create an expired invoice */
502
+ if (ir -> invreq -> invreq_recurrence_cancel )
503
+ return cancel_invoice (cmd , ir );
504
+
473
505
return add_blindedpaths (cmd , ir );
474
506
}
475
507
@@ -618,14 +650,18 @@ static struct command_result *invreq_base_amount_simple(struct command *cmd,
618
650
* The reader:
619
651
*...
620
652
* - otherwise (no `offer_amount`):
621
- * - MUST reject the invoice request if it does not contain
622
- * `invreq_amount`.
653
+ * - MUST reject the invoice request if `invreq_recurrence_cancel`
654
+ * is not present and it does not contain `invreq_amount`.
623
655
*/
624
- err = invreq_must_have (cmd , ir , invreq_amount );
625
- if (err )
626
- return err ;
627
-
628
- * amt = amount_msat (* ir -> invreq -> invreq_amount );
656
+ if (!ir -> invreq -> invreq_recurrence_cancel ) {
657
+ err = invreq_must_have (cmd , ir , invreq_amount );
658
+ if (err )
659
+ return err ;
660
+ }
661
+ if (ir -> invreq -> invreq_amount )
662
+ * amt = amount_msat (* ir -> invreq -> invreq_amount );
663
+ else
664
+ * amt = AMOUNT_MSAT (0 );
629
665
}
630
666
return NULL ;
631
667
}
@@ -763,6 +799,7 @@ static struct command_result *listoffers_done(struct command *cmd,
763
799
bool active ;
764
800
struct command_result * err ;
765
801
struct amount_msat amt ;
802
+ struct tlv_invoice_request_invreq_recurrence_cancel * cancel ;
766
803
767
804
/* BOLT #12:
768
805
*
@@ -850,23 +887,27 @@ static struct command_result *listoffers_done(struct command *cmd,
850
887
851
888
/* BOLT #12:
852
889
* - if `offer_quantity_max` is present:
853
- * - MUST reject the invoice request if there is no `invreq_quantity` field.
890
+ * - MUST reject the invoice request if `invreq_recurrence_cancel`
891
+ * is not present and there is no `invreq_quantity` field.
854
892
* - if `offer_quantity_max` is non-zero:
855
893
* - MUST reject the invoice request if `invreq_quantity` is zero, OR greater than
856
894
* `offer_quantity_max`.
857
895
* - otherwise:
858
896
* - MUST reject the invoice request if there is an `invreq_quantity` field.
859
897
*/
860
898
if (ir -> invreq -> offer_quantity_max ) {
861
- err = invreq_must_have (cmd , ir , invreq_quantity );
862
- if (err )
863
- return err ;
899
+ if (!ir -> invreq -> invreq_recurrence_cancel ) {
900
+ err = invreq_must_have (cmd , ir , invreq_quantity );
901
+ if (err )
902
+ return err ;
903
+ }
864
904
865
- if (* ir -> invreq -> invreq_quantity == 0 )
905
+ if (ir -> invreq -> invreq_quantity && * ir -> invreq -> invreq_quantity == 0 )
866
906
return fail_invreq (cmd , ir ,
867
907
"quantity zero invalid" );
868
908
869
- if (* ir -> invreq -> offer_quantity_max &&
909
+ if (ir -> invreq -> invreq_quantity &&
910
+ * ir -> invreq -> offer_quantity_max &&
870
911
* ir -> invreq -> invreq_quantity > * ir -> invreq -> offer_quantity_max ) {
871
912
return fail_invreq (cmd , ir ,
872
913
"quantity %" PRIu64 " > %" PRIu64 ,
@@ -910,13 +951,18 @@ static struct command_result *listoffers_done(struct command *cmd,
910
951
* field.
911
952
* - MUST reject the invoice request if there is a `invreq_recurrence_start`
912
953
* field.
954
+ * - MUST reject the invoice request if there is a `invreq_recurrence_cancel`
955
+ * field.
913
956
*/
914
957
err = invreq_must_not_have (cmd , ir , invreq_recurrence_counter );
915
958
if (err )
916
959
return err ;
917
960
err = invreq_must_not_have (cmd , ir , invreq_recurrence_start );
918
961
if (err )
919
962
return err ;
963
+ err = invreq_must_not_have (cmd , ir , invreq_recurrence_cancel );
964
+ if (err )
965
+ return err ;
920
966
}
921
967
922
968
/* BOLT #12:
@@ -926,8 +972,12 @@ static struct command_result *listoffers_done(struct command *cmd,
926
972
* - MUST copy all non-signature fields from the invoice request (including
927
973
* unknown fields).
928
974
*/
975
+ /* But "invreq_recurrence_cancel" doesn't exist in invoices, so temporarily remove */
976
+ cancel = ir -> invreq -> invreq_recurrence_cancel ;
977
+ ir -> invreq -> invreq_recurrence_cancel = NULL ;
929
978
ir -> inv = invoice_for_invreq (cmd , ir -> invreq );
930
979
assert (ir -> inv -> invreq_payer_id );
980
+ ir -> invreq -> invreq_recurrence_cancel = cancel ;
931
981
932
982
/* BOLT #12:
933
983
* - if `offer_issuer_id` is present:
0 commit comments