You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Follow-up to the Nostr server-side issue (advertise allowsNostr/nostrPubkey, accept + structurally validate the nostr zap request, use it as the invoice description). This issue adds the parts that need cryptography, a relay/WebSocket client, and a payment-settled hook to make the server fully NIP-57 compliant: verify the incoming zap request's signature, and sign + publish the kind-9735 zap receipt after payment.
This is the largest new surface — the library currently has no payment-notification path (requestInvoice returns pr and stops) and no outbound WebSocket.
Goal
Full NIP-57 zap compliance: verified zap requests, and signed kind-9735 receipts published to the request's relays once the invoice settles.
Scope / Tasks
Add a Nostr crypto dependency. Evaluate swentel/nostr-php (Schnorr signing + relay WebSocket — covers both signing and publishing) and/or an extension-backed verifier (uma/secp256k1-nostr, innis/nostr-core) for fast signature verification. Pick and justify.
Verify the zap request signature (NIP-57 Appendix D rule 1): recompute the event id = sha256 of the NIP-01 serialized array and BIP-340 Schnorr-verify against the event pubkey. Reject invalid signatures.
Server Nostr key management: config for the server's Nostr private key (matching the advertised nostrPubkey). Handle securely (env/secret, never logged/committed).
Payment-settled hook: add a way to learn when an invoice is paid — an LNbits webhook route (the invoice request supports webhook) and/or polling. Persist the stored zap request keyed to the invoice/payment hash so it can be matched on settlement.
Build + sign the kind-9735 receipt (NIP-57 Appendix E):
tags: p (recipient, from request), optional P (sender = request pubkey), optional e/a/k copied from the request, bolt11 (the paid invoice), description (the exact zap-request JSON that was hashed), optional preimage.
id = sha256(serialization), sig = BIP-340 Schnorr by the server key.
Publish the receipt over WebSocket to every relay in the zap request's relays tag (["EVENT", <9735>]), handling OK/NOTICE.
Tests: signature verify accept/reject with fixtures; receipt event construction (tags/content/created_at) against the NIP-57 example; a mocked relay-publish path.
Implementation notes
SHA256(description) on the receipt MUST match the invoice's description_hash — reuse the exact stored zap-request bytes from the server-side issue.
This likely warrants a new module (e.g. src/Zap/…) plus an infrastructure route for the LNbits webhook.
Relay publishing and signing are the genuinely new capabilities; keep them behind interfaces so they're testable without live relays/nodes.
Acceptance criteria
Forged zap requests are rejected (bad Schnorr sig).
On invoice settlement, a correctly-signed 9735 receipt is generated and pushed to the request's relays (verified against a mock relay).
Receipt description matches the invoice description_hash.
composer test-all green; server private key never logged/committed.
Dependencies
Depends on the Nostr server-side issue (advertisement + request handling + zap-as-description).
Context
Follow-up to the Nostr server-side issue (advertise
allowsNostr/nostrPubkey, accept + structurally validate thenostrzap request, use it as the invoice description). This issue adds the parts that need cryptography, a relay/WebSocket client, and a payment-settled hook to make the server fully NIP-57 compliant: verify the incoming zap request's signature, and sign + publish the kind-9735 zap receipt after payment.This is the largest new surface — the library currently has no payment-notification path (
requestInvoicereturnsprand stops) and no outbound WebSocket.Goal
Full NIP-57 zap compliance: verified zap requests, and signed kind-9735 receipts published to the request's relays once the invoice settles.
Scope / Tasks
swentel/nostr-php(Schnorr signing + relay WebSocket — covers both signing and publishing) and/or an extension-backed verifier (uma/secp256k1-nostr,innis/nostr-core) for fast signature verification. Pick and justify.id= sha256 of the NIP-01 serialized array and BIP-340 Schnorr-verify against the eventpubkey. Reject invalid signatures.nostrPubkey). Handle securely (env/secret, never logged/committed).webhook) and/or polling. Persist the stored zap request keyed to the invoice/payment hash so it can be matched on settlement.kind:9735,content:"",created_at:invoicepaid_at,pubkey:server'snostrPubkey.p(recipient, from request), optionalP(sender = requestpubkey), optionale/a/kcopied from the request,bolt11(the paid invoice),description(the exact zap-request JSON that was hashed), optionalpreimage.id= sha256(serialization),sig= BIP-340 Schnorr by the server key.relaystag (["EVENT", <9735>]), handlingOK/NOTICE.Implementation notes
SHA256(description)on the receipt MUST match the invoice'sdescription_hash— reuse the exact stored zap-request bytes from the server-side issue.src/Zap/…) plus an infrastructure route for the LNbits webhook.Acceptance criteria
descriptionmatches the invoicedescription_hash.composer test-allgreen; server private key never logged/committed.Dependencies
References