feat: pay Nostr Offer Strings (CLINK)#4102
Open
kaloudis wants to merge 12 commits into
Open
Conversation
Contributor
There was a problem hiding this comment.
Code Review
This pull request introduces support for CLINK (Nostr-based Lightning offers), adding a new payment flow, utility functions for offer decoding, and integration into the contact and URI handling systems. The reviewer suggested an improvement to the decodeNoffer utility to ensure full compliance with the CLINK specification by correctly handling default price types when the TLV field is omitted.
A CLINK offer is discovered from the NIP-05 side (not the reverse) with Example NIP-05 Response: {
"names": {
"bob": "<hex_pub>"
},
"clink_offer": {
"bob": "noffer1..."
}
} |
ajaysehwal
reviewed
May 25, 2026
…p) + err localization
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Relates to issue: ZEUS-2400
Adds support for CLINK — pay-to-noffer over Nostr. CLINK is a successor to LNURL-pay and Lightning Addresses that uses Nostr direct messages as transport, eliminating the need for a publicly accessible HTTPS endpoint on the recipient side.
How it works
A
noffer1...bech32 string carries the recipient's Nostr pubkey, a recommended relay URL, and an offer id (plus optional pricing hints). When the user scans or pastes one:PaymentRequestflow.Entry points
noffer1...(scan / paste).?noffer=noffer1...(collision case routes throughChoosePaymentMethod, which now shows a CLINK row).ContactDetails, the Contacts settings list, and the Send-screen contact picker.Spec compliance
clink_version: "1"tag on every request and response; responses lacking it are rejected.verifySignature) and the author is checked against the offer's recipient pubkey before decryption.Out of scope / follow-up
.onionrelays: refused with a clear error rather than silently leaked over clearnet. WebSocket-over-Tor would be a separate change.ndebit1) and CLINK Manage (nmanage1): tracked separately; this PR is offers-only.{res:"ok", preimage}): redundant with the LN backend's own preimage; not wired.PR Type
This pull request is categorized as a:
Checklist
yarn run tscand made sure my code compiles correctlyyarn run lintand made sure my code didn't contain any problematic patternsyarn run prettierand made sure my code is formatted correctlyyarn run testand made sure all of the tests passTesting
If you modified or added a utility file, did you add new unit tests?
utils/ClinkUtils.test.tscovers the bech32/TLV decoder (all three pricing types, multi-byte prices, uppercase, malformed input, bad checksum, missing required TLVs, wrong prefix), the request-payload builder (amount-required enforcement for spontaneous/variable), the response-event structural validator (wrong kind, wrong author, missingclink_version, wrongetag), andverifyBolt11MatchesOfferagainst signed bolt11 test vectors (fixed match/mismatch, spontaneous match/mismatch, variable match, amountless-allowed-for-spontaneous, amountless-rejected-otherwise, undecodable input).utils/AddressUtils.test.tscovers thenoffer=BIP-21 parameter parsing.I have tested this PR on the following platforms (please specify OS version and phone model/VM):
I have tested this PR with the following types of nodes (please specify node version and API version where appropriate):
On-device
Remote
Locales
New keys:
views.ClinkPay.*(14),views.Settings.Noffer,utils.handleAnything.invalidNoffer.Third Party Dependencies and Packages
yarnafter this PR is merged inNo new dependencies — uses
nostr-tools(1.16.0),@nostr/tools/nip44,@scure/base, andbolt11, all already inpackage.json.