Adding support for main bolt12 commands to NIP-47
This is a request to add support for Bolt12 to NWC, such that a Lightning client can use NWC to generate and use Bolt12 offers, fetch and pay Bolt12 invoices, thus benefiting from the improvements over Bolt11.
@TheBlueMatt is correct when it comes to bolt12 invoices. They should be kept out completely and only deal with offers. That means paying an offer not bolt12 invoice and dropping the fetch_invoice method completely. I was working on a PR like this aswell: https://github.com/daywalker90/nips/pull/1
@TheBlueMatt is correct when it comes to bolt12 invoices. They should be kept out completely and only deal with offers. That means paying an offer not bolt12 invoice and dropping the fetch_invoice method completely. I was working on a PR like this aswell: daywalker90#1
Thanks! As I mentioned I am also fine with dropping the fetch_invoice method. It could be replaced by a modified pay_invoice command that supports offer strings and also payer_note, and the addition of a get_offer_info command that provides the main decoded offer information. I will modify the PR to reflect this.
@TheBlueMatt is correct when it comes to bolt12 invoices. They should be kept out completely and only deal with offers. That means paying an offer not bolt12 invoice and dropping the fetch_invoice method completely. I was working on a PR like this aswell: daywalker90#1
Ok so I did remove the fetch_invoice command and made the changes required to make it work with bolt12. I have also added support for the offer issuer field, as well as other currencies when making and decoding offers. The offer_issuer, offer_id and payer_note fields are now part of the results when listing transactions, when applicable.
@21M4TW is there any NWC Wallet Service implementation that supports any of this?
@21M4TW is there any NWC Wallet Service implementation that supports any of this?
I've done a prototype in preparation for a spec PR with my own nip spec here: https://github.com/daywalker90/cln-nip47/pull/2
PR for the library i use in cln-nip47: https://github.com/daywalker90/nips/pull/1 My own spec PR: https://github.com/daywalker90/nostr/pull/1
@21M4TW is there any NWC Wallet Service implementation that supports any of this?
Sorry, I just noticed this question. I had this PR for nwcprovider (https://github.com/riccardobl/nwcprovider/pull/12) . I also have implemented the bolt12 functionalities in lnbits (https://github.com/lnbits/lnbits/pull/3092). I also wanted to help adding Bolt12 NWC support to Zeus (which uses getAlby for NWC). Zeus already supports bolt12, including enabling and disabling offers, through CLNRest. All these (except lnbits') are pretty much pending on the inclusion of Bolt12 into NIP47.
Is there anything I can do to get this moving? Thanks!
Looks good to me, sounds like there are 2+ implementations? If so I think we can merge.
@reneaaron @rolznz any opinions on this?
Imo i agree that we should remove enable/disable offer
Also I was considering extracting the decoding code from CLN and package it into a library so it can be used anywhere. It seemed to be a sticking point and I agree it would be better to do it locally instead of relying on a get_offer_info command.
Also I was considering extracting the decoding code from CLN and package it into a library so it can be used anywhere. It seemed to be a sticking point and I agree it would be better to do it locally instead of relying on a get_offer_info command.
I am working on a bolt12 offer decode now and making very good progress. CLN's code was relying on way too many header and source files to make it tidy enough though, so I am writing a minimal library that should be much lighter. The nice part is that since we are only dealing with offers and not invoices, we don't even have to deal with Merkle trees and signatures for this, as offers are not signed.
Just removed the get_offer_info as well.
Also I was considering extracting the decoding code from CLN and package it into a library so it can be used anywhere. It seemed to be a sticking point and I agree it would be better to do it locally instead of relying on a get_offer_info command.
I am working on a bolt12 offer decode now and making very good progress. CLN's code was relying on way too many header and source files to make it tidy enough though, so I am writing a minimal library that should be much lighter. The nice part is that since we are only dealing with offers and not invoices, we don't even have to deal with Merkle trees and signatures for this, as offers are not signed.
So my Bolt12 offer decoding project is now in very good shape and available (https://github.com/21M4TW/b12od ). There are bindings for Rust, Python and WASM in addition to C. The code itself has no dependency and should be very portable. Hopefully it will help for Bolt12 support a bit.
FWIW you should also be able to just use the LDK lightning crate to decode offers pretty trivially. From the Rust end you can expose bindings to C/whatever language you want and on compilation all the unused/non-BOLT12 stuff will get dropped and not included in the binary.
This is ready for review. Thanks!
Now that we've gotten this far.....
Should we actually support BOLT 12 natively or should we support BIP 353? For making and receiving payments, ISTM most of the time you just want a payment instruction, which means BIP 321, not BOLT 12.
Specifically, I'd really like to better understand how wallets actually use the NWC stuff like listing invoices and such. I assume that most NWC clients really just want to generate and pay payment instructions. They don't care about BOLT 11/12, some crazy disable-invoice nonsense, or even listing transactions.
In a future with Ark, silent payments, etc shouldn't we be generating BIP 321 and basically just do BIP 321-over-nostr?
Specifically, I'd really like to better understand how wallets actually use the NWC stuff like listing invoices and such. I assume that most NWC clients really just want to generate and pay payment instructions. They don't care about BOLT 11/12, some crazy disable-invoice nonsense, or even listing transactions.
I disagree, this is certainly not true for Zeus, that supports all these features, and more.
Right, there's two highly distinct use-cases here - there's wallet frontend, which wants All Of The Things, and then there's wallet remote control (eg nostr client), which just wants create + pay, and everything else is extra.
Still, ignoring disable and list and history, Im not sure if a wallet fronted needs anything more than a "give me a BIP 321 payment instruction" instruction, rather than wanting BOLT 11/12/etc low-level stuff.
Right, there's two highly distinct use-cases here - there's wallet frontend, which wants All Of The Things, and then there's wallet remote control (eg nostr client), which just wants create + pay, and everything else is extra.
Still, ignoring disable and list and history, Im not sure if a wallet fronted needs anything more than a "give me a BIP 321 payment instruction" instruction, rather than wanting BOLT 11/12/etc low-level stuff.
Ok, but the goal of this PR was not to completely replace the existing NWC API, it was to extend it minimally, while remaining backward compatible, to enable support for Bolt12 as well...
Right, my point here, though, is that we could almost entirely take exactly the changes here, and s/bolt12/bip321/, remove a few bolt-12 specific fields, and it would still be the same. Obviously for practical reasons we can't drop all the old bolt 11 stuff, but if the end goal is "BIP 321" then IMO we should just do that?
Right, my point here, though, is that we could almost entirely take exactly the changes here, and
s/bolt12/bip321/, remove a few bolt-12 specific fields, and it would still be the same. Obviously for practical reasons we can't drop all the old bolt 11 stuff, but if the end goal is "BIP 321" then IMO we should just do that?
I am not super familiar with BIP 321. Let's say I want to create a USD-denominated single use offer with BIP 321, and the payer wanted to provide extra tip and add a note, how would the sequence would look like with BIP 321?
BIP 321 is just bitcoin:instructions, so it depends a bit, but I think every type of Bitcoin payment instruction I'm aware of allows for additional funds to be included. The operative flag for requesting a BIP 321 from a wallet is mostly "is this single-use", so if its a single-use request, you'd presumably get something like bitcoin:onchain?lightning=bolt11&amount=requested-onchain-amount and the paying wallet can select to use bolt11 or on-chain (if its included at all, it can be elided) and can always pay more than what was requested.
If the BIP 321 is not single-use, the wallet should likely return something more like bitcoin:onchain?lno=bolt12offer&sp=silentpaymentaddr. Again, all of these payment instruction formats allow for paying any arbitrary amount (though of course the wallet may not want to include on-chain stuff if it doesn't want to)
The nice thing about using BIP 321 is everyone already has logic for it, so doubling down on that as the "machine-readable bitcoin payment instruction format" seems like the right direction.
BIP 321 is just
bitcoin:instructions, so it depends a bit, but I think every type of Bitcoin payment instruction I'm aware of allows for additional funds to be included. The operative flag for requesting a BIP 321 from a wallet is mostly "is this single-use", so if its a single-use request, you'd presumably get something likebitcoin:onchain?lightning=bolt11&amount=requested-onchain-amountand the paying wallet can select to use bolt11 or on-chain (if its included at all, it can be elided) and can always pay more than what was requested.If the BIP 321 is not single-use, the wallet should likely return something more like
bitcoin:onchain?lno=bolt12offer&sp=silentpaymentaddr. Again, all of these payment instruction formats allow for paying any arbitrary amount (though of course the wallet may not want to include on-chain stuff if it doesn't want to)
Ok thanks, this is when you receive a payment request, but my question was more about an equivalent to the "make_offer" method with BIP 321. Would BIP 321 only replace the "pay*" methods?
I was imagining, basically, build_receive_instructions(single_use, min_amount, description) (where min_amount is only allowed if single_use is set) which returns a BIP 321 and pay_for_instructions(bip321, amount_incl_tip, payer_note_if_supported, proof_of_payment_metadata).
I was imagining, basically,
build_receive_instructions(single_use, min_amount, description)(wheremin_amountis only allowed ifsingle_useis set) which returns a BIP 321 andpay_for_instructions(bip321, amount_incl_tip, payer_note_if_supported, proof_of_payment_metadata).
Ok thanks. Why would min_amount be only allowed if single_use is set though? What about expiry, issuer, and currrency options? Wouldn't be also useful to be able to select between bolt11/bolt12 (or silent payment, payjoin) since bolt12 (and silent payment or payjoin) support is not quite universal right now?
Why would min_amount be only allowed if single_use is set though?
I'm not aware of a bitcoin payment instruction format that has an amount field that is intended as multi-use/donations. the amount field in BIP 321 URIs, plus the amount fields in BOLT 11 and BOLT 12 are really intended/have UX flows for "this is the amount for the payment" (and someone can add a tip if they want, but its really a payment for an amount). When no amount is provided, the UX flow changes to something more like a donation. Those UX flows are fairly distinct and the use-cases for a single-use invoice and multi-use invoice are different and I think furthering that makes sense.
What about expiry, issuer, and currrency options?
We can certainly include these fields, and expiry can map to both BOLT 11 and 12, but not all forms of Bitcoin payment instructions have expiries (do Cashu payment instructions? Ark? Spark? certainly not on-chain...). FWIW, BOLT 12 currency conversion is really a thing mostly for recurrence which is currently not supported.
Wouldn't be also useful to be able to select between bolt11/bolt12 (or silent payment, payjoin) since bolt12 (and silent payment or payjoin) support is not quite universal right now?
That's the nice thing about BIP 321 - you just shove everything you support in there and the payer picks whatever they also support. IMO the NWC client shouldn't concern itself with this (unless it has some specific requirement, eg its doing a zap so can only support BOLT 12 or whatever), and the wallet should be providing everything it supports.
Why would min_amount be only allowed if single_use is set though?
I'm not aware of a bitcoin payment instruction format that has an amount field that is intended as multi-use/donations. the
amountfield in BIP 321 URIs, plus the amount fields in BOLT 11 and BOLT 12 are really intended/have UX flows for "this is the amount for the payment" (and someone can add a tip if they want, but its really a payment for an amount). When no amount is provided, the UX flow changes to something more like a donation. Those UX flows are fairly distinct and the use-cases for a single-use invoice and multi-use invoice are different and I think furthering that makes sense.
Bolt 12 offers do support multi-use with minimum amounts?
What about expiry, issuer, and currrency options?
We can certainly include these fields, and expiry can map to both BOLT 11 and 12, but not all forms of Bitcoin payment instructions have expiries (do Cashu payment instructions? Ark? Spark? certainly not on-chain...). FWIW, BOLT 12 currency conversion is really a thing mostly for recurrence which is currently not supported.
Wouldn't be also useful to be able to select between bolt11/bolt12 (or silent payment, payjoin) since bolt12 (and silent payment or payjoin) support is not quite universal right now?
That's the nice thing about BIP 321 - you just shove everything you support in there and the payer picks whatever they also support. IMO the NWC client shouldn't concern itself with this (unless it has some specific requirement, eg its doing a zap so can only support BOLT 12 or whatever), and the wallet should be providing everything it supports.
I can see how this can be useful in some situations to maximize the chance of support, but in other situations it is preferable to only include some of them. For example, amongst other things Bolt 12 addresses some privacy shortcomings of Bolt 11. If a Bolt 11 invoice is generated every time along with a Bolt 12 offer, it negates the benefits of Bolt 12... Also if a new onchain address was to be generated every single time, it could make wallet recovery problematic. I think one would want to be able to select which type of address should be generated. There could be a default that could be "any supported", but it should be selectable...