8.5 KiB
NIP-57
Lightning Zaps
draft optional author:jb55 author:kieran
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 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.
Definitions
zapper - the lightning node or service that sends zap notes (kind 9735)
zap request - a note of kind 9734 created by the person zapping
zap invoice - the bolt11 invoice fetched from a custom lnurl endpoint which contains a zap request note
Protocol flow
Client side
-
Calculate the lnurl pay request url for a user from the lud06 or lud16 field on their profile
-
Fetch the lnurl pay request static endpoint (
https://host.com/.well-known/lnurlp/user) and gather theallowsNostrandnostrPubkeyfields. IfallowsNostrexists and it istrue, and ifnostrPubkeyexists and is a valid BIP 340 public key, associate this information with the user. ThenostrPubkeyis thezapper's pubkey, and it is used to authorize zaps sent to that user. -
Clients may choose to display a lightning zap button on each post or on the users profile, if the user's lnurl pay request endpoint supports nostr, the client SHOULD generate a
zap invoiceinstead of a normal lnurl invoice. -
To generate a
zap invoice, call thecallbackurl withamountset to the milli-satoshi amount value. Anostrquerystring value MUST be set as well. It is a uri-encodedzap requestnote signed by the user's key. Thezap requestnote contains anetag of the note it is zapping, and aptag of the target user's pubkey. Theetag is optional which allows profile tipping. An optionalatag allows tipping parameterized replaceable events such as NIP-23 long-form notes. Thezap requestnote must also have arelaystag, which is gathered from the user's configured relays. Thezap requestnote SHOULD contain anamounttag, which is the milli-satoshi value of the zap which clients SHOULD verify being equal to the amount of the invoice. ThecontentMAY be an additional comment from the user which can be displayed when listing zaps on posts and profiles. -
Pay this invoice or pass it to an app that can pay the invoice. Once it's paid, a
zap notewill be created by thezapper.
LNURL Server side
The lnurl server will need some additional pieces of information so that clients can know that zap invoices are supported:
-
Add a
nostrPubkeyto the lnurl-pay static endpoint/.well-known/lnurlp/user, wherenostrPubkeyis the nostr pubkey of thezapper, the entity that creates zap notes. Clients will use this to authorize zaps. -
Add an
allowsNostrfield and set it to true. -
In the lnurl-pay callback URL, watch for a
nostrquerystring, where the contents of the note is a uri-encodedzap requestJSON. -
If present, the zap request note must be validated:
a. It MUST have a valid nostr signature
b. It MUST have tags
c. It MUST have at least one p-tag
d. It MUST have either 0 or 1 e-tag
e. There should be a
relaystag with the relays to send thezapnote to.f. If there is an
amounttag, it MUST be equal to theamountquery parameter.g. If there is an
atag, it MUST be a valid NIP-33 event coordinate -
If valid, fetch a description hash invoice where the description is this note and this note only. No additional lnurl metadata is included in the description.
At this point, the lightning node is ready to send the zap note once payment is received.
The zap note
Zap notes are created by a lightning node reacting to paid invoices. Zap notes are only created when the invoice description (committed to the description hash) contains a zap request note.
Example zap note:
{
"id": "67b48a14fb66c60c8f9070bdeb37afdfcc3d08ad01989460448e4081eddda446",
"pubkey": "9630f464cca6a5147aa8a35f0bcdd3ce485324e732fd39e09233b1d848238f31",
"created_at": 1674164545,
"kind": 9735,
"tags": [
[
"p",
"32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245"
],
[
"e",
"3624762a1274dd9636e0c552b53086d70bc88c165bc4dc0f9e836a1eaf86c3b8"
],
[
"bolt11",
"lnbc10u1p3unwfusp5t9r3yymhpfqculx78u027lxspgxcr2n2987mx2j55nnfs95nxnzqpp5jmrh92pfld78spqs78v9euf2385t83uvpwk9ldrlvf6ch7tpascqhp5zvkrmemgth3tufcvflmzjzfvjt023nazlhljz2n9hattj4f8jq8qxqyjw5qcqpjrzjqtc4fc44feggv7065fqe5m4ytjarg3repr5j9el35xhmtfexc42yczarjuqqfzqqqqqqqqlgqqqqqqgq9q9qxpqysgq079nkq507a5tw7xgttmj4u990j7wfggtrasah5gd4ywfr2pjcn29383tphp4t48gquelz9z78p4cq7ml3nrrphw5w6eckhjwmhezhnqpy6gyf0"
],
[
"description",
"{\"pubkey\":\"32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245\",\"content\":\"\",\"id\":\"d9cc14d50fcb8c27539aacf776882942c1a11ea4472f8cdec1dea82fab66279d\",\"created_at\":1674164539,\"sig\":\"77127f636577e9029276be060332ea565deaf89ff215a494ccff16ae3f757065e2bc59b2e8c113dd407917a010b3abd36c8d7ad84c0e3ab7dab3a0b0caa9835d\",\"kind\":9734,\"tags\":[[\"e\",\"3624762a1274dd9636e0c552b53086d70bc88c165bc4dc0f9e836a1eaf86c3b8\"],[\"p\",\"32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245\"],[\"relays\",\"wss://relay.damus.io\",\"wss://nostr-relay.wlvs.space\",\"wss://nostr.fmt.wiz.biz\",\"wss://relay.nostr.bg\",\"wss://nostr.oxtr.dev\",\"wss://nostr.v0l.io\",\"wss://brb.io\",\"wss://nostr.bitcoiner.social\",\"ws://monad.jb55.com:8080\",\"wss://relay.snort.social\"]]}"
],
[
"preimage",
"5d006d2cf1e73c7148e7519a4c68adc81642ce0e25a432b2434c99f97344c15f"
]
],
"content": "",
"sig": "b0a3c5c984ceb777ac455b2f659505df51585d5fd97a0ec1fdb5f3347d392080d4b420240434a3afd909207195dac1e2f7e3df26ba862a45afd8bfe101c2b1cc"
}
-
The zap note MUST have a
bolt11tag containing the description hash bolt11 invoice. -
The zap note MUST contain a
descriptiontag which is the invoice description. -
SHA256(description)MUST match the description hash in the bolt11 invoice. -
The zap note MAY contain a
preimageto match against the payment hash of the bolt11 invoice. This isn't really a payment proof, there is no real way to prove that the invoice is real or has been paid. You are trusting the author of the zap note for the legitimacy of the payment.
The zap note is not a proof of payment, all it proves is that some nostr user fetched an invoice. The existence of the zap note implies the invoice as paid, but it could be a lie given a rogue implementation.
Creating a zap note
When receiving a payment, the following steps are executed:
-
Get the description for the invoice. This needs to be saved somewhere during the generation of the description hash invoice. It is saved automatically for you with CLN, which is the reference implementation used here.
-
Parse the bolt11 description as a JSON nostr note. You SHOULD check the signature of the parsed note to ensure that it is valid. This is the
zap requestnote created by the entity who is zapping. -
The note MUST have only one
ptag -
The note MUST have 0 or 1
etag -
Create a nostr note of kind
9735that includes theptag AND optionaletag. The content SHOULD be empty. The created_at date SHOULD be set to the invoice paid_at date for idempotency. -
Send the note to the
relaysdeclared in thezap requestnote from the invoice description.
A reference implementation for the zapper is here: zapper
Client Behavior
Clients MAY fetch zap notes on posts and profiles:
{"kinds": [9735], "#e": [...]}
To authorize these notes, clients MUST fetch the nostrPubkey from the users configured lightning address or lnurl and ensure that the zaps to their posts were created by this pubkey. If clients don't do this, anyone could forge unauthorized zaps.
Once authorized, clients MAY tally zaps on posts, and list them on profiles. If the zap request note contains a non-empty content, it may display a zap comment. Generally clients should show users the zap request note, and use the zap note to show "zap authorized by ..." but this is optional.
Future Work
Zaps can be extended to be more private by encrypting zap request notes to the target user, but for simplicity it has been left out of this initial draft.