Kukks / BTCPayServerPlugins

MIT License
27 stars 25 forks source link

[Nostr] Nostr plugin documentation and user interface is confusing #57

Open jooray opened 2 months ago

jooray commented 2 months ago

Hey.

I made a pull request: https://github.com/Kukks/BTCPayServerPlugins/pull/56

I would like to improve the documentation and user interface a little bit more though, the documentation is very confusing. I volunteer to write it and create pull request, but I need clarification.

1.) The official documentation (linked from the "Manage Plugin" tab) contains three things - NIP05 (verifying accounts), NIP57 (zaps), NIP47 (receiving to NWC enabled lightning wallet).

But the "Usage" part does not distinguish among these use cases. What am I setting up?

2.) The Nostr tab that appears in the sidebar contains this notice:

For Zaps, just enable a lightning address. None of the nostr settings on this page are needed for zaps anymore.

OK, so what are they needed for? What am I setting up? NIP05 verification?

Why is there a private key (and why is it optional? What happens if I put it there, what happens if I don't)?

3.) There's no mention on setting up NWC. It is not in Nostr tab, it is in setting up the wallet of the store.

I found this blog by Alby. Should we point users to it? Is there a better documentation? Should we at least briefly write about this in plug-in documentation?

Should we include any documentation for this functionality? (Or at least point them to it).

4.) Is there any maintained website that lists wallets that support NWC?

johnheenan commented 1 month ago

1.) The official documentation (linked from the "Manage Plugin" tab) contains three things - NIP05 (verifying accounts), NIP57 (zaps), NIP47 (receiving to NWC enabled lightning wallet).

But the "Usage" part does not distinguish among these use cases. What am I setting up?

NIP05: Suppose your btcpay server web address is btcpay.example.com and that you have registered name myname with the nostr plugin then a GET query to https://btcpay.example.com/.well-known.nostr.json?name=myname will return a json response with the hex version of your nostr public key and your optional relays, if you included them.

In this case myname@btcpay.example.com is a nostr address. Nothing more. You can have multiple nostr addresses all providing the same public key (but only one nostr address per BTCPay store, unlike lightning addresses).

NIP57:

2.) The Nostr tab that appears in the sidebar contains this notice:

For Zaps, just enable a lightning address. None of the nostr settings on this page are needed for zaps anymore.

OK, so what are they needed for? What am I setting up? NIP05 verification?

Nothing to do with NIP05 and you are not verifying anything with NIP05. The nostr address identifies a public key, it does not authenticate or verify a public key. Only the nostr public key can be used to verify an event (such as a message) was signed by the particular private key of that public key.

Why is there a private key (and why is it optional? What happens if I put it there, what happens if I don't)?

Nothing additional happens to the NIP05 information passed back with the private key entered. The private key can be used to sign a zap receipt.

I assume if you do not have a ligntning address added in to receive a zap then any payment to your nostr address as a lightning address gets processed as a lightning payment, perhaps with an additional nostr signed receipt that you may not get otherwise with a lightning address. Perhaps @Kukks can clarify.

Interesting questions: What happens if your nostr name is the same as one your added lightning address names? Which code flow gets precedence for processing?

Also, if nostr is enabled and you have lighning addresses enabled then your lightning address GET query will also list your nostr public key in hex

NIP47:

3.) There's no mention on setting up NWC. It is not in Nostr tab, it is in setting up the wallet of the store.

NWC is the abbreviated name for NIP47. It is just a protocol.

A nostr client can ask a lightning service for a lightning address to pay when all it knows is the nostr address.

From NIP47 (emphasis added)

client discovers wallet service by scanning a QR code, handling a deeplink or pasting in a URI. client: Nostr app on any platform that wants to pay Lightning invoices. wallet service: Nostr app that typically runs on an always-on computer (eg. in the cloud or on a Raspberry Pi). This app has access to the APIs of the wallets it serves.

So the plugin adds the above mentioned wallet service to BTCPay so as NIP47 (NWC) enabled nostr clients can talk to a lightning service

I will give this a try and report back.

johnheenan commented 1 month ago

Interesting questions: What happens if your nostr name is the same as one your added lightning address names? Which code flow gets precedence for processing?

My guess is that if the NWC protocol is used then a nostr signed zap receipt is shown if the nostr private key is included. If sent direct through lightning then no nostr signed zap receipt is shown

johnheenan commented 1 month ago

I have a look at Amethyst in Android. You can enter an nostr address as part of a profile associated with your npub or nsec. An nsec profile is required to send a zap. If only a npub profile is associated with a sender then a zap won't be sent.

It wasn't possible to use a nostr address to send a private message without knowing the npub or @ name for it. If a nostr address is added to a profile of Amethyst, then Amethyst will tell you there is an associated nostr address and show a tick. The verfication in this case is a verfication that a web lookup returned the npub it is associated with. It did not work backwards from within Amethyst (finding an npub from nostr address). There is no user verfifcation, only a verfication of an npub with a web address.

Even with the Nostr Address ticked for a user, a zap is not sent without a lightning address associated with a profile being sent to. So an nsec is required for profile of sender and a lignting address is required for profile of receiver. An nostr address is not required.

My conclusion is that Amethyst does not implement NWC. As for the upcoming Alby wallet with NWC, the Alby wallet is not publically available. The upcoming NWC Service from Alby is for use on a server with an SDK.

I could not any association with NWC for other nostr clients. The association of Ametyst with NWC is misleading.

Conclusion: NWC is not currently available client side and there is no general SDK available server side.

jooray commented 1 month ago

As I see it (to make the interface more clear):

Zaps

For zaps, my suggestion is to reformulate the interface to reflect the above.

NIP-05 verification

For NIP-05 verification, we need name, public key and a list of relays. Then nip-05 verified address will work. Let's make it clear that these are used for NIP-05, because it's not clear from the interface

NWC

NWC is unrelated to this interface page. We should set it up as a Lightning node in the store. It should also be clearer from the interface.

If I am correct in my assumptions, I will provide suggestions on how to change the texts in the interface and how to alter the documentation.

johnheenan commented 1 month ago

Correction. I was able to get an Alby browser extension wallet to work by using the LND REST feature of BTCPay.

I did not see these addiitonal settings below come in Amethyst in the lower half:

image

I have confirmed the additional features are in NIP47 and assume they are already preconfgured in BTCPay.

It looks like the purpose of the Alby NWC SDK is to split into two what BTCPay is already doing as a complete service. So functionally Ametyst wallet + Alby SDK = BTCPay.

johnheenan commented 1 month ago

As I see it (to make the interface more clear):

I would agree the existing interfaces could be better documented or explained. If you could add this in we would all be grateful.

My impression is that there is nothing wrong with the interface and there are no missing interfaces. Protocols don't care about interfaces.

Documentation is poor from the perspective of a user or admin trying to learn. But that is not the fault of BTCPay. Why should BTCPay be tasked with filling in the gaps?

johnheenan commented 1 month ago

It looks like the purpose of the Alby NWC SDK is to split into two what BTCPay is already doing as a complete service. So functionally Ametyst wallet + Alby SDK = BTCPay.

So my guess is that unless funds are held custodially by Alby Wallet or Amethyst Wallet there won't be a usable NWC service with these wallets

jooray commented 1 month ago

Btcpay presents the user interface. It's not about teaching about the protocols, my problem is I don't know what I'm setting up, what is the interface doing. Like writing you don't need this for zaps, but then you realize that zaps fully don't work without it (because there are no receipts). Or that the private key is not needed for the verification. Or that the "username" is different for zaps and for verification. I'll start with documentation.

johnheenan commented 1 month ago

Btcpay presents the user interface. It's not about teaching about the protocols, my problem is I don't know what I'm setting up, what is the interface doing. Like writing you don't need this for zaps, but then you realize that zaps fully don't work without it (because there are no receipts).

When I paid a zap in Ametyst I go thrown to a wallet to make a lightning payment. This was not a a NIP57 zap. I suppose a clearer explanation is that the private key field is required for NIP57 zap but no one pays zaps this way.

Or that the private key is not needed for the verification.

Agreed, except that verifcation is not user verfication.

Or that the "username" is different for zaps and for verification.

Why do you say that? The username is part of the identifcation scheme to provide a nostr public key and to link to a wallet service. The public key is what is important for nostr, a username proves nothing in nostr.

Are you distinguising between the 'verfication' username and the nostr 'username' typcally seen in a nostr post? Both are used to identify a public key. True, they don't need to be the same. For NIP05, BTCPay only cares about the nostr public key and whatever arbitrary name is used to find the nostr key.

johnheenan commented 1 month ago

I am about to post a Pull Request that hopefully clarifies the nostr interface to a level that avoids confusion.

I will reference this issue so I expect a link will appear below this comment.

If you want the interface clarified further and have specific suggestions as to wording, then please make them at the pull request.

If you have more general comments to make, then please continue posting to this issue.

With regard to zaps and entering the private key in the interface for the nostr plugin, if no private key is entered then a random key is made up. Yes, it would be nice if this was explicitly stated at the interface. So let's do this.

Looking at the BTCPay plugin code, it looks like plugin issues type 9735 nostr receipts to nostr relays independent of how the the zap was requested when a lightning payment is made, if there is a nostr address associated with the store the lightning address belongs to.

The filtering function below processes NIP57 zap events (kind 9734). The nostr client makes the request to a lightning wallet server using a nostr address and is only really required when a lightning address is unknown. I don't think Amethyst bothers with this, but it does not matter.

https://github.com/Kukks/BTCPayServerPlugins/blob/5cfe2e5acd40cd4b982c34871c2e084cdc0467fe/Plugins/BTCPayServer.Plugins.NIP05/LnurlDescriptionFilter.cs#L35

When a lightning payment is actually made, the plugin checks if there is a nostr address associated with the store, no matter what lightning addresses belong to a store. If there is the plugin issues a nostr type 9735 event to relays

When a payment is made, this line uses the stored private key if it was entered. If none was entered it uses a made up random key.

result.ZapperPrivateKey ??= Convert.ToHexString(RandomUtils.GetBytes(32));

from https://github.com/Kukks/BTCPayServerPlugins/blob/5cfe2e5acd40cd4b982c34871c2e084cdc0467fe/Plugins/BTCPayServer.Plugins.NIP05/Zapper.cs#L43

johnheenan commented 1 month ago

The nostr client makes the request to a lightning wallet server using a nostr address and is only really required when a lightning address is unknown.

My statement is wrong, but not fully! The nostr address of NIP05 has nothing to do with providing a lightning address. Even though the nostr address and at least one lightning address could be the same, there is no requirement for this. Also, although BTCPay might choose to process a nostr address as an unlisted lightning address, there is no obligation to do so..

This has clarified issues for me.

But it is not the end of the story!

Since NIP47 is implemented, BTCPay must provide a connection URI, see https://github.com/nostr-protocol/nips/blob/master/47.md#theory-of-operation

So where is it?

I will make this into another issue.

johnheenan commented 1 month ago

Since NIP47 is implemented, BTCPay must provide a connection URI, see https://github.com/nostr-protocol/nips/blob/master/47.md#theory-of-operation

So where is it?

Shown here: https://github.com/Kukks/BTCPayServerPlugins/issues/63#issuecomment-2354632246

johnheenan commented 1 month ago

Thanks to @Kukks for merging mine and @jooray commits with regard to clarifying the nostr plugin UI.

There is a lot of material that jooray can use to get way ahead with. For example, Kukks has invented a technique for a nostr client to configure a combined nostr server/btcpay store with lightning wallet, to make a one touch zap payment, rather than the other way of expecting the nostr client to fetch the approved configuration from an intermediary to the lightning wallet and nostr client, through a nostr+walletconnect deeplink.

I added in Kukks nostr server fragment into btcpay and got it configured. The instructions are very terse but the do work. By relay below I mean the nostr relay on the btcpay server, which has URI of the form wss://btcpay.example.com/nostr, when the docker fragment is loaded.

The initial AdminKey, usable as an initial hex nostr secret key for a nostr client, is sent as an error message when attempting to contact the relay from any nostr client that uses the relay for a nostr private DM to the relay (by sending a DM to oneself). These relay error messages are not regular messages. They can be seen by Amethyst Android nostr client app by clicking on the relay name, but but not by the nostrudel nostr client web app.

In addition, currently the desired edited {CONFIG} to send back, with a new AdminKey, must NOT be sent encrypted to the relay. This needs a fix. This means nostrudel cannot currently be used be send /admin commands for this and encryption needs to be toggled off on Amethyst for the DM.

There is no admin webui for the nostr server, unlike for the btcpay nostr plugin.

There is clever and interesting code in the nostr btcpay plugin. Kukks has reversed the onus on a wallet service to provide a one touch zap NIP-47 nostr+walletconnect deeplink to be used by the nostr client. Instead he has invented a NIP (NIP-67) which allows the nostr server to send a nostr confirmatory event to confirm how the nostr server/btcpay server has been configured for one touch NWC zaps. A nostr client tell the nostr server what services to provide and what secret to use to verify a payment request is genuinely from an approved nostr client. Currently no known public nostr client apps implements recognition of NIP-67 events. Presumably there is will be as an extension to the /admin command system that configures the one touch zap service and allows one or more eligible clients to receive the event with the details.

So who might these clients be receiving the NIP-67 events automatically ? I assume any nostr client that is using the same nostr secret as the formerly sent AdminKey to the nostr server with the /admin config {CONFIG} command.

johnheenan commented 1 month ago

Some clarity added how the above might work, step by step. Also some more background detail and what the future might bring, that I also think adds clarity, particularly as to just how flexible a UI can be with nostr and btcpay

First the nostr server code mentioned is called NNostr and is available from https://github.com/Kukks/NNostr. The title is 'A Nostr Relay and Client written in C#'. The server code can be installed with btcpay server through the well recognised technique in btcpay of including docker fragments for a rerun setup.

The client part of NNostr is a C# library to listen for events, subscribe to particular events and send events. There is no UI, but that is where its strength lies. In the usage example provided there is an example of connecting to a single relay. A specific main strength is the capacity to be used by plugins in btcpay to communicate with the nostr server of the btcpay server.

Step by step details of an example of automated configuration for one touch zap (and even zero touch zap):

  1. Two nostr clients have added nostr accounts that are used for DM purposes with the nostr server on btcpay. The secret key for the accounts is the same as the same nostr server AdminKey.
  2. One nostr client sends a currently, as of now, unidentified /admin command through a DM message to the btcpay nostr server to configure one touch zap payments
  3. The nostr server stores a Kukks' NIP-67 event with the NIP-47 nostr+walletconnect:// NWC URI string.
  4. The nostr server sends the NIP-67 event to the two clients whom it knows have the same secret key as the AdminKey
  5. The two nostr clients decode the NWC URI and provide information to a user they can now use one touch zaps

So how might this be useful right now, given that no known clients use NIP-67 and there is no discussion of it?

As indicated above, the NNostr C# client code has one very useful feature that can be used right now! It can be used by btcpay plugins that are themselves nostr clients to the btcpay nostr server! They can also add in an admin webui for the nostr server!

So there is a lot of potential for building sophisticated solutions with further exotic plugins, including btcpay plugins providing zero touch zaps! How about setting up a zap service as a plugin that sends a series of automated zaps on a regular basis!

johnheenan commented 1 month ago

So why automate sending zaps rather than direct lightning payments?

Because zaps can associate payment with the payer's public key. So payment and source of payment can be proved. This allows account keeping.

At a more raw level it allows those who receive zaps to know who zapped them (by public key).

I have changed the title of issue https://github.com/Kukks/BTCPayServerPlugins/issues/63#issuecomment-2372553206 and added more comments to confirm if the approach above could work.