Skip to content

Commit 0ddbe23

Browse files
committed
BOLT 12: Allow either optional or compulsory recurrence variants.
This allows the writer of the offer to decide how pre-recurrence-supporting wallets should behave. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
1 parent 08fc679 commit 0ddbe23

File tree

1 file changed

+30
-14
lines changed

1 file changed

+30
-14
lines changed

12-offer-encoding.md

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,11 @@ The human-readable prefix for offers is `lno`.
229229
1. type: 22 (`offer_issuer_id`)
230230
2. data:
231231
* [`point`:`id`]
232-
1. type: 24 (`offer_recurrence`)
232+
1. type: 24 (`offer_recurrence_compulsory`)
233+
2. data:
234+
* [`byte`:`time_unit`]
235+
* [`tu32`:`period`]
236+
1. type: 25 (`offer_recurrence_optional`)
233237
2. data:
234238
* [`byte`:`time_unit`]
235239
* [`tu32`:`period`]
@@ -273,6 +277,8 @@ Thus, each offer containing a recurring payment has:
273277

274278
Note that the `offer_absolute_expiry` field already covers the case where an offer is no longer valid after January 1st 2021.
275279

280+
For wallets which don't (yet) support recurrence, the basic recurrence field comes in two variants: `offer_recurrence_compulsory` if they should not attempt a payment, and `offer_recurrence_optional` if it still makes sense for them to attempt a single payment.
281+
276282
### Offer Period Calculation
277283

278284
Each period has a zero-based index, and a start time and an end time. Because the periods can be in non-seconds units, the duration of a period can depend on when it starts. The period with index N+1 begins immediately following the end of period with index N.
@@ -356,8 +362,10 @@ A writer of an offer:
356362
- MUST set `offer_quantity_max` to 0.
357363
- otherwise:
358364
- MUST NOT set `offer_quantity_max`.
359-
- MAY include `offer_recurrence` to indicate offer should trigger time-spaced invoice requests.
360-
- if it includes `offer_recurrence`:
365+
- If an offer MAY trigger time-spaced invoice requests:
366+
- MUST include exactly one of `offer_recurrence_optional` or `offer_recurrence_compulsory`.
367+
- SHOULD NOT use `offer_recurrence_optional` if a payment of a single period would be useless or misleading (older wallets).
368+
- if it includes either `offer_recurrence_optional` or `offer_recurrence_compulsory`:
361369
- MUST set `time_unit` to 0 (seconds), 1 (days), 2 (months) or 3 (years).
362370
- MUST set `period` to how often (in `time-unit`) it wants to be paid.
363371
- if there is a maximum number of payments:
@@ -418,13 +426,13 @@ A reader of an offer:
418426
- MUST warn the user if the received `invoice_amount` differs significantly
419427
from that estimate.
420428
- if the current time is after `offer_absolute_expiry`:
421-
- MUST NOT make an initial response to the offer (i.e. continuing an existing offer with `offer_recurrence` is ok)
422-
- if `offer_recurrence` is set:
429+
- MUST NOT make an initial response to the offer (i.e. continuing an existing offer with recurrence is ok)
430+
- if `offer_recurrence_optional` or `offer_recurrence_compulsory` are set:
423431
- if `time_unit` is not one of 0, 1, 2 or 3:
424432
- MUST NOT respond to the offer.
425433
- if `offer_recurrence_limit` is set and `max_period` is 0:
426434
- MUST NOT respond to the offer.
427-
- otherwise: (no `offer_recurrence`):
435+
- otherwise: (no recurrence):
428436
- if it `offer_recurrence_paywindow`, `offer_recurrence_limit` or `offer_recurrence_base` are set:
429437
- MUST NOT respond to the offer.
430438
- if it chooses to send an invoice request, it sends an onion message:
@@ -531,7 +539,11 @@ while still allowing signature validation.
531539
1. type: 22 (`offer_issuer_id`)
532540
2. data:
533541
* [`point`:`id`]
534-
1. type: 24 (`offer_recurrence`)
542+
1. type: 24 (`offer_recurrence_compulsory`)
543+
2. data:
544+
* [`byte`:`time_unit`]
545+
* [`tu32`:`period`]
546+
1. type: 25 (`offer_recurrence_optional`)
535547
2. data:
536548
* [`byte`:`time_unit`]
537549
* [`tu32`:`period`]
@@ -607,7 +619,7 @@ The writer:
607619
- MUST set `invreq_quantity` less than or equal to `offer_quantity_max`.
608620
- otherwise:
609621
- MUST NOT set `invreq_quantity`
610-
- if `offer_recurrence` is present:
622+
- if `offer_recurrence_optional` or `offer_recurrence_compulsory` are present:
611623
- for the initial request:
612624
- MUST use a unique `invreq_payer_id`.
613625
- MUST set `invreq_recurrence_counter` `counter` to 0.
@@ -692,7 +704,7 @@ The reader:
692704
- MAY reject the invoice request if `invreq_amount`.`msat` greatly exceeds the *expected amount*.
693705
- otherwise (no `offer_amount`):
694706
- MUST reject the invoice request if it does not contain `invreq_amount`.
695-
- if `offer_recurrence` is present:
707+
- if `offer_recurrence_optional` or `offer_recurrence_compulsory` are present:
696708
- MUST reject the invoice request if there is no `invreq_recurrence_counter` field.
697709
- if `offer_recurrence_base` is present:
698710
- MUST reject the invoice request if there is no `invreq_recurrence_start` field.
@@ -710,7 +722,7 @@ The reader:
710722
- SHOULD reject the invoice request if the current time is equal to or after the start of the period plus `seconds_after`.
711723
- otherwise:
712724
- SHOULD reject the invoice request if the current time is prior to the start of the previous period.
713-
- otherwise (no `offer_recurrence`):
725+
- otherwise (no recurrence):
714726
- MUST reject the invoice request if there is a `invreq_recurrence_counter` field.
715727
- MUST reject the invoice request if there is a `invreq_recurrence_start` field.
716728
- SHOULD send an invoice in response using the `onionmsg_tlv` `reply_path`.
@@ -802,7 +814,11 @@ the `onion_message` `invoice` field.
802814
1. type: 22 (`offer_issuer_id`)
803815
2. data:
804816
* [`point`:`id`]
805-
1. type: 24 (`offer_recurrence`)
817+
1. type: 24 (`offer_recurrence_compulsory`)
818+
2. data:
819+
* [`byte`:`time_unit`]
820+
* [`tu32`:`period`]
821+
1. type: 25 (`offer_recurrence_optional`)
806822
2. data:
807823
* [`byte`:`time_unit`]
808824
* [`tu32`:`period`]
@@ -949,7 +965,7 @@ A writer of an invoice:
949965
- for the bitcoin chain, it MUST set each `fallback_address` with
950966
`version` as a valid witness version and `address` as a valid witness
951967
program
952-
- if `offer_recurrence` is present:
968+
- if `offer_recurrence_optional` or `offer_recurrence_compulsory` are present:
953969
- MUST set `invoice_recurrence_basetime`.`basetime` to the start of period #0 as calculated by [Period Calculation](#offer-period-calculation).
954970
- if it sets `invoice_relative_expiry`:
955971
- MUST NOT set `invoice_relative_expiry`.`seconds_from_creation` more than the number of seconds after `invoice_created_at` that payment for this period will be accepted.
@@ -1007,7 +1023,7 @@ A reader of an invoice:
10071023
- MUST ignore any `fallback_address` for which `version` is greater than 16.
10081024
- MUST ignore any `fallback_address` for which `address` is less than 2 or greater than 40 bytes.
10091025
- MUST ignore any `fallback_address` for which `address` does not meet known requirements for the given `version`
1010-
- if `offer_recurrence` is present:
1026+
- if `offer_recurrence_optional` or `offer_recurrence_compulsory` are present:
10111027
- MUST reject the invoice if `invoice_recurrence_basetime` is not present.
10121028
- if `invreq_recurrence_counter` is 0:
10131029
- if `offer_recurrence_base` is present:
@@ -1024,7 +1040,7 @@ A reader of an invoice:
10241040
- MUST reject the invoice if it did not arrive via invoice request `onionmsg_tlv` `reply_path`.
10251041
- if it pays the invoice:
10261042
- MUST have authorization for the payment purpose, recipient and amount.
1027-
- if `offer_recurrence` is present:
1043+
- if `offer_recurrence_optional` or `offer_recurrence_compulsory` are present:
10281044
- SHOULD obtain single authorization which covers all expected payments.
10291045

10301046
## Rationale

0 commit comments

Comments
 (0)