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
base: master
Are you sure you want to change the base?
Offers #798
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
c0aae68
to
19235c4
Compare
07c45e9
to
c918789
Compare
9f129f2
to
9c526ff
Compare
efdcb71
to
781004a
Compare
e02c7d8
to
4d0d10a
Compare
4d0d10a
to
fc8aab7
Compare
I have merged the million-fixup-commits into one commit, and trivially rebased onto the updated #759. The last two commits are new:
|
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:
Now we have 2 scenarios:
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. |
{ | ||
"description": "with blinded path via Bob (0x424242...), blinding 020202...", | ||
"valid": true, | ||
"bolt12": "lno1pgx9getnwss8vetrw3hhyucs5ypjgef743p5fzqq9nqxh0ah7y87rzv3ud0eleps9kl2d5348hq2k8qzqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgqpqqqqqqqqqqqqqqqqqqqqqqqqqqqzqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqqzq3zyg3zyg3zyg3vggzamrjghtt05kvkvpcp0a79gmy3nt6jsn98ad2xs8de6sl9qmgvcvs", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is the same blinded path using an sciddir introduction node:
lno1pgx9getnwss8vetrw3hhyucs3yqqqqqqqqqqqqp2qgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqqyqqqqqqqqqqqqqqqqqqqqqqqqqqqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqqgzyg3zyg3zyg3z93pqthvwfzadd7jejes8q9lhc4rvjxd022zv5l44g6qah82ru5rdpnpj
12-offer-encoding.md
Outdated
- if 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*. | ||
- otherwise (invoice not requested, e.g. for user to scan directly): | ||
- MUST set `invreq_chain` as it would for an invoice_request. | ||
- MUST set `offer_description` as it would for an offer. | ||
- MUST NOT set `invreq_payer_id` or `offer_node_id`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just noticing that we don't copy "all non-signature fields" for the "refund" variation. Why is this the case? In LDK we use this data to determine if we should pay the invoice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rustyrussell Oh, wait this is talking about a scanned invoice. Shouldn't this be removed now?
Add example of scid first-id for blinded path (thanks jkczyz!)
Offer can be in a different currency. invoice will be in sats. |
I've added the following to the rationale: Because ? |
Yeah, while you could support this, I want to master the simpler flow first.
The current flow is as primitive as I could make it. Bob refunds Alice by showing her an invoice_request, which refers to the original invoice Alice paid. She sends an invoice, which proves she was the one who actually made the payment (technically: same key she signed the invoice request originally), and gets paid. Two future extensions are interesting which would automate this over the network:
|
Many things are bought in quantity? Of course, combining multiple offers into a single invoice_request -> invoice would be a nice optimization, which we can do in future too (every wallet becomes a shopping cart!), but this the MVP to allow a single QR per product, rather than having to have a checkout process which generates it dynamically? Two cases I think of are flour per 100g, or years of domain name registration. |
Remove leftover reference to direct invoices (thanks jkczyz!)
describe the offer_amount/currency/invreq_amount/invoice_amount purpose
make offer_node_id optional, if they specify offer_paths. 1. We now tell them explicitly where to send the onion message. 2. We use this as shorthand later when they're supposed to check the reply. 3. Raw invoice_requests cannot set `offer_paths`, so we add `invreq_paths` for this. Thanks to thomash-acinq and jkczyz!
Make offer_description optional if there's no amount; this is the common "tip" case. Note that this implies a minimal offer is simply a bech32 encoding of the offer_node_id field, or "lno1" + bech32(0x2242<node_id>). This might become normalized as the "default offer" to which you can throw sats to a node directly?
@thomash-acinq and @jkczyz I have done those, plus as Matt wanted, made the description optional (iff there's no amount). This makes the smallest possible offer |
What is the purpose of referencing other currencies? Seems to provide wasted space in the spec and confusion when sat is the global standard. |
Again, referencing unrelated currencies seems to provide wasted space and confusion. |
- if `offer_node_id` is set: | ||
- MUST send the onion message to `offer_node_id` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given the writer MAY set offer_node_id
to the node's public key when offer_paths
is set, the reader can't assume it is the node's public key -- it may be transient! So readers should only send to offer_node_id
when offer_paths
is not set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems very wrong to me. If you don't want them prove a offer_node_id, don't set it. But offer_paths ids are forced transient: they are useless for any reputation system (they sign the invoice with that random key, but that means nothing).
Public nodes will want to sign their invoices with their node_id, so will any vendors trying to build a reputation for honesty. See Matt's DNS proposal, for example. Such offers may also want to use blinded paths, as they're the only way to give capacity or routing hints.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I strongly disagree that we should be continuing to tie the node_id
concept to the thing that signs invoices, in fact the separation is one reason I'm excited by offers. A single merchant may have several nodes, but more importantly we really should be separating the key material that is signing proof-of-payment data from the key material that is being used to decode onions or establish P2P connections. Reusing the same key material across so many different contexts is just horrible practice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason for setting both offer_paths
and offer_node_id
would be to enjoy the privacy of blinded paths while still using a stable identity that user can attach a reputation to.
Example: I'm a merchant and I want to use a stable node id that user can learn to trust, so I set offer_node_id
and sign invoices with it. However I either don't have a public node (e.g. phoenix) or don't want it to be known that it is my node, so I use offer_paths
and set offer_node_id
to be different from the node id of my lightning node.
I also disagree with your assertion that blinded paths are necessarily transient, all phoenix wallets will use blinded paths that will be valid forever.
You wouldn't want a subscription / recurring offer denominated in msats if the price of BTC is trending up. Currencies were largely for that purpose though recurrences were removed from v1 of the spec. |
@TheBlueMatt was thinking the description could be always optional. Any reason why it is required when there is an amount? |
Seems like it makes sense to have removed recurrences from the spec. I think you should always request a new invoice if some time has passed, all markets can always shift. If there are no more recurrences, does it make sense to remove arbitrary currencies from the spec too? It seems to me like if you are basing your prices on some arbitrary currency, that should be done out of band. |
I'm indifferent to removing it now. Note that the currency is only in offer not the invoice. For a recurring payment, the user would request a new invoice each time. |
Invoices are single-use, you must always request a new invoice each time you want to make a payment regardless of how much time has passed.
Some day in the future, goods may be priced in bitcoins, but today merchants set their prices in euros, dollars or other fiat currencies, that's the reality we live in. If we want real life merchants to use offers, they must support fiat currencies. |
Real charges are still in other currencies, and will be for the forseeable future. However, if no currency is specified, it's in (milli)sats. |
It only makes sense to omit it when there's no specific purpose for the payment. Otherwise, I really want you indicate what it is you think I'm paying for! This is approximately maps to "specific amount: specific purpose". It's a compromise, which allows for a tiny qr / default offer for a simple "throw sats at this node". |
"description": "Missing offer_description", | ||
"valid": false, | ||
"bolt12": "lno1zcss9mk8y3wkklfvevcrszlmu23kfrxh49px20665dqwmn4p72pksese" | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this test vector needs to be updated to include an amount now.
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