mirror of
https://github.com/lightning/bolts.git
synced 2025-03-13 19:37:31 +01:00
Support async payments in BOLT 12.
This builds on prior commits by adding the ability to fetch an invoice from an always-online node on behalf of an often-offline recipient, e.g. a mobile node. The idea is that often-offline recipients will supply some always-online node such as their wallet vendor with a static (i.e. `payment_hash`-less) invoice to return on its behalf. The recipient will then publish an offer containing blinded paths that terminate at this always-online node, who payers can request the invoice from if the recipient is offline at the time. After receiving the static invoice, payers will commence the protocol outlined in [1] to send the HTLC asynchronously. [1]: https://lists.linuxfoundation.org/pipermail/lightning-dev/2021-October/003307.html
This commit is contained in:
parent
625994f250
commit
e8efd2c12d
3 changed files with 92 additions and 16 deletions
|
@ -214,6 +214,9 @@ This is formatted according to the Type-Length-Value format defined in [BOLT #1]
|
|||
1. type: 18 (`total_amount_msat`)
|
||||
2. data:
|
||||
* [`tu64`:`total_msat`]
|
||||
1. type: 5482373484 (`sender_provided_payment_preimage`)
|
||||
2. data:
|
||||
* [`32*byte`:`payment_preimage`]
|
||||
|
||||
`short_channel_id` is the ID of the outgoing channel used to route the
|
||||
message; the receiving peer should operate the other end of this channel.
|
||||
|
@ -240,6 +243,9 @@ The requirements ensure consistency in responding to an unexpected
|
|||
`outgoing_cltv_value`, whether it is the final node or not, to avoid
|
||||
leaking its position in the route.
|
||||
|
||||
`sender_provided_payment_preimage` is set in the case that the recipient is
|
||||
often-offline and another node provided a static BOLT 12 invoice on their behalf.
|
||||
|
||||
### Requirements
|
||||
|
||||
The creator of `encrypted_recipient_data` (usually, the recipient of payment):
|
||||
|
@ -273,6 +279,12 @@ The writer of the TLV `payload`:
|
|||
- MUST use the current block height as a baseline value.
|
||||
- if a [random offset](07-routing-gossip.md#recommendations-for-routing) was added to improve privacy:
|
||||
- SHOULD add the offset to the baseline value.
|
||||
- if paying to a static BOLT 12 invoice:
|
||||
- MUST set `sender_provided_payment_preimage` to randomly generated unique bytes.
|
||||
- MUST set `update_add_htlc.payment_hash` to match the SHA256 hash of
|
||||
`sender_provided_payment_preimage`.
|
||||
- otherwise:
|
||||
- MUST NOT set `sender_provided_payment_preimage`.
|
||||
- MUST NOT include any other tlv field.
|
||||
- For every node outside of a blinded route:
|
||||
- MUST include `amt_to_forward` and `outgoing_cltv_value`.
|
||||
|
@ -324,6 +336,7 @@ The reader:
|
|||
- MUST return an error if `amt_to_forward` is below what it expects for the payment.
|
||||
- MUST return an error if incoming `cltv_expiry` < `outgoing_cltv_value`.
|
||||
- MUST return an error if incoming `cltv_expiry` < `current_block_height` + `min_final_cltv_expiry_delta`.
|
||||
- MUST use `sender_provided_payment_preimage` when claiming the HTLC, if present
|
||||
- Otherwise (it is not part of a blinded route):
|
||||
- MUST return an error if `path_key` is set in the incoming `update_add_htlc` or `current_path_key` is present.
|
||||
- MUST return an error if `amt_to_forward` or `outgoing_cltv_value` are not present.
|
||||
|
|
|
@ -29,6 +29,7 @@ The Context column decodes as follows:
|
|||
* `C+`: presented in the `channel_announcement` message, but always even (required).
|
||||
* `9`: presented in [BOLT 11](11-payment-encoding.md) invoices.
|
||||
* `B`: presented in the `allowed_features` field of a blinded path.
|
||||
* `R`: presented in [BOLT 12](12-offers.md) invoice requests.
|
||||
|
||||
| Bits | Name | Description | Context | Dependencies | Link |
|
||||
|-------|-----------------------------------|-----------------------------------------------------------|----------|---------------------------|-----------------------------------------------------------------------|
|
||||
|
@ -52,8 +53,14 @@ The Context column decodes as follows:
|
|||
| 48/49 | `option_payment_metadata` | Payment metadata in tlv record | 9 | | [BOLT #11](11-payment-encoding.md#tagged-fields) |
|
||||
| 50/51 | `option_zeroconf` | Understands zeroconf channel types | IN | `option_scid_alias` | [BOLT #2][bolt02-channel-ready] |
|
||||
| 52/53 | `option_htlc_hold` | Hold HTLCs and forward on receipt of an onion message | IN | `option_onion_messages` |
|
||||
| 56/57 | `option_om_mailbox` | Store-and-forward onion messages for often-offline peers | IN | `option_onion_messages` | [BOLT #12](bolt12-offers.md) |
|
||||
| 59 | `static_invoice_pay` | Supports paying BOLT 12 static invoices | R | `option_onion_messages` | [BOLT #12](bolt12-offers.md) |
|
||||
|
||||
|
||||
We define `option_om_mailbox` as the ability to store an onion message on behalf
|
||||
of an offline peer, and forward it once the peer comes online (subject to rate
|
||||
limiting).
|
||||
|
||||
## Requirements
|
||||
|
||||
The origin node:
|
||||
|
|
|
@ -42,7 +42,7 @@ Here we use "user" as shorthand for the individual user's lightning
|
|||
node and "merchant" as the shorthand for the node of someone who is
|
||||
selling or has sold something.
|
||||
|
||||
There are two basic payment flows supported by BOLT 12:
|
||||
There are three basic payment flows supported by BOLT 12:
|
||||
|
||||
The general user-pays-merchant flow is:
|
||||
1. A merchant publishes an *offer*, such as on a web page or a QR code.
|
||||
|
@ -58,6 +58,19 @@ The merchant-pays-user flow (e.g. ATM or refund):
|
|||
3. The merchant confirms the *invoice_node_id* to ensure it's about to pay the correct
|
||||
person, and makes a payment to the invoice.
|
||||
|
||||
The pay-mobile-user flow (e.g. paying a friend back to their mobile node):
|
||||
1. The mobile user supplies some always-online node with a static (i.e.
|
||||
`payment_hash`-less) invoice to return on its behalf. This always-online node may
|
||||
be the mobile user's channel counterparty, wallet vendor, or another node on the
|
||||
network that it has an out-of-band relationship with.
|
||||
2. The mobile user publishes an offer that contains blinded paths that terminate
|
||||
at the always-online node.
|
||||
3. The payer sends an `invoice_request` to the always-online node, who replies
|
||||
with the static invoice previously provided by the mobile user if the mobile user
|
||||
is offline. If they are online, the `invoice_request` is forwarded to the mobile
|
||||
user as usual.
|
||||
4. The payer makes a payment to the mobile user as indicated by the invoice.
|
||||
|
||||
## Payment Proofs and Payer Proofs
|
||||
|
||||
Note that the normal lightning "proof of payment" can only demonstrate that an
|
||||
|
@ -70,6 +83,9 @@ to request the invoice. In addition, the Merkle construction of the BOLT 12
|
|||
invoice signature allows the user to reveal invoice fields in case
|
||||
of a dispute selectively.
|
||||
|
||||
Payers will not get proofs in the case that they received a static invoice from the
|
||||
payee, see the pay-mobile-user flow above.
|
||||
|
||||
# Encoding
|
||||
|
||||
Each of the forms documented here are in
|
||||
|
@ -261,8 +277,9 @@ A writer of an offer:
|
|||
after midnight 1 January 1970, UTC that invoice_request should not be
|
||||
attempted.
|
||||
- if it is connected only by private channels:
|
||||
- MUST include `offer_paths` containing one or more paths to the node from
|
||||
publicly reachable nodes.
|
||||
- MUST include `offer_paths` containing one or more paths to the node
|
||||
that will reply to the `invoice_request`, using introduction nodes that are
|
||||
publicly reachable.
|
||||
- otherwise:
|
||||
- MAY include `offer_paths`.
|
||||
- if it includes `offer_paths`:
|
||||
|
@ -282,6 +299,8 @@ A writer of an offer:
|
|||
- MUST set `offer_quantity_max` to 0.
|
||||
- otherwise:
|
||||
- MUST NOT set `offer_quantity_max`.
|
||||
- if it is often-offline and the invoice may be provided by another node on their behalf:
|
||||
- MUST NOT include more than 1 chain in `offer_chains`.
|
||||
|
||||
A reader of an offer:
|
||||
- if the offer contains any TLV fields outside the inclusive ranges: 1 to 79 and 1000000000 to 1999999999:
|
||||
|
@ -441,6 +460,20 @@ while still allowing signature validation.
|
|||
2. data:
|
||||
* [`bip340sig`:`sig`]
|
||||
|
||||
## Invoice Request Features
|
||||
|
||||
| Bits | Description | Name |
|
||||
|------|----------------------------------|-----------------------------|
|
||||
| 59 | Supports paying static invoices | static_invoice_pay/optional |
|
||||
|
||||
Setting `static_invoice_pay` indicates that the payer supports receiving a
|
||||
`payment_hash`-less invoice in response to their `invoice_request`, and
|
||||
subsequently setting `sender_provided_payment_preimage` in their payment onion.
|
||||
|
||||
Useful if the payee is often offline and the invoice is being returned on
|
||||
their behalf by another node, to avoid trusting that other node to not reuse a
|
||||
`payment_hash`.
|
||||
|
||||
## Requirements for Invoice Requests
|
||||
|
||||
The writer:
|
||||
|
@ -530,7 +563,14 @@ The reader:
|
|||
- MUST reject the invoice request if bitcoin is not a supported chain.
|
||||
- otherwise:
|
||||
- MUST reject the invoice request if `invreq_chain`.`chain` is not a supported chain.
|
||||
|
||||
- if receiving the `invoice_request` on behalf of an often-offline payee:
|
||||
- if the payee is online:
|
||||
- MUST forward the `invoice_request` to the payee
|
||||
- otherwise (payee is offline):
|
||||
- if `invreq_features` supports `static_invoice_pay`:
|
||||
- MUST reply with the static invoice previously provided by the payee
|
||||
- otherwise:
|
||||
- MUST reply with `invoice_error`
|
||||
|
||||
## Rationale
|
||||
|
||||
|
@ -561,10 +601,11 @@ The requirement to use `offer_paths` if present, ensures a node does not reveal
|
|||
|
||||
# Invoices
|
||||
|
||||
Invoices are a payment request, and when the payment is made,
|
||||
the payment preimage can be combined with the invoice to form a cryptographic receipt.
|
||||
Invoices are a payment request. If `invoice_payment_hash` is set, then when the
|
||||
payment is made, the payment preimage can be combined with the invoice to form a
|
||||
cryptographic receipt.
|
||||
|
||||
The recipient sends an `invoice` in response to an `invoice_request` using
|
||||
The recipient creates an `invoice` for responding to an `invoice_request` using
|
||||
the `onion_message` `invoice` field.
|
||||
|
||||
1. `tlv_stream`: `invoice`
|
||||
|
@ -653,6 +694,9 @@ the `onion_message` `invoice` field.
|
|||
1. type: 176 (`invoice_node_id`)
|
||||
2. data:
|
||||
* [`point`:`node_id`]
|
||||
1. type: 178 (`invoice_message_paths`)
|
||||
2. data:
|
||||
* [`...*blinded_path`:`paths`]
|
||||
1. type: 240 (`signature`)
|
||||
2. data:
|
||||
* [`bip340sig`:`sig`]
|
||||
|
@ -691,17 +735,21 @@ may (due to capacity limits on a single channel) require it.
|
|||
A writer of an invoice:
|
||||
- MUST set `invoice_created_at` to the number of seconds since Midnight 1
|
||||
January 1970, UTC when the invoice was created.
|
||||
- MUST set `invoice_amount` to the minimum amount it will accept, in units of
|
||||
the minimal lightning-payable unit (e.g. milli-satoshis for bitcoin) for
|
||||
`invreq_chain`.
|
||||
- if the invoice is in response to an `invoice_request`:
|
||||
- if `invoice_payment_hash` is set and the invoice is in response to an `invoice_request`:
|
||||
- MUST copy all non-signature fields from the invoice request (including unknown fields).
|
||||
- if `invreq_amount` is present:
|
||||
- MUST set `invoice_amount` to `invreq_amount`
|
||||
- otherwise:
|
||||
- MUST set `invoice_amount` to the *expected amount*.
|
||||
- MUST set `invoice_payment_hash` to the SHA256 hash of the
|
||||
`payment_preimage` that will be given in return for payment.
|
||||
- if the invoice is intended to be provided by a node other than the recipient:
|
||||
- MUST NOT set `invoice_payment_hash`.
|
||||
- MUST NOT set `invoice_amount`.
|
||||
- MUST include `invoice_message_paths` containing at least two paths to
|
||||
the recipient, where the penultimate hop supports `option_om_mailbox`.
|
||||
- MUST NOT set any `invoice_request` TLV fields
|
||||
- otherwise:
|
||||
- MUST set `invoice_payment_hash` to the SHA256 hash of the
|
||||
`payment_preimage` that will be given in return for payment.
|
||||
- if `offer_issuer_id` is present:
|
||||
- MUST set `invoice_node_id` to the `offer_issuer_id`
|
||||
- otherwise, if `offer_paths` is present:
|
||||
|
@ -727,11 +775,14 @@ A writer of an invoice:
|
|||
- MUST include `invoice_blindedpay` with exactly one `blinded_payinfo` for each `blinded_path` in `paths`, in order.
|
||||
- MUST set `features` in each `blinded_payinfo` to match `encrypted_data_tlv`.`allowed_features` (or empty, if no `allowed_features`).
|
||||
- SHOULD ignore any payment which does not use one of the paths.
|
||||
- if providing invoices on behalf of an often offline recipient:
|
||||
- MAY reuse the previous invoice.
|
||||
|
||||
A reader of an invoice:
|
||||
- MUST reject the invoice if `invoice_amount` is not present.
|
||||
- MUST reject the invoice if `invoice_created_at` is not present.
|
||||
- MUST reject the invoice if `invoice_payment_hash` is not present.
|
||||
- if `static_invoice_pay` was not supported in `invreq_features`:
|
||||
- MUST reject the invoice if `invoice_payment_hash` is not present.
|
||||
- MUST reject the invoice if `invoice_amount` is not present.
|
||||
- MUST reject the invoice if `invoice_node_id` is not present.
|
||||
- if `invreq_chain` is not present:
|
||||
- MUST reject the invoice if bitcoin is not a supported chain.
|
||||
|
@ -753,7 +804,8 @@ A reader of an invoice:
|
|||
- MUST NOT use the corresponding `invoice_paths`.`path` if `payinfo`.`features` has any unknown even bits set.
|
||||
- MUST reject the invoice if this leaves no usable paths.
|
||||
- if the invoice is a response to an `invoice_request`:
|
||||
- MUST reject the invoice if all fields in ranges 0 to 159 and 1000000000 to 2999999999 (inclusive) do not exactly match the invoice request.
|
||||
- if `invoice_payment_hash` is set:
|
||||
- MUST reject the invoice if all fields in ranges 0 to 159 and 1000000000 to 2999999999 (inclusive) do not exactly match the invoice request.
|
||||
- if `offer_issuer_id` is present (invoice_request for an offer):
|
||||
- MUST reject the invoice if `invoice_node_id` is not equal to `offer_issuer_id`
|
||||
- otherwise, if `offer_paths` is present (invoice_request for an offer without id):
|
||||
|
@ -782,6 +834,10 @@ A reader of an invoice:
|
|||
- MUST reject the invoice if it arrived via a blinded path.
|
||||
- otherwise (derived from an offer):
|
||||
- MUST reject the invoice if it did not arrive via invoice request `onionmsg_tlv` `reply_path`.
|
||||
- if `invoice_payment_hash` is unset:
|
||||
- MUST reject the invoice if `invoice_message_paths` is not present or is empty.
|
||||
- MUST pay asynchronously using the `held_htlc_available` onion message
|
||||
flow, where the onion message is sent over `invoice_message_paths`.
|
||||
|
||||
## Rationale
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue