Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Offers #798

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open

Offers #798

wants to merge 23 commits into from

Conversation

rustyrussell
Copy link
Collaborator

@rustyrussell rustyrussell commented Aug 31, 2020

Offers are "static invoices", with many more features. This is mostly implemented in c-lightning already, and is now ready for wider testing.

This PR is based on onion messages specified in #759

04-onion-routing.md Outdated Show resolved Hide resolved
04-onion-routing.md Outdated Show resolved Hide resolved
@@ -366,6 +367,93 @@ otherwise meets the amount criterion (eg. some other failure, or
invoice timeout), however if it were to fulfill only some of them,
intermediary nodes could simply claim the remaining ones.

### Onion Messages
Copy link
Collaborator

@t-bast t-bast Sep 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering whether this should be in Bolt 4, a separate bolt dedicated to (remote) node-to-node messaging may be worth creating, if only to provide better separation of the TLV namespaces (since those will not be interpreted by the Bolt 4 layer but rather higher level component after decryption).

09-features.md Outdated Show resolved Hide resolved
13-offer-encoding.md Outdated Show resolved Hide resolved
13-offer-encoding.md Outdated Show resolved Hide resolved
13-offer-encoding.md Outdated Show resolved Hide resolved
13-offer-encoding.md Outdated Show resolved Hide resolved
13-offer-encoding.md Outdated Show resolved Hide resolved
13-offer-encoding.md Outdated Show resolved Hide resolved
Copy link
Contributor

@dr-orlovsky dr-orlovsky left a comment

Gave an initial read, really like the concept.

With the new developments in miniscript and descriptors the need for invoices is more generic than simple LN: maybe some common format solving bech23 and miniscript use problems as well?

As you probably remember, I am working on RGB: assets & smart contracts over bitcoin and LN with Peter Todd client-side validation paradigms (not tx space use, pure L2/L3) backed by Bitfinex and USDT. In this regard we need shared extensible multi-asset invoice format, preferably with confidential asset support as well.

01-messaging.md Show resolved Hide resolved
13-offer-encoding.md Outdated Show resolved Hide resolved
13-offer-encoding.md Outdated Show resolved Hide resolved
Each form is signed using one or more TLV signature elements; TLV types
240 through 1000 are considered signature elements.

The only currently defined signature TLV is the secp256k1 signature of
Copy link
Contributor

@dr-orlovsky dr-orlovsky Sep 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Schnorr or ECDSA? Secp256k1 will soon have both...

Copy link
Collaborator Author

@rustyrussell rustyrussell Oct 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Schnorr, I should correct! This should refer to BIP-340

13-offer-encoding.md Outdated Show resolved Hide resolved
11-payment-encoding.md Outdated Show resolved Hide resolved
07-routing-gossip.md Outdated Show resolved Hide resolved
13-offer-encoding.md Outdated Show resolved Hide resolved
@rustyrussell rustyrussell marked this pull request as ready for review Apr 16, 2021
@rustyrussell rustyrussell changed the title DRAFT: Offers Offers Apr 16, 2021
@rustyrussell
Copy link
Collaborator Author

@rustyrussell rustyrussell commented Apr 16, 2021

I have merged the million-fixup-commits into one commit, and trivially rebased onto the updated #759.

The last two commits are new:

  1. Make spelling happy.
  2. Add a method to replace invoices; I've not yet implemented this though!

@renepickhardt
Copy link
Contributor

@renepickhardt renepickhardt commented Apr 16, 2021

I have a question with respect to replacing invoices and the fact that we can proof if the payee claimed both htlcs:

What is the use of that? As far as I understand we could sue the person but this won't give us a cryptographic guarantee to get our money back as even a convicted person might have run or just have already spent the money. Or do I miss something?

The only fix that cryptographically would give us a guarantee to not pay twice that I can think of only seems to shift the problem of stuck payments (and would thus create a burden to the network) and is the following:

  • Assume Alice sends out an onion to Bob over some path that gets stuck
  • Alice wants to use your replacement mechanism to cancle the payment.
  • before (!) sending out a new onion with the new payment hash alice waits for an incoming htlc of the old payment hash (this assumes that Bob after sending out the replacement invoice sets a "reimbursement path" to Alice.

Now we have 2 scenarios:

  1. The orinal payment times out and gets unstuck. Alice would also cancle the reimbursement payment (of course opening Bob to a stuck payment attack from Alice or actually from anyone else when he sets up the reimbursement path)
  2. The original onion arrives at Bob. He should fail the onion and if so Alice should fail the reimbursement onion once her initial htlc is withdrawn or if Bob claims the funds Alice can use the preimage on the reimbursement path to claim her money back.

As said initially: I don't think the reimbursement path (which is by the way inspired by the boomerang paper c.f.: https://arxiv.org/abs/1910.01834 ) solves any issue in our case because the reimbursement path is also open to stuck payment attacks and overall we bind liquidity in two directions now.

…nels.

Suggested-by: @bluematt
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
- MAY append additional information to `description` (e.g. " +shipping").
- if it does not set `amount` to the *base invoice amount* calculated from the invoice_request:
- MUST append the reason to `description` (e.g. " 5% bulk discount").

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should change the description or the amount here.
The offer should lay out all the terms of the payment and the invoice request should be seen as an agreement with the terms of the offer and a willingness to pay immediately. Everything that comes after (the invoice and the payment itself) should be technicalities that can stay hidden from the user.
If you think it's desirable to add extra costs for shipping or bulk discount, these should be part of the offer.

Copy link
Collaborator Author

@rustyrussell rustyrussell Mar 10, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, you cannot do this. For example, you don't know shipping costs until after presented (future extension) with the address in the invoice_request.

Of course, it's unusual, and hence the requirement to annotate the description.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's for a future extension, then it should be added in the future extension, not now.

It also means that the amount in the invoice may be completely different from the amount in the request, it goes against what you wrote in the rationale of the invoice request:

Users can give a tip (or obscure the amount sent) by specifying an amount in their invoice request, even though the offer specifies an amount.

I've rounded the amount to increase my privacy and now the invoice asks me to pay an amount that would leak my shipping address!

- MAY append additional information to `description` (e.g. " +shipping").
- if it does not set `amount` to the *base invoice amount* calculated from the invoice_request:
- MUST append the reason to `description` (e.g. " 5% bulk discount").

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should change the description or the amount here.
The offer should lay out all the terms of the payment and the invoice request should be seen as an agreement with the terms of the offer and a willingness to pay immediately. Everything that comes after (the invoice and the payment itself) should be technicalities that can stay hidden from the user.
If you think it's desirable to add extra costs for shipping or bulk discount, these should be part of the offer.

Use " not ` for string literals.

And remove merkle test which used now-removed fields.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
@jb55
Copy link
Contributor

@jb55 jb55 commented Mar 24, 2022

I just finished reading up on stateless bolt11 invoices (#912), would there be a similar mechanism for bolt12 invoices? would it just be a matter of including the payment_metadata tlv or are there other considerations?

@thomash-acinq
Copy link

@thomash-acinq thomash-acinq commented Mar 24, 2022

I just finished reading up on stateless bolt11 invoices (#912), would there be a similar mechanism for bolt12 invoices? would it just be a matter of including the payment_metadata tlv or are there other considerations?

With blinded routes, you can include any payment_metadata you want in the last blinded payload.

@jb55
Copy link
Contributor

@jb55 jb55 commented Mar 24, 2022

@thomash-acinq: ah yes I just found this comment by @t-bast which mentioned this. neat, thx!

thomash-acinq added a commit to ACINQ/eclair that referenced this issue Apr 13, 2022
Add types for representing offers and Bolt12 invoices (lightning/bolts#798)
@0xAsteria
Copy link

@0xAsteria 0xAsteria commented Apr 18, 2022

Hey everyone, super pumped for BOLT12. One thing: is there a way we could add a signature to this offer? As an example, I have a website that's presenting a BOLT12 invoice for payment. However, there is a malicious web extension in the browser, which swaps the QR/invoice on the page. User pays the attacker and payment flow gets broken.

Is there a way we can add a recoverable, compressed secp256k1 signature to the offer, as well as a domain? This would (1) allow us to verify public key of the signature with public key available at the domain (whether through DNS or HTTPS, haven't decided yet), letting us put a big green checkmark in the user's wallet to show they're indeed paying the company they want to.

And (2) would then allow us to do info fetching outside payment flow. For example, fetching an image of the company's logo and formatted company name to display in the wallet (which is very useful for UX).

If not and we want to keep this down, that's okay too. We'll likely be looking at building another specification which would incorporate a BOLT12 and other features, and we could add this functionality in there.

@thomash-acinq
Copy link

@thomash-acinq thomash-acinq commented Apr 19, 2022

Yes, it is optional but the offer can include a signature if you want. However I would expect most offers to not be signed to fit in smaller QR codes. But even if the offer is not signed, the invoice will be, so any check that would have done on the offer can be done on the invoice.

@0xAsteria
Copy link

@0xAsteria 0xAsteria commented Apr 19, 2022

Thanks, this makes a lot of sense. Assuming we don't put a signature in the offer, could we add some sort of domain field then? Actually, rather than adding it directly into BOLT12 which could bloat it, it would probably be optimal to do this in a wrapper protocol, right? Maybe the domain approves a certain list of node IDs that it owns and that is available outside LN.

- if it is connected only by private channels:
- if no node connecting a private channel supports blinded payments:
- MUST include `desthint` containing the private channel information.
- otherwise:
- MUST include `blinded_path` containing one or more paths to the node.
- otherwise:
- MAY include `blinded_path`.
Copy link

@thomash-acinq thomash-acinq Apr 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should make blinded_path mandatory. The recipient can always create a single node blinded route that has the added benefit of having an encrypted_recipient_data compared to just using a public node id. If the invoice only has a public node id, there is no way to provide payment_secret or payment_metadata which are valuable features.

desthint just adds complexity for a case that will almost never happen in practice: the recipient is a private node, it wants to use offers and it is connected to a public node that support route blinding for onion messages (otherwise the recipient is not reachable by onion message and can't use offers anyways) but not route blinding for payments.

rustyrussell added 2 commits Jun 7, 2022
You're either making up the node_id anyway, or you don't need to blind
it.  Saves some space.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
The reader can do it, and this avoids having to separately specify the
`first_node_id`.

Also clarify when using the path is mandatory.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
- if it supports offer features:
- SHOULD set `features` to the bitmap of offer features.
Copy link

@jkczyz jkczyz Jun 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are offer features a new context in BOLT 9 parlance? Additionally, how do the features in an offer differ from those in invoice_request and invoice, if at all.

- if it has bolt11 features:
- MUST set `features` to the bitmap of features.
Copy link

@jkczyz jkczyz Jun 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to my earlier question, is the "bolt11" qualifier here meant to distinguish these features from those in the offer?

1. type: 16 (`paths`)
2. data:
* [`...*blinded_path`:`paths`]
Copy link

@jkczyz jkczyz Jun 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Terminology-wise, is there a difference between a blinded path and a blinded route? BOLT 4 uses the latter while BOLT 12 uses the former.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's the same.

{
"comment": "A complete string is valid",
"valid": true,
"string": "lno1qcp4256ypqpq86q2pucnq42ngssx2an9wfujqerp0y2pqun4wd68jtn00fkxzcnn9ehhyec6qgqsz83qfwdpl28qqmc78ymlvhmxcsywdk5wrjnj36jryg488qwlrnzyjczlqsp9nyu4phcg6dqhlhzgxagfu7zh3d9re0sqp9ts2yfugvnnm9gxkcnnnkdpa084a6t520h5zhkxsdnghvpukvd43lastpwuh73k29qsy"
Copy link

@jkczyz jkczyz Jun 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the test vectors contain fields that have been removed from the BOLT. Do you have any updated ones that I can use for testing?

1. subtype: `blinded_path`
2. data:
* [`point`:`blinding`]
* [`byte`:`num_hops`]
Copy link

@jkczyz jkczyz Jun 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this field necessary / desirable? Seems the number of hops can be determined from the TLV length (I think). And BOLT 1 recommends avoiding encoding the length twice where it can be avoided.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blinded_path is not a TLV. The TLV contains a list of blinded_path so there is no way to derive the number of hops from the TLV length.

Copy link

@jkczyz jkczyz Jul 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes, I see. The test vectors weren't exercising this since they don't contain blinded paths. FWIW, here's one that does albeit using junk data:

lno1qcp4256ypqpq86q2pucnq42ngssx2an9wfujqerp0yg06qg2qdd7t628sgykwj5kuc837qmlv9m9gr7sq8ap6erfgacv26nhp8zzcqgzhdvttlk22pw8fmwqqrvzst792mj35ypylj886ljkcmug03wg6heqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq6muh550qsfva9fdes0ruph7ctk2s8aqq06r4jxj3msc448wzwy9sqs9w6ckhlv55zuwnkuqqxc9qhu24h9rggzflyw04l9d3hcslzu340jqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq2pqun4wd68jtn00fkxzcnn9ehhyec6qgqsz83qfwdpl28qqmc78ymlvhmxcsywdk5wrjnj36jryg488qwlrnzyjczlqsp9nyu4phcg6dqhlhzgxagfu7zh3d9re0sqp9ts2yfugvnnm9gxkcnnnkdpa084a6t520h5zhkxsdnghvpukvd43lastpwuh73k29qsy

Copy link

@0xAsteria 0xAsteria left a comment

A few grammar/readability changes :)


# Limitations of BOLT 11

The BOLT 11 invoice format has proven popular, but has several

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The BOLT 11 invoice format has proven popular, but has several
The BOLT 11 invoice format has proven popular but has several

limitations:

1. The entangling of bech32 encoding makes it awkward to send
in other forms (e.g. inside the lightning network itself).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
in other forms (e.g. inside the lightning network itself).
in other forms (e.g, inside the lightning network itself).

2. The signature applying to the entire invoice makes it impossible
to prove an invoice without revealing its entirety.
3. Fields cannot generally be extracted for external use: the `h`
field was a boutique extraction of the `d` field, only.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
field was a boutique extraction of the `d` field, only.
field was a boutique extraction of the `d` field only.

to prove an invoice without revealing its entirety.
3. Fields cannot generally be extracted for external use: the `h`
field was a boutique extraction of the `d` field, only.
4. The lack of 'it's OK to be odd' rule makes backwards compatibility

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
4. The lack of 'it's OK to be odd' rule makes backwards compatibility
4. The lack of the 'it's OK to be odd' rule makes backward compatibility

7. The `payment_secret` designed to prevent probing by other nodes in
the path was only useful if the invoice remained private between the
payer and payee.
8. Invoices must be given per-user, and are actively dangerous if two

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
8. Invoices must be given per-user, and are actively dangerous if two
8. Invoices must be given per user and are actively dangerous if two


`replace_invoice` allows the mutually-agreed removal of and old unpaid
invoice; this can be used in the case of stuck payments. If
successful in replacing the stuck invoice, the sender may make a

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
successful in replacing the stuck invoice, the sender may make a
the sender successfully replaces the stuck invoice, they may make a

`replace_invoice` allows the mutually-agreed removal of and old unpaid
invoice; this can be used in the case of stuck payments. If
successful in replacing the stuck invoice, the sender may make a
second payment such that it can prove double-payment should the

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
second payment such that it can prove double-payment should the
second payment so that it can prove double-payment should the

Invoices are a request for payment, and when the payment is made
it can be combined with the invoice to form a cryptographic receipt.

The human-readable prefix for invoices is `lni`. It can be sent in

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The human-readable prefix for invoices is `lni`. It can be sent in
The human-readable prefix for invoices is `lni`. The recipient can send it in

invoice signature allows the user to selectively reveal fields of the invoice
in case of dispute.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
invoice signature allows the user to selectively reveal fields of the invoice
in case of dispute.
invoice signature allows the user to reveal invoice fields in case
of a dispute selectively.

- MAY ignore any invoice_request which does not use one of the `paths`.
- MUST NOT blind the first `onionmsg_path` `node_id` point.
- if it sets `issuer`:
- SHOULD set it to clearly identify the issuer of the invoice.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- SHOULD set it to clearly identify the issuer of the invoice.
- SHOULD set it to identify the issuer of the invoice clearly.

@thomash-acinq
Copy link

@thomash-acinq thomash-acinq commented Jul 1, 2022

Submitted a PR to force the use blinded routes when paying: rustyrussell#4

any). Note that for recurring invoices with `proportional_amount`
set, the `amount` in the invoice request will be scaled by the time in
the period; the sender should not attempt to scale it.
Copy link

@jkczyz jkczyz Jul 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this should be removed as it pertains to recurring invoices.

1. subtype: `blinded_path`
2. data:
* [`point`:`blinding`]
* [`byte`:`num_hops`]
Copy link

@jkczyz jkczyz Jul 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes, I see. The test vectors weren't exercising this since they don't contain blinded paths. FWIW, here's one that does albeit using junk data:

lno1qcp4256ypqpq86q2pucnq42ngssx2an9wfujqerp0yg06qg2qdd7t628sgykwj5kuc837qmlv9m9gr7sq8ap6erfgacv26nhp8zzcqgzhdvttlk22pw8fmwqqrvzst792mj35ypylj886ljkcmug03wg6heqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq6muh550qsfva9fdes0ruph7ctk2s8aqq06r4jxj3msc448wzwy9sqs9w6ckhlv55zuwnkuqqxc9qhu24h9rggzflyw04l9d3hcslzu340jqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq2pqun4wd68jtn00fkxzcnn9ehhyec6qgqsz83qfwdpl28qqmc78ymlvhmxcsywdk5wrjnj36jryg488qwlrnzyjczlqsp9nyu4phcg6dqhlhzgxagfu7zh3d9re0sqp9ts2yfugvnnm9gxkcnnnkdpa084a6t520h5zhkxsdnghvpukvd43lastpwuh73k29qsy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment