@@ -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
}
@@ -372,6 +388,18 @@ static struct command_result *add_blindedpaths(struct command *cmd,
372
388
found_best_peer , ir );
373
389
}
374
390
391
+ static struct command_result * cancel_invoice (struct command * cmd ,
392
+ struct invreq * ir )
393
+ {
394
+ /* We create an invoice, so we can mark the cancellation, but with
395
+ * expiry 0. And we don't send it to them! */
396
+ * ir -> inv -> invoice_relative_expiry = 0 ;
397
+
398
+ /* In case they set a reply path! */
399
+ ir -> reply_path = tal_free (ir -> reply_path );
400
+ return create_invoicereq (cmd , ir );
401
+ }
402
+
375
403
static struct command_result * check_period (struct command * cmd ,
376
404
struct invreq * ir ,
377
405
u64 basetime )
@@ -483,6 +511,10 @@ static struct command_result *check_period(struct command *cmd,
483
511
}
484
512
}
485
513
514
+ /* If this is actually a cancel, we create an expired invoice */
515
+ if (ir -> invreq -> invreq_recurrence_cancel )
516
+ return cancel_invoice (cmd , ir );
517
+
486
518
return add_blindedpaths (cmd , ir );
487
519
}
488
520
@@ -626,19 +658,23 @@ static struct command_result *invreq_base_amount_simple(struct command *cmd,
626
658
627
659
* amt = amount_msat (raw_amount );
628
660
} else {
629
- /* BOLT #12:
661
+ /* BOLT-recurrence #12:
630
662
*
631
663
* The reader:
632
664
*...
633
665
* - otherwise (no `offer_amount`):
634
- * - MUST reject the invoice request if it does not contain
635
- * `invreq_amount`.
666
+ * - MUST reject the invoice request if `invreq_recurrence_cancel`
667
+ * is not present and it does not contain `invreq_amount`.
636
668
*/
637
- err = invreq_must_have (cmd , ir , invreq_amount );
638
- if (err )
639
- return err ;
640
-
641
- * amt = amount_msat (* ir -> invreq -> invreq_amount );
669
+ if (!ir -> invreq -> invreq_recurrence_cancel ) {
670
+ err = invreq_must_have (cmd , ir , invreq_amount );
671
+ if (err )
672
+ return err ;
673
+ }
674
+ if (ir -> invreq -> invreq_amount )
675
+ * amt = amount_msat (* ir -> invreq -> invreq_amount );
676
+ else
677
+ * amt = AMOUNT_MSAT (0 );
642
678
}
643
679
return NULL ;
644
680
}
@@ -776,6 +812,7 @@ static struct command_result *listoffers_done(struct command *cmd,
776
812
bool active ;
777
813
struct command_result * err ;
778
814
struct amount_msat amt ;
815
+ struct tlv_invoice_request_invreq_recurrence_cancel * cancel ;
779
816
780
817
/* BOLT #12:
781
818
*
@@ -861,25 +898,29 @@ static struct command_result *listoffers_done(struct command *cmd,
861
898
return fail_invreq (cmd , ir , "Offer expired" );
862
899
}
863
900
864
- /* BOLT #12:
901
+ /* BOLT-recurrence #12:
865
902
* - if `offer_quantity_max` is present:
866
- * - MUST reject the invoice request if there is no `invreq_quantity` field.
903
+ * - MUST reject the invoice request if `invreq_recurrence_cancel`
904
+ * is not present and there is no `invreq_quantity` field.
867
905
* - if `offer_quantity_max` is non-zero:
868
906
* - MUST reject the invoice request if `invreq_quantity` is zero, OR greater than
869
907
* `offer_quantity_max`.
870
908
* - otherwise:
871
909
* - MUST reject the invoice request if there is an `invreq_quantity` field.
872
910
*/
873
911
if (ir -> invreq -> offer_quantity_max ) {
874
- err = invreq_must_have (cmd , ir , invreq_quantity );
875
- if (err )
876
- return err ;
912
+ if (!ir -> invreq -> invreq_recurrence_cancel ) {
913
+ err = invreq_must_have (cmd , ir , invreq_quantity );
914
+ if (err )
915
+ return err ;
916
+ }
877
917
878
- if (* ir -> invreq -> invreq_quantity == 0 )
918
+ if (ir -> invreq -> invreq_quantity && * ir -> invreq -> invreq_quantity == 0 )
879
919
return fail_invreq (cmd , ir ,
880
920
"quantity zero invalid" );
881
921
882
- if (* ir -> invreq -> offer_quantity_max &&
922
+ if (ir -> invreq -> invreq_quantity &&
923
+ * ir -> invreq -> offer_quantity_max &&
883
924
* ir -> invreq -> invreq_quantity > * ir -> invreq -> offer_quantity_max ) {
884
925
return fail_invreq (cmd , ir ,
885
926
"quantity %" PRIu64 " > %" PRIu64 ,
@@ -923,13 +964,18 @@ static struct command_result *listoffers_done(struct command *cmd,
923
964
* field.
924
965
* - MUST reject the invoice request if there is a `invreq_recurrence_start`
925
966
* field.
967
+ * - MUST reject the invoice request if there is a `invreq_recurrence_cancel`
968
+ * field.
926
969
*/
927
970
err = invreq_must_not_have (cmd , ir , invreq_recurrence_counter );
928
971
if (err )
929
972
return err ;
930
973
err = invreq_must_not_have (cmd , ir , invreq_recurrence_start );
931
974
if (err )
932
975
return err ;
976
+ err = invreq_must_not_have (cmd , ir , invreq_recurrence_cancel );
977
+ if (err )
978
+ return err ;
933
979
}
934
980
935
981
/* BOLT #12:
@@ -939,8 +985,12 @@ static struct command_result *listoffers_done(struct command *cmd,
939
985
* - MUST copy all non-signature fields from the invoice request (including
940
986
* unknown fields).
941
987
*/
988
+ /* But "invreq_recurrence_cancel" doesn't exist in invoices, so temporarily remove */
989
+ cancel = ir -> invreq -> invreq_recurrence_cancel ;
990
+ ir -> invreq -> invreq_recurrence_cancel = NULL ;
942
991
ir -> inv = invoice_for_invreq (cmd , ir -> invreq );
943
992
assert (ir -> inv -> invreq_payer_id );
993
+ ir -> invreq -> invreq_recurrence_cancel = cancel ;
944
994
945
995
/* BOLT #12:
946
996
* - if `offer_issuer_id` is present:
0 commit comments