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

NIP-57: Lightning Zaps #224

Merged
merged 9 commits into from
Feb 13, 2023
Merged

NIP-57: Lightning Zaps #224

merged 9 commits into from
Feb 13, 2023

Conversation

jb55
Copy link
Contributor

@jb55 jb55 commented Feb 5, 2023

This NIP defines a new note type called a lightning zap of kind 9735. These represent paid lightning invoice receipts sent by a lightning node called the zapper. We also define a another note type of kind 9734 which are zap request notes, which will be described in this document.

Having lightning receipts on nostr allows clients to display lightning payments from entities on the network. These can be used for fun or for spam deterrence.

https://github.com/nostr-protocol/nips/blob/zaps/57.md

57.md Outdated Show resolved Hide resolved
57.md Outdated Show resolved Hide resolved
jb55 and others added 2 commits February 5, 2023 12:04
Co-authored-by: 0xtr <oxtrr@protonmail.com>
@lylepratt
Copy link
Contributor

nice! awesome spec! Will work on implementing this.

@fiatjaf
Copy link
Member

fiatjaf commented Feb 5, 2023

Can we remove the allowsNostr field entirely and just rely on the presence of nostrPubkey?

@jb55
Copy link
Contributor Author

jb55 commented Feb 5, 2023

probably, I can't remember why I had them separate.

@jb55
Copy link
Contributor Author

jb55 commented Feb 5, 2023

I kinda rushed this and might be underspecified, let me know if anything seems unclear.

@jb55
Copy link
Contributor Author

jb55 commented Feb 5, 2023

probably, I can't remember why I had them separate.

maybe for temporarily disabling it while still allowing clients to validate older zaps? I think I had some kind of reasoning along those lines.

@fiatjaf
Copy link
Member

fiatjaf commented Feb 5, 2023

maybe for temporarily disabling it while still allowing clients to validate older zaps? I think I had some kind of reasoning along those lines.

Makes sense.

@fiatjaf
Copy link
Member

fiatjaf commented Feb 5, 2023

I don't understand the need for the encrypted zap request, since HTTPS calls are already encrypted. What have I misunderstood?

@jb55
Copy link
Contributor Author

jb55 commented Feb 5, 2023

This would allow you to hide who created the invoice. you could still tally zaps and only the person receiving the zap could see who it was from. The description would be an encrypted zap request note.

@jb55
Copy link
Contributor Author

jb55 commented Feb 5, 2023

Well it would be slightly more complicated, it would have to be a kind 9733 note with a random key, or potentially just a json blob with no key; with relays encrypted to the zapper (to reduce fingerprinting), in this json is a 9734 note encrypted to the user getting zapped.

I have this all thought out but didn't want to complicate this spec with it just yet.

57.md Outdated Show resolved Hide resolved

1. Calculate the lnurl pay request url for a user from the lud06 or lud16 field on their profile

2. Fetch the lnurl pay request static endpoint (`https://host.com/.well-known/lnurlp/user`) and gather the `allowsNostr` and `nostrPubkey` fields. If `allowsNostr` exists and it is `true`, and if `nostrPubkey` exists and is a valid BIP 340 public key, associate this information with the user. The `nostrPubkey` is the `zapper`'s pubkey, and it is used to authorize zaps sent to that user.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
2. Fetch the lnurl pay request static endpoint (`https://host.com/.well-known/lnurlp/user`) and gather the `allowsNostr` and `nostrPubkey` fields. If `allowsNostr` exists and it is `true`, and if `nostrPubkey` exists and is a valid BIP 340 public key, associate this information with the user. The `nostrPubkey` is the `zapper`'s pubkey, and it is used to authorize zaps sent to that user.
2. Fetch the lnurl pay request static endpoint (`https://host.com/.well-known/lnurlp/user`) and gather the `allowsNostr` and `nostrPubkey` fields. If `allowsNostr` exists and it is `true`, and if `nostrPubkey` exists and is a valid BIP 340 public key, 32 bytes, hex-encoded, associate this information with the user. The `nostrPubkey` is the `zapper`'s pubkey, and it is used to authorize zaps sent to that user.

@bumi
Copy link

bumi commented Feb 5, 2023

I am excited to see the interest of deeply integrating lightning payments into Nostr. The name zaps is great!

Here are a few thoughts/questions:

Do I understand it correctly that the zap request should be stored in the invoice description? Or only the hash of the zap request in the invoice description_hash? "Parse the bolt11 description as a JSON nostr note" indicates that the whole nostr node should be saved in the invoice description.
This would be different to what is currently described in the lnurl-pay spec?

Would it be possible to reuse LUD18 payerdata for this? afaik LUD18 is already generic and allows the storage generic payer data. It is also committed in the description_hash.

Would it be possible to allow the client to publish the zap? This would remove the requirement that LNURL implementations/service providers need to implement Nostr connections. The smaller the usage specific requirement is the more tools/service providers will be able to be used. I am worried that this is a too big limitation. IMO ideally the LNURL spec should not have any social network specific requirements and is independent.

The main data that would be needed is the preimage, correct? With the preimage and the payment request/hash the validation can also be done.
I could imagine that clients will deeply integrate lightning wallets and thus also have access to the preimage or alternatively with a proposal like the lnnurl-verify the preimage could be retrieved without any Nostr specific requirement on side of the the LNURL-spec.

Thanks for pushing this forward! This can bring the value4value idea to so many more usecases!

@fiatjaf
Copy link
Member

fiatjaf commented Feb 5, 2023

I was pretty happy with this NIP, but after thinking about it for many minutes, this question has occurred to me: is there a reason for reusing LNURL endpoints even though this is not an LNURL payment at all?

Wouldn't it be more elegant and much simpler to decouple this entirely from LNURL and use an independent spec (and a different /.well-known endpoint) for requesting the invoice? It wouldn't need all the other LNURL things, and it would be automatically a nostrified endpoint (so no need for the nostrEnabled flag).

Moreover the communication could be reduced to a single step. Could be something like:

A user sets a field in their Nostr metadata like: "nip57": "https://zapper.com/"

Then a client can call

GET https://zapper.com/.well-known/zap

and get back

{"pubkey": "<hex pubkey of the zapper>"}

And when sending a zap the client would call:

POST /.well-known/zap
{
  ...zap request event, as it is today, but also including the amount as a tag
}

and immediately get an invoice back, check that the description hash matches against the event id of the zap request, and pay it. The rest is the same.

The only reason I can see for keeping the lud06/lud16 things in place and reusing them are that people don't have to change their metadata and can start getting zaps immediately as soon as their zapper provider (currently LNURL provider) implements this NIP. But I think this reason is not good enough and that a dedicated protocol that doesn't ever say anything about LNURL such as above would be less confusing and easier to implement for everybody.

@fiatjaf
Copy link
Member

fiatjaf commented Feb 6, 2023

Another idea is to embed the zapper pubkey in the metadata of the user who is receiving the zaps directly, so the field could be something like "nip57": "["<zapperpubkeyhex>", https://zapper.com"] instead. Then other clients don't have to actually call the zapper endpoint to verify the zaps, they can just use the zapper key taken from the metadata directly.

Now I am thinking: why restrict the number of zappers a user can have to only one? Maybe I am crazy, but users may want to have more than one, as fallbacks. So the field could be "nip57": [["key", "url"], ["key", "url"]], but this is ugly, better put it on the event tags: "tags": [["zapper", "key", "url"], ["zapper", "key", "url"]].

Or maybe it is even better to put these things in yet another dedicated replaceable event, as explained by @staab at #218 (comment), that would mitigate the issue of unwanted metadata overwrites and then only clients that implemented zaps could fetch that specific event to the get zapper addresses for people.

@fiatjaf
Copy link
Member

fiatjaf commented Feb 6, 2023

The problem with my spec suggestion above is that it assumes the zapper service will know who is receiving the funds from the zap request event, which is definitely a possibility, but shouldn't be mandatory as it may complicate things for some potential providers.

It is probably better that the specified zapper URL be just an arbitrary URL and clients just POST to that URL directly, without the .well-known shenanigans. Using arbitrary URLs solve things since zapper services can give URLs with internal IDs for their users and use these to discriminate incoming zap payments.

OK, now I'll shut up.

@bumi
Copy link

bumi commented Feb 6, 2023

I think being able to build on all the adoption of LNURL/LUD16 out there is a great advantage. Imo ideally people can use their current setup as much as possible and developers also don't need to start from scratch again building nostr LN support. So I am +1 for LNURL

What exactly do we miss from LNURL?

@starbackr-dev
Copy link
Contributor

Would it be possible to allow the client to publish the zap? This would remove the requirement that LNURL implementations/service providers need to implement Nostr connections. The smaller the usage specific requirement is the more tools/service providers will be able to be used. I am worried that this is a too big limitation. IMO ideally the LNURL spec should not have any social network specific requirements and is independent.

The main data that would be needed is the preimage, correct? With the preimage and the payment request/hash the validation can also be done. I could imagine that clients will deeply integrate lightning wallets and thus also have access to the preimage or alternatively with a proposal like the lnnurl-verify the preimage could be retrieved without any Nostr specific requirement on side of the the LNURL-spec.

Thanks for pushing this forward! This can bring the value4value idea to so many more usecases!

Would it be possible to allow the client to publish the zap? - I like Bhumi's point on having this option. There are many wallets such as Strike don't have LNURL implemented. Zaps break if wallet does not support it.

There should be a manual option for zapper user to input the preimage after the payment and the client creates kind 9735 event on behalf of the zapper user. This eliminates dependency on wallets implementing LNURL and Zapper specs.

@lylepratt
Copy link
Contributor

Zaps break if wallet does not support it.

I don't think this is true. The Nostr client requests a Bolt11 invoice from the server which all wallets should be able to pay.

@Giszmo Giszmo added enhancement New feature or request and removed enhancement New feature or request labels Feb 6, 2023
@ok300
Copy link
Contributor

ok300 commented Feb 9, 2023

The only downside I can think of is that it would allow Carol to zap Alice at alice+bob_pubkey@ln.com.

This would appear as a zap from Bob to Alice, but it's like Carol donated to Alice in Bob's name. Who would mind that?


b. It MUST have tags

c. It MUST have at least one p-tag
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
c. It MUST have at least one p-tag
c. It MUST have one p-tag

Zaps cannot be sent to multiple users with one request

@bumi
Copy link

bumi commented Feb 11, 2023

I love the zaps - as everybody :) seeing the excitement and interest on this is a great sign for monetization options.

As mentioned I am a bit concerned about the Nostr specific requirements for LNURL providers. This adds implementation complexity and we also create a Nostr island that is no longer interoperable.
LNURL has brought some standardization and allows people to use their preferred tools and service providers and wallets. The support for it among the lightning ecosystem is big and growing. For example the podcasting 2.0 community also discusses the use of LNURL (starting with LUD16) as an alternative to the currently used keysend payments.

To me reusabiltity and interoperability is an important goal. If people can use their existing lightning setup to receive payments on Nostr then this is favorable and simplifies and especially speeds up adoption. It took years for many providers and tools to implement LNURL-pay and we are still far from seeing its full potential.

I also think the lightning related spec should be universal. Being able to use it also for other areas like for example blogging makes it more powerful.

If we couple this closely to Nostr and if it is only useful within Nostr then imo it's better to just have a Nostr specific setup (as @fiatjaf says).

From my understanding the requirements are:

  • having a new nostr note type that references the payment (kind 9735 - the zap) to tally the payment
  • being able to associate the payment to the note or the zap on the lightning node
  • having the possibility to somewhat validate that the payment had happend - but ultimately we're trusting the recipient.

is this correct?

With LUD18 we have the protocol to pass a payerData record to the LNURL server

A potential protocol flow:

Client side

  1. Calculate the lnurl pay request URL for a user from the lud06 or lud16 field on their profile

  2. Fetch the lnurl pay request static endpoint (https://host.com/.well-known/lnurlp/user) and gather the payerData record.

  3. To get a invoice, call the callback url with amount set to the milli-satoshi amount value and the payerData as described in LUD18.
    The pubkey is the nostr pubkey.
    a payable could contain a URI of the note (nostr:note...) or the full note itself. This allows the recipient to reference from the LN side the receiving note.
    To align with the current proposal the zap request could be passed in here.
    If a LNURL provider does not implement this it would still work the recipient would mainly miss the reference to the note which was paid.

  4. Pay this invoice or pass it to an app that can pay the invoice. For improved usability I expect more clients to integrate lightning wallets through APIs like the ZBD API, Breez SDK, Alby API, WebLN, etc. (web clients already do this with WebLN) Those APIs return the preimage to the initiating client.

If the invoice is passed to an app the preimage can not be passed back. In this case the LNURL-verify can be used to check the payment status and retrieve details like the preimage from the LNURL-server. (this is what @v0l proposes above)
If none is available and the preimage can not be gathered the validation would not work.

  1. Create and publish the zap note including the payment request and the preimage for some validation
    Note: the description_hash included the payerdata. The payment hash from the invoice can be checked against the preimage. The note maybe also should include a lnurl-verify link for other clients to validate the payment (basically clients can ask the recipient if that zap was received). Like LNURL itself this would simpley use HTTP.

LNURL Server side

  • the LNURL server will create the invoice as described in LUD18 - it needs support for LUD18. If not then just no Nostr data would be saved. (like currently with email/name etc.)

  • if publishing the zap from the receiving node is really preferred (instead of 5. on the client side) the zap request could be loaded from the LUD18 field and published. - This would be the only Nostr specific implementation then on the LNURL-Sever side.

  • the LNURL Server should not need to implement any Nostr specific requirements and no new protocols (stick to HTTP and not add a WS dependency)

As mentioned I generally think that the LNURL-pay spec should not contain any application/usage specific requirements. From a LNURL point of view Nostr is "just" one usage. I think with some abstraction this can be done and does not require high-level Nostr coupling.

P.S.
the speed here in Nostr is amazing. I started typing this a few days ago but was too busy finishing it and so much had happend. :)
Go Nostr!

@starbackr-dev
Copy link
Contributor

  1. Create and publish the zap note including the payment request and the preimage for some validation
    Note: the description_hash included the payerdata. The payment hash from the invoice can be checked against the preimage. The note maybe also should include a lnurl-verify link for other clients to validate the payment (basically clients can ask the recipient if that zap was received). Like LNURL itself this would simpley use HTTP.

Thanks Bumi for the approach. I really like multiple options in who is creating the note kind - 9735. Nostr clients should determine this and should not force lightning providers to create this. It is not important at all on who is creating this note kind 9735 only the content in this note such as preimage, bolt11 and LNURL-verify is important.

This also opens up another scenario/use case for anonymous zaps where the zap sender pay for sats but don't want his pub key associated with it. Think of Canadian truck drivers protest. To keep anonymity, after the payment is successful, Nostr client can create this note with a random private key and destroy the key after it is posted. Zap receiver or the public don't know who zapped it but they receive sats which is powerful.

Am also up for implementing multiple approaches to see which one is liked and adopted by the users. Thanks to @jb55 and @v0l for pushing a working version into the wild and seeing the reaction.

@fiatjaf
Copy link
Member

fiatjaf commented Feb 12, 2023

It is not important at all on who is creating this note kind 9735

In fact it is. When displaying the zaps, clients are trusting that they come from a reputable provider -- or from the direct zap receiver themselves. If anyone can create an event then I can create a trillion zap events myself and fake that I have tipped the entire universe.

@starbackr-dev
Copy link
Contributor

clients are trusting that they come from a reputable provider

Don't trust but verify...! if you are trusting that they came from a reputable provider then there is no difference between today's world (Apple trusting VisaMastercard). We are simply replacing the current overlords with new ones. You can argue that the new overlords are better but that is not the point. The lightning/wallet providers should provide a verifiable link for the payment LN-URL which can be embedded on the note.

@fiatjaf
Copy link
Member

fiatjaf commented Feb 12, 2023

About @bumi's proposal above, I want to say that it would be nice to have it realized, but I am afraid the added complexity wouldn't be worth the trouble. @jb55 has actually implemented a zap flow using LUD-18 as far as I know, but later decided to drop it, which I think was sensible (I just don't understand why he didn't go all the way and dropped everything, which is what I want to happen).

The complexity I mention above is mostly the reliance on the lnurl-verify bit which is not implemented anywhere, and then the need for clients to poll that endpoint.

There is also the problem that the payer is the one publishing the zap, which opens the door for anyone to forge zaps @starbackr-dev (unless we introduce another requiment, that the invoice is signed by the receiver nostr public key or sometihng like that, i.e. more complexity). I think the receiver should be the one signing the zap events. My solution for a pure-lnurl flow at #243 (comment) addresses that (actually it is @ok300's proposal, I just made a suggestion on top of it), but it introduces too many requirements and complexity, so I don't think it is worth the trouble either.

Considering all this I believe the most sensible path forward is to get rid of lnurl entirely and make a simpler protocol that is specific to Nostr.

@bumi
Copy link

bumi commented Feb 12, 2023

In fact it is. When displaying the zaps, clients are trusting that they come from a reputable provider

the client only needs to be able to verify it. In my proposal this is done by asking the receiver (reputable provider) - not through a nostr note signing but through the same method we actually receive the invoice from the receiver. (with a HTTP call)

both LUD-18 and LNURL-verify would be optional. LUD-18 is only needed to tell the recipient for which note that payment was. and LNURL-verify would only be for clients to check if the claimed payment actually happened.

@fiatjaf can you describe the complexity that you see?
because to me it is much less. LUD18 is already often implemented and the verification is one HTTP endpoint. It only requires data that the provider already has and the provider already speaks HTTP to create the invoice. So it is not more than another route.
Requiring LNURL providers now to implement event validation, signing and websockets is much more complexity to me and requires a whole new flow. LNURL providers should not be required to implement social networking publishing features - also not to Nostr.

If we would do that, I am with @fiatjaf that this should no longer be LNURL. That spec should be universal and not have such a tight coupling to something else like some social networking.

@jb55
Copy link
Contributor Author

jb55 commented Feb 12, 2023

what makes something lnurl vs not lnurl? I agree it's not lnurl, all I'm doing is piggy-backing on the lnurl endpoint since these servers are already setup to fetch invoices from backends. the only thing that changes is the metadata gets swapped out with a nostr note.

This is the entirety of the change required on my lnurl server:

From 4677a23f3c776326ee4f622d45cd54127284e864 Mon Sep 17 00:00:00 2001
From: William Casarin <jb55@jb55.com>
Date: Sun, 8 Jan 2023 17:11:26 -0800
Subject: [PATCH] accept nostr notes

---
 index.js          | 86 +++++++++++++++++++++++++++++++++++++++++++----
 package.json      |  2 +-
 public/index.html |  2 +-
 3 files changed, 81 insertions(+), 9 deletions(-)

diff --git a/index.js b/index.js
index d836358..32de30c 100644
--- a/index.js
+++ b/index.js
@@ -45,12 +45,12 @@ async function make_request(auth, method, params) {
 }
 
 
-async function make_invoice(opts, amount)
+async function make_invoice(opts, amount, extra)
 {
 	try {
 		const res = await make_request(opts, "invoice", {
 			amount_msat: amount || "any",
-			description: make_metadata_str(opts),
+			description: make_metadata_str(opts, extra),
 			deschashonly: true,
 			label: crypto.randomUUID().toString(),
 		})
@@ -85,8 +85,11 @@ function make_metadata(opts) {
 	return metadata
 }
 
-function make_metadata_str(opts) {
-	return JSON.stringify(make_metadata(opts))
+function make_metadata_str(opts, extra) {
+	if (extra && extra.nostr)
+		return JSON.stringify(extra.nostr)
+
+	return JSON.stringify(make_metadata(opts, extra))
 }
 
 async function find_metadata(user)
@@ -125,6 +128,23 @@ function invalid_username(res) {
 	return json_err(res, "Bad username", 400)
 }
 
+function get_nostr_note(parsed) {
+	let nostr = parsed.searchParams.get('nostr')
+	if (nostr == null)
+		return
+
+	try {
+		nostr = JSON.parse(nostr)
+	} catch (e) {
+		throw new Error(`nostr parameter must be a nostr note: ${e}`)
+	}
+
+	const validated = validate_note(nostr)
+	if (validated !== true)
+		throw new Error(validated)
+	return nostr
+}
+
 async function handle_static_payreq(parsed, req, res)
 {
 	let user = user_from_wellknown(parsed.pathname)
@@ -137,13 +157,26 @@ async function handle_static_payreq(parsed, req, res)
 	if (metadata === null)
 		return user_not_found(res)
 
-	const resp = {
+	let nostr
+	try {
+		nostr = get_nostr_note(parsed)
+	} catch (e) {
+		return json_err(res, e.toString(), 400)
+	}
+	const extra = { nostr }
+
+	let resp = {
 		status: "OK",
 		tag: "payRequest",
 		minSendable: 1,
 		maxSendable: 10000000000,
 		callback: `https://sendsats.lol/@${user}`,
-		metadata: make_metadata_str(metadata),
+		metadata: make_metadata_str(metadata, extra),
+	}
+
+	if (user === "jb55") {
+		resp.allowsNostr = true
+		resp.nostrPubkey = "9630f464cca6a5147aa8a35f0bcdd3ce485324e732fd39e09233b1d848238f31"
 	}
 
 	return json_ok(res, resp)
@@ -161,12 +194,21 @@ async function handle_payreq(parsed, req, res)
 	if (!amount)
 		return json_err(res, "Missing amount", 400)
 
+	
+	let nostr
+	try {
+		nostr = get_nostr_note(parsed)
+	} catch (e) {
+		return json_err(res, e.toString(), 400)
+	}
+	const extra = { nostr }
+
 	const metadata = await find_metadata(user)
 	if (metadata === null)
 		return user_not_found(res)
 
 	try {
-		const pr = await make_invoice(metadata, amount)
+		const pr = await make_invoice(metadata, amount, extra)
 		const routes = []
 		json_ok(res, {pr, routes})
 	} catch (e) {
@@ -316,6 +358,36 @@ async function serve_page(pathname, req, res)
 
 }
 
+function validate_note(note)
+{
+	if (note.kind !== 9734)
+		return "Expected tip request note (kind 9734)"
+
+	if (!note.tags)
+		return "No tags found?"
+
+	// Make sure we only have one p tag
+        const ptags = note.tags.filter(t =>
+		t && t.length && t.length >= 2 && t[0] === "p")
+
+        if (ptags.length !== 1)
+                return "None or multiple p tags found"
+
+	// Make sure we have 0 or 1 etag (for note tipping)
+	const etags = note.tags.filter(t =>
+		t && t.length && t.length >= 2 && t[0] === "e")
+	if (!(etags.length === 0 || etags.length === 1))
+		return "Expected 0 or 1 e tags"
+
+	// Look for the relays tag, the wallet will broadcast to these relays
+	const relays_tag = note.tags.find(t =>
+		t && t.length && t.length >= 2 && t[0] === "relays")
+	if (!relays_tag)
+		return "No relays tag found"
+
+	return true
+}
+
 function handle_request(opts, req, res)
 {
 	console.log("%s - %s", req.method, req.url)
diff --git a/package.json b/package.json
index eba4435..d68a4c0 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
   "name": "sendsats.lol",
   "description": "sendsats.lol",
-  "version": "0.1.0",
+  "version": "1.2.2",
   "repository": {
     "url": "https://github.com/jb55/sendsats.lol"
   },
diff --git a/public/index.html b/public/index.html
index 3f7cbc0..0c26a25 100644
--- a/public/index.html
+++ b/public/index.html
@@ -102,7 +102,7 @@
 
 	  <script src="js/qrcode.js?v=3" > </script>
 	  <script src="js/lnsocket.js?v=3" > </script>
-	  <script src="js/index.js?v=10" > </script>
+	  <script src="js/index.js?v=11" > </script>
 
     </body>
 </html>
-- 
2.39.1

The proposed alternative seems like I would have to rejig everything for reasons which I don't understand.

@jb55
Copy link
Contributor Author

jb55 commented Feb 12, 2023

afaik snort, damus and amethyst have already implemented the original spec

@fiatjaf
Copy link
Member

fiatjaf commented Feb 12, 2023

The change is small, but it introduces spaghetti in your lnurl server.

And it is only small because you already have an lnurl server.

Now for people that want to make zap-only servers, they will have to make a full lnurl server first, then introduce your changes -- while if the protocol didn't rely on anything related to lnurl their complete job of implementing zaps would be much smaller.

The same applies to clients that only want to implement zaps and not lnurl donations. Since zaps are a much more natural way of doing things on Nostr I imagined the lnurl donation stuff would end up dying, which would be a good thing probably.

@fiatjaf
Copy link
Member

fiatjaf commented Feb 12, 2023

Another problem with the way this NIP was made is that now users can't have separate zap and lnurl services on their profile.

They could choose to have an lnurl for donations -- and that same service doesn't support zaps, but they can't.

Or they could decide to use a service that just supports zaps, not lnurl, and now people will see on clients that they accept lnurl and just be frustrated when paying.

The proposal will either make user experience worse everywhere or make it so only providers implementing both protocols will be chosen by users, which will have a centralizing effect.

It's naïve to assume only services implementing lnurl today will implement zap support and also that 100% of those will implement zap support, which are the two requirements for this NIP proposal to be a good idea.

@starbackr-dev
Copy link
Contributor

starbackr-dev commented Feb 13, 2023

According to @fiatjaf comments, both approaches appear to have equal pros and cons. However, @jb55 stated that the specifications have already been implemented in three popular Nostr clients. So I went ahead and started putting it into action. It only took a couple of hours for me to change the backend so that LNURL will continue to work for non-Nostr use cases and posting type 9735 will just be implemented for invoices created by Nostr clients. It is preferable to test this in public to obtain user feedback rather than iterating inside github.

@fiatjaf fiatjaf merged commit 17ffd3e into master Feb 13, 2023
@fiatjaf fiatjaf deleted the zaps branch February 13, 2023 11:36
@fiatjaf
Copy link
Member

fiatjaf commented Feb 13, 2023

Turns out this was settled long before the PR was opened, there were no answers to any the feedback presented here at all. Committing directly to master would have been better and would have wasted less time from others.

@ok300
Copy link
Contributor

ok300 commented Feb 13, 2023

Agree. Very unfortunate.

@pgerstbach
Copy link

Reading this PR makes me think why the rush? Nostr is developing fast, that's great, but more "PRs" like this and Nostr might end up in a complete mess. It suppose it is good practice to propose something and implement it in parallel to do a reality-check, but if the discussion shows that some NIP has flaws early developers need to re-do the work and not stick to it. I wonder how this will turn out...

To my understanding (as a interested user, not as a developer) I find it confusing to have a working lnurl service, but zaps do not work. And if I want to test zaps with a supported provider, I can't use my working lnurl service.

@ok300
Copy link
Contributor

ok300 commented Feb 14, 2023

There was a proposal to address exactly that: #244

@ok300
Copy link
Contributor

ok300 commented Feb 14, 2023

There were also other proposals above that made zaps not interfere with LNURL, or at least be backwards compatible with existing LNURL services.

But hey, this was easy to implement bro, don't understand what the fuss is all about.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet