From 858e73ea81afd64307c3c406031ca3e6baf3c225 Mon Sep 17 00:00:00 2001 From: shocknet-justin <34176400+shocknet-justin@users.noreply.github.com> Date: Mon, 26 Aug 2024 22:54:45 -0400 Subject: [PATCH 01/24] first pass --- 69.md | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 69.md diff --git a/69.md b/69.md new file mode 100644 index 0000000000..976d726b07 --- /dev/null +++ b/69.md @@ -0,0 +1,123 @@ +NIP-69 +====== + +Nostr Offer STRings +------------------- + +`wip` `optional` + +This NIP proposes a format for static payment codes in Nostr as a successor to LNURL-Pay, enabling users to initiate Lightning Network payments by scanning or clicking a string. + +## Motivation + +Reliance on LNURL has led to centralization via custodial solutions due to the legacy baggage of IP4-NAT/Domain/SSL requirements. Nostr's use-cases are already centered around Lightning, whether as a wallet connector, zap receipts, or its overlapping network effects, rendering Nostr as a de facto "3rd layer" for Lightning and a natural successor to LNURL. + +When layered over kind 21000, NWC, or other potential Lightning RPCs, this specification enables a seamless user experience similar to legacy LNURL-Pay, without the domain and SSL requirements. Additionally, the signed nature of Nostr communications eliminates the trust requirements inherent in LNURL when a node must outsource the serving of web requests. + +## Specification + +### Static Payment Code Format + +The static payment code is a bech32 (per NIP-19) encoded string prefixed with `noffer`. The encoded string will include the following TLV (Type-Length-Value) items: + +- `0`: The 32 bytes of the receiving services public key, encoded in hex. +- `1`: The relay URL where the receiving service subscribes to payment requests +- `2`: The offer string + +## Process Flow + +1. **Payer Scans or Clicks the Static Payment Code** + +2. **Payers wallet decodes the payment code** + +3. **Payers wallet sends a Nostr event to the specified relay, addressed to the receiver's public key, containing the identifier string.** + - Event Type: Ephemeral Kind 21001 | NIP-44 Encrypted + - Optional: Include additional payer data + +4. **Receiver Responds with Lightning Invoice** + - Upon receiving the payment request event, the receiver generates a Lightning invoice and responds with a Nostr event containing the invoice details. + - Event Type: Ephemeral Kind 21001 | NIP-44 Encrypted + - Optional: Include additional purchase data + +5. **Payer Pays the Invoice** + - The payer completes the payment by settling the Lightning invoice. + +6. **Optional: Receiver Emits Payment Receipt** + - This step is out of scope for this NIP, but potential receipt considerations include: + a. Nostr Event as Receipt: Emitting a public Nostr event as a "zap" receipt for verifiable record-keeping. + b. Lightning Pre-Image: Sharing the Lightning pre-image as proof of payment. + c. External / WebHook: The receiver may finalize the flow out-of-band. + +### Nostr Event + +This NIP specifies the use of event kind `21001` with the following structure: + +- `content`: NIP-44 encrypted payment details +- `tags`: + - `p`: Receiver's public key (encoded in hex) + - `relay`: URL of the relay for receiving payment requests + - `offer`: Unique identifier for the payment purpose + +Example event: +```json +{ + "id": "", + "pubkey": "", + "created_at": 1234567890, + "kind": 21001, + "tags": [ + ["p", ""], + ["e", ""] // used only in response by the receiver to identify the original payment request + ], + "content": "", + "sig": "" +} +``` + +The `content` field should contain a stringified JSON object with the following structure: + +```json +{ + "offer_id": "", + "payer_data": "" +} +``` + +## Client Behavior + +Clients implementing this NIP must: + +1. Decode and validate the structure of the `noffer` bech32-encoded static payment code. +2. Use NIP-44 encryption for all communication between payer and receiver. +3. Generate and send kind 21001 events as specified in this NIP. +4. Parse the `content` field of received events by decrypting and JSON-parsing the stringified content. +5. Handle potential errors gracefully, providing clear feedback to users. +6. Respect the `relay` tag specified in the static payment code for sending payment request events. + +Clients implementing this NIP may: + +1. Support both this protocol and LNURL for backward compatibility during the transition period. +2. Implement additional features such as multi-recipient payments or integration with other Lightning-related NIPs. + +Clients implementing this NIP MUST NOT: + +1. Send unencrypted sensitive information in event content or tags. +2. Ignore or modify any fields from the encoded static payment code. + +## Notes + +### Transition from LNURL + +LNURL services wishing to migrate to Nostr Offer STRings should consider adding a `noffer` tag to their responses. + +### Future Considerations + +Future versions of this NIP may consider additional features such as: + +1. Multi-recipient payments +2. Integration with other Lightning-related NIPs +3. Extended metadata for more complex payment scenarios + +## Reference Implementation + +Lightning.Pub / ShockWallet offers branch \ No newline at end of file From aa57d5f49efbcbf90602b412405f0d45316586bb Mon Sep 17 00:00:00 2001 From: shocknet-justin <34176400+shocknet-justin@users.noreply.github.com> Date: Fri, 30 Aug 2024 15:25:35 -0400 Subject: [PATCH 02/24] errors --- 69.md | 100 ++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 62 insertions(+), 38 deletions(-) diff --git a/69.md b/69.md index 976d726b07..eb51d93b30 100644 --- a/69.md +++ b/69.md @@ -1,12 +1,12 @@ -NIP-69 -====== +NIP-69: Nostr Offer STRings +=========================== Nostr Offer STRings ------------------- `wip` `optional` -This NIP proposes a format for static payment codes in Nostr as a successor to LNURL-Pay, enabling users to initiate Lightning Network payments by scanning or clicking a string. +This NIP proposes a format for static payment codes in Nostr as a successor to LNURL-Pay, enabling users to initiate Lightning Network payments by scanning or clicking a string. ## Motivation @@ -20,45 +20,40 @@ When layered over kind 21000, NWC, or other potential Lightning RPCs, this speci The static payment code is a bech32 (per NIP-19) encoded string prefixed with `noffer`. The encoded string will include the following TLV (Type-Length-Value) items: -- `0`: The 32 bytes of the receiving services public key, encoded in hex. -- `1`: The relay URL where the receiving service subscribes to payment requests -- `2`: The offer string +- `0`: The 32 bytes of the receiving service's public key, encoded in hex. +- `1`: The relay URL where the receiving service subscribes to payment requests. +- `2`: The offer string. -## Process Flow +### Process Flow 1. **Payer Scans or Clicks the Static Payment Code** - -2. **Payers wallet decodes the payment code** - -3. **Payers wallet sends a Nostr event to the specified relay, addressed to the receiver's public key, containing the identifier string.** +2. **Payer's Wallet Decodes the Payment Code** +3. **Payer's Wallet Sends a Nostr Event to the Specified Relay** + - Addressed to the receiver's public key, containing the identifier string. - Event Type: Ephemeral Kind 21001 | NIP-44 Encrypted - - Optional: Include additional payer data - + - Optional: Include additional payer data. 4. **Receiver Responds with Lightning Invoice** - - Upon receiving the payment request event, the receiver generates a Lightning invoice and responds with a Nostr event containing the invoice details. + - Generates a Lightning invoice and responds with a Nostr event containing the invoice details. - Event Type: Ephemeral Kind 21001 | NIP-44 Encrypted - - Optional: Include additional purchase data - + - Optional: Include additional purchase data. 5. **Payer Pays the Invoice** - - The payer completes the payment by settling the Lightning invoice. - + - Completes the payment by settling the Lightning invoice. 6. **Optional: Receiver Emits Payment Receipt** - This step is out of scope for this NIP, but potential receipt considerations include: - a. Nostr Event as Receipt: Emitting a public Nostr event as a "zap" receipt for verifiable record-keeping. - b. Lightning Pre-Image: Sharing the Lightning pre-image as proof of payment. - c. External / WebHook: The receiver may finalize the flow out-of-band. + - Nostr Event as Receipt: Emitting a public Nostr event as a "zap" receipt for verifiable record-keeping. + - Lightning Pre-Image: Sharing the Lightning pre-image as proof of payment. + - External / WebHook: The receiver may finalize the flow out-of-band. ### Nostr Event This NIP specifies the use of event kind `21001` with the following structure: -- `content`: NIP-44 encrypted payment details +- `content`: NIP-44 encrypted payment details. - `tags`: - - `p`: Receiver's public key (encoded in hex) - - `relay`: URL of the relay for receiving payment requests - - `offer`: Unique identifier for the payment purpose + - `p`: Receiver's public key (encoded in hex). Example event: + ```json { "id": "", @@ -69,22 +64,22 @@ Example event: ["p", ""], ["e", ""] // used only in response by the receiver to identify the original payment request ], - "content": "", + "content": "", "sig": "" } -``` -The `content` field should contain a stringified JSON object with the following structure: +The `content` field, after NIP-44 decryption, should contain a stringified JSON object with the following structure: -```json { - "offer_id": "", - "payer_data": "" + "offer": "", + "payer_data": "" } ``` ## Client Behavior +### Mandatory + Clients implementing this NIP must: 1. Decode and validate the structure of the `noffer` bech32-encoded static payment code. @@ -92,31 +87,60 @@ Clients implementing this NIP must: 3. Generate and send kind 21001 events as specified in this NIP. 4. Parse the `content` field of received events by decrypting and JSON-parsing the stringified content. 5. Handle potential errors gracefully, providing clear feedback to users. -6. Respect the `relay` tag specified in the static payment code for sending payment request events. +6. Respect the relay URL specified in the static payment code for sending payment request events. + +### Optional Clients implementing this NIP may: 1. Support both this protocol and LNURL for backward compatibility during the transition period. 2. Implement additional features such as multi-recipient payments or integration with other Lightning-related NIPs. +### Prohibited + Clients implementing this NIP MUST NOT: 1. Send unencrypted sensitive information in event content or tags. 2. Ignore or modify any fields from the encoded static payment code. -## Notes +## Error Handling + +To ensure consistent error handling across implementations, this NIP defines the following error responses, similar to other NIPs: + +1. **Invalid Offer**: When the offer ID is invalid or no longer available. +2. **Temporary Failure**: When the receiver is temporarily unable to process the request. +3. **Expired Offer**: When the offer has expired and is no longer valid. +4. **Unsupported Feature**: When the receiver doesn't support a feature requested by the payer. + +Error responses should be sent as kind 21001 events with the following structure in the encrypted content: + +```json +{ + "error": "", + "code": "" +} +``` + +Error codes: + +- 1: Invalid Offer +- 2: Temporary Failure +- 3: Expired Offer +- 4: Unsupported Feature + +Clients MUST handle these error responses gracefully and display appropriate messages to users. -### Transition from LNURL +## Transition from LNURL LNURL services wishing to migrate to Nostr Offer STRings should consider adding a `noffer` tag to their responses. -### Future Considerations +## Future Considerations Future versions of this NIP may consider additional features such as: -1. Multi-recipient payments -2. Integration with other Lightning-related NIPs -3. Extended metadata for more complex payment scenarios +1. Multi-recipient payments. +2. Integration with other Lightning-related NIPs. +3. Extended metadata for more complex payment scenarios. ## Reference Implementation From d43c9e156d7ee3e2494603d9cbfb7808f3b49e92 Mon Sep 17 00:00:00 2001 From: shocknet-justin <34176400+shocknet-justin@users.noreply.github.com> Date: Fri, 30 Aug 2024 16:02:49 -0400 Subject: [PATCH 03/24] nip05 --- 69.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/69.md b/69.md index eb51d93b30..99aaddf03c 100644 --- a/69.md +++ b/69.md @@ -24,6 +24,10 @@ The static payment code is a bech32 (per NIP-19) encoded string prefixed with `n - `1`: The relay URL where the receiving service subscribes to payment requests. - `2`: The offer string. +### NIP-05 Integration + +To support trust-optimized Lightning Addresses, services can add a `nip69` field in the NIP-05 content. This field will provide the offer on name-based lookups. + ### Process Flow 1. **Payer Scans or Clicks the Static Payment Code** @@ -50,7 +54,7 @@ This NIP specifies the use of event kind `21001` with the following structure: - `content`: NIP-44 encrypted payment details. - `tags`: - - `p`: Receiver's public key (encoded in hex). + - `p`: Receiver's public key (hex). Example event: @@ -68,7 +72,7 @@ Example event: "sig": "" } -The `content` field, after NIP-44 decryption, should contain a stringified JSON object with the following structure: +The `content` field, after NIP-44 decryption, should contain an object with the following structure: { "offer": "", @@ -95,6 +99,8 @@ Clients implementing this NIP may: 1. Support both this protocol and LNURL for backward compatibility during the transition period. 2. Implement additional features such as multi-recipient payments or integration with other Lightning-related NIPs. +3. **Use Addressable Events**: Implement addressable events to allow for updates to the recipient key or relay URL associated with the offer. +4. **Attempt Payments by Name**: Use the combination of NIP-05 and NIP-69 to attempt payments by name-based lookups. ### Prohibited @@ -103,6 +109,15 @@ Clients implementing this NIP MUST NOT: 1. Send unencrypted sensitive information in event content or tags. 2. Ignore or modify any fields from the encoded static payment code. +## Service Behavior + +### Optional + +Services implementing this NIP may: + +1. Use an account identifier as a default offer string for spontaneous payments without explicit user setup. +2. **NIP-05 Integration**: Add a `nip69` field in the NIP-05 content to provide the offer on name-based lookups for trust-optimized Lightning Addresses. + ## Error Handling To ensure consistent error handling across implementations, this NIP defines the following error responses, similar to other NIPs: @@ -141,6 +156,7 @@ Future versions of this NIP may consider additional features such as: 1. Multi-recipient payments. 2. Integration with other Lightning-related NIPs. 3. Extended metadata for more complex payment scenarios. +4. **Addressable Events**: In Nostr apps where the offer is used, consider using addressable events to allow for updates to the recipient key or relay URL associated with the offer. ## Reference Implementation From 4f41a9ac48dabdcefc85a3b477c907a35f43f578 Mon Sep 17 00:00:00 2001 From: shocknet-justin <34176400+shocknet-justin@users.noreply.github.com> Date: Fri, 30 Aug 2024 16:06:40 -0400 Subject: [PATCH 04/24] format --- 69.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/69.md b/69.md index 99aaddf03c..cb3e4e8ad6 100644 --- a/69.md +++ b/69.md @@ -71,9 +71,11 @@ Example event: "content": "", "sig": "" } +``` The `content` field, after NIP-44 decryption, should contain an object with the following structure: +```json { "offer": "", "payer_data": "" From 39e8ea58545a14334d544ea9a0e2e7ea0cd16cb2 Mon Sep 17 00:00:00 2001 From: shocknet-justin <34176400+shocknet-justin@users.noreply.github.com> Date: Sun, 1 Sep 2024 10:52:29 -0400 Subject: [PATCH 05/24] amounts --- 69.md | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 10 deletions(-) diff --git a/69.md b/69.md index cb3e4e8ad6..21823e77e9 100644 --- a/69.md +++ b/69.md @@ -1,5 +1,5 @@ -NIP-69: Nostr Offer STRings -=========================== +NIP-69 +====== Nostr Offer STRings ------------------- @@ -12,40 +12,70 @@ This NIP proposes a format for static payment codes in Nostr as a successor to L Reliance on LNURL has led to centralization via custodial solutions due to the legacy baggage of IP4-NAT/Domain/SSL requirements. Nostr's use-cases are already centered around Lightning, whether as a wallet connector, zap receipts, or its overlapping network effects, rendering Nostr as a de facto "3rd layer" for Lightning and a natural successor to LNURL. -When layered over kind 21000, NWC, or other potential Lightning RPCs, this specification enables a seamless user experience similar to legacy LNURL-Pay, without the domain and SSL requirements. Additionally, the signed nature of Nostr communications eliminates the trust requirements inherent in LNURL when a node must outsource the serving of web requests. +When layered over kind 21000, NWC, or other potential Lightning RPCs, this specification enables a seamless user experience similar to legacy LNURL-Pay, without the domain and SSL requirements. Additionally, the signed nature of Nostr communications minimizes the trust requirements inherent in LNURL when a receiving node must outsource the serving of web requests. ## Specification ### Static Payment Code Format -The static payment code is a bech32 (per NIP-19) encoded string prefixed with `noffer`. The encoded string will include the following TLV (Type-Length-Value) items: +The static payment code is a bech32 (per [NIP-19](19.md)) encoded string prefixed with `noffer`. The encoded string will include the following TLV (Type-Length-Value) items: - `0`: The 32 bytes of the receiving service's public key, encoded in hex. - `1`: The relay URL where the receiving service subscribes to payment requests. -- `2`: The offer string. +- `2`: The offer identifying string. +- `3`: The price in sats (optional). +- `4`: A flag indicating the pricing type (optional): + - `0`: Fixed price + - `1`: Variable price + - `2`: Spontaneous payment (payer specifies the amount) + +If neither the price nor the pricing type flag is present, the sender may assume it is a spontaneous payment offer. + +Example static payment code structure: + +``` +noffer1... + 0: + 1: + 2: + 3: (optional, 0 for fixed, 1 for variable, 2 for spontaneous) + 4: (optional) +``` ### NIP-05 Integration -To support trust-optimized Lightning Addresses, services can add a `nip69` field in the NIP-05 content. This field will provide the offer on name-based lookups. +To support trust-optimized Lightning Addresses, services can add a `nip69` field in the NIP-05 content to contain an offer for spontaneous payments. This field will provide the offer on name-based lookups. + +Example NIP-05 content with `nip69` field: +```json +{ + "names": { + "example": "npub1examplepublickey" + }, + "nip69": "noffer1..." +} +``` ### Process Flow 1. **Payer Scans or Clicks the Static Payment Code** 2. **Payer's Wallet Decodes the Payment Code** 3. **Payer's Wallet Sends a Nostr Event to the Specified Relay** - - Addressed to the receiver's public key, containing the identifier string. + - Addressed to the receiver's public key, containing the offer identifying string. - Event Type: Ephemeral Kind 21001 | NIP-44 Encrypted + - **Conditional**: Include the amount in sats the sender wishes to pay if the payment type is spontaneous. - Optional: Include additional payer data. 4. **Receiver Responds with Lightning Invoice** - Generates a Lightning invoice and responds with a Nostr event containing the invoice details. - Event Type: Ephemeral Kind 21001 | NIP-44 Encrypted + - **Content**: `{"bolt11":""}` - Optional: Include additional purchase data. 5. **Payer Pays the Invoice** - Completes the payment by settling the Lightning invoice. 6. **Optional: Receiver Emits Payment Receipt** - This step is out of scope for this NIP, but potential receipt considerations include: - Nostr Event as Receipt: Emitting a public Nostr event as a "zap" receipt for verifiable record-keeping. - - Lightning Pre-Image: Sharing the Lightning pre-image as proof of payment. + - Lightning Pre-Image: The Lightning pre-image is proof of payment. - External / WebHook: The receiver may finalize the flow out-of-band. ### Nostr Event @@ -55,6 +85,7 @@ This NIP specifies the use of event kind `21001` with the following structure: - `content`: NIP-44 encrypted payment details. - `tags`: - `p`: Receiver's public key (hex). + - `e`: Used in response to the requesting event. Example event: @@ -68,7 +99,7 @@ Example event: ["p", ""], ["e", ""] // used only in response by the receiver to identify the original payment request ], - "content": "", + "content": "", "sig": "" } ``` @@ -78,10 +109,28 @@ The `content` field, after NIP-44 decryption, should contain an object with the ```json { "offer": "", + "amount": "", "payer_data": "" } ``` +Example response event with `bolt11` invoice: + +```json +{ + "id": "", + "pubkey": "", + "created_at": 1234567891, + "kind": 21001, + "tags": [ + ["p", ""], + ["e", ""] // original payment request event ID + ], + "content": "\"}>", + "sig": "" +} +``` + ## Client Behavior ### Mandatory @@ -162,4 +211,4 @@ Future versions of this NIP may consider additional features such as: ## Reference Implementation -Lightning.Pub / ShockWallet offers branch \ No newline at end of file +Lightning.Pub / ShockWallet offers branches \ No newline at end of file From f89b090c93141250ffa18ec9266e6cabc8e47ee3 Mon Sep 17 00:00:00 2001 From: shocknet-justin <34176400+shocknet-justin@users.noreply.github.com> Date: Sun, 1 Sep 2024 10:59:15 -0400 Subject: [PATCH 06/24] readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 80b8dcf287..6e34cbbfbe 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos - [NIP-59: Gift Wrap](59.md) - [NIP-64: Chess (PGN)](64.md) - [NIP-65: Relay List Metadata](65.md) +- [NIP-69: Nostr Static Payment Codes](69.md) - [NIP-70: Protected Events](70.md) - [NIP-71: Video Events](71.md) - [NIP-72: Moderated Communities](72.md) @@ -158,6 +159,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos | `10096` | File storage server list | [96](96.md) | | `13194` | Wallet Info | [47](47.md) | | `21000` | Lightning Pub RPC | [Lightning.Pub][lnpub] | +| `21001` | Static Payment Code | [69](69.md) | | `22242` | Client Authentication | [42](42.md) | | `23194` | Wallet Request | [47](47.md) | | `23195` | Wallet Response | [47](47.md) | From ecacbf4d7b34947ef2b43a77c8e55decba8d6915 Mon Sep 17 00:00:00 2001 From: shocknet-justin <34176400+shocknet-justin@users.noreply.github.com> Date: Sun, 1 Sep 2024 11:08:02 -0400 Subject: [PATCH 07/24] range error --- 69.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/69.md b/69.md index 21823e77e9..c26b19070d 100644 --- a/69.md +++ b/69.md @@ -177,13 +177,18 @@ To ensure consistent error handling across implementations, this NIP defines the 2. **Temporary Failure**: When the receiver is temporarily unable to process the request. 3. **Expired Offer**: When the offer has expired and is no longer valid. 4. **Unsupported Feature**: When the receiver doesn't support a feature requested by the payer. +5. **Invalid Amount**: When the amount specified is too big or too small, providing the acceptable range. Error responses should be sent as kind 21001 events with the following structure in the encrypted content: ```json { "error": "", - "code": "" + "code": "", + "range": { + "min": "", + "max": "" + } } ``` @@ -193,6 +198,7 @@ Error codes: - 2: Temporary Failure - 3: Expired Offer - 4: Unsupported Feature +- 5: Invalid Amount Clients MUST handle these error responses gracefully and display appropriate messages to users. From 75069ab45000946d49cd8ac56e26930b39ac9c3a Mon Sep 17 00:00:00 2001 From: shocknet-justin <34176400+shocknet-justin@users.noreply.github.com> Date: Mon, 2 Sep 2024 10:43:51 -0400 Subject: [PATCH 08/24] better nip05 --- 69.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/69.md b/69.md index c26b19070d..49c15cfeee 100644 --- a/69.md +++ b/69.md @@ -47,12 +47,26 @@ noffer1... To support trust-optimized Lightning Addresses, services can add a `nip69` field in the NIP-05 content to contain an offer for spontaneous payments. This field will provide the offer on name-based lookups. Example NIP-05 content with `nip69` field: +```json +{ + "pubkey": "hex_pub", + "kind": 0, + "content": "{\"name\": \"bob\", \"nip05\": \"bob@example.com\", \"nip69\": \"noffer1...\"}" + ... +} +``` + +Example NIP-05 Service Response with Offers + + ```json { "names": { - "example": "npub1examplepublickey" + "bob": "hex_pub" }, - "nip69": "noffer1..." + "nip69": { + "hex_pub": "noffer1..." + } } ``` From 0cb9a86e7a3b919324334fc725955477870d5a3b Mon Sep 17 00:00:00 2001 From: shocknet-justin <34176400+shocknet-justin@users.noreply.github.com> Date: Mon, 2 Sep 2024 11:28:36 -0400 Subject: [PATCH 09/24] name fix --- 69.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/69.md b/69.md index 49c15cfeee..278bfcd278 100644 --- a/69.md +++ b/69.md @@ -65,7 +65,7 @@ Example NIP-05 Service Response with Offers "bob": "hex_pub" }, "nip69": { - "hex_pub": "noffer1..." + "bob": "noffer1..." } } ``` From 4693f53e92f542661302f7e0dd55d7c4f2b3556c Mon Sep 17 00:00:00 2001 From: shocknet-justin <34176400+shocknet-justin@users.noreply.github.com> Date: Mon, 2 Sep 2024 13:53:30 -0400 Subject: [PATCH 10/24] better tlv order --- 69.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/69.md b/69.md index 278bfcd278..7f6a940ddd 100644 --- a/69.md +++ b/69.md @@ -23,11 +23,11 @@ The static payment code is a bech32 (per [NIP-19](19.md)) encoded string prefixe - `0`: The 32 bytes of the receiving service's public key, encoded in hex. - `1`: The relay URL where the receiving service subscribes to payment requests. - `2`: The offer identifying string. -- `3`: The price in sats (optional). -- `4`: A flag indicating the pricing type (optional): +- `3`: A flag indicating the pricing type: - `0`: Fixed price - `1`: Variable price - `2`: Spontaneous payment (payer specifies the amount) +- `4`: The price in sats (optional). If neither the price nor the pricing type flag is present, the sender may assume it is a spontaneous payment offer. From 993b3a841c4a708b6a31e7b239c5f1d799691ee4 Mon Sep 17 00:00:00 2001 From: shocknet-justin <34176400+shocknet-justin@users.noreply.github.com> Date: Tue, 3 Sep 2024 12:51:33 -0400 Subject: [PATCH 11/24] better other nips descriptions --- 69.md | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/69.md b/69.md index 7f6a940ddd..43bd696057 100644 --- a/69.md +++ b/69.md @@ -27,7 +27,7 @@ The static payment code is a bech32 (per [NIP-19](19.md)) encoded string prefixe - `0`: Fixed price - `1`: Variable price - `2`: Spontaneous payment (payer specifies the amount) -- `4`: The price in sats (optional). +- `4`: The price in sats (optional for display purposes). If neither the price nor the pricing type flag is present, the sender may assume it is a spontaneous payment offer. @@ -42,11 +42,11 @@ noffer1... 4: (optional) ``` -### NIP-05 Integration +## Integration with other NIPs -To support trust-optimized Lightning Addresses, services can add a `nip69` field in the NIP-05 content to contain an offer for spontaneous payments. This field will provide the offer on name-based lookups. +### NIP-01 User Metadata -Example NIP-05 content with `nip69` field: +Example user metadata content with `nip69` field: ```json { "pubkey": "hex_pub", @@ -56,6 +56,10 @@ Example NIP-05 content with `nip69` field: } ``` +### NIP-05 "Lightning Addresses" + +To support trust-minimized Lightning Addresses, services can add a `nip69` field in the NIP-05 content to contain an offer for spontaneous payments. This field will provide the offer on name-based lookups. + Example NIP-05 Service Response with Offers @@ -70,7 +74,33 @@ Example NIP-05 Service Response with Offers } ``` -### Process Flow +### NIP-57 Zaps + +Instead of using the LNURL-pay callback, the "zap" flow can be initiated as content payload to an Offer: + +1. The client creates a kind 9734 zap request event as specified in NIP-57. +2. Instead of sending this to an LNURL-pay endpoint, the client sends it as the `zap` part of the encrypted content in a NIP-69 payment request. +3. The receiver processes the NIP-69 payment request, decrypts the content, extracts the kind 9734 event, and uses it to generate the invoice. +4. The receiver responds with the invoice as specified in NIP-69. +5. Once paid, the receiver generates and publishes the kind 9735 zap receipt as specified in NIP-57. + +Example NIP-57 zap request: + +```json +{ + "id": "", + "pubkey": "", + "created_at": 1234567890, + "kind": 21001, + "tags": [ + ["p", ""] + ], + "content": "\",\"zap\":}>", + "sig": "" +} +``` + +## General Process Flow 1. **Payer Scans or Clicks the Static Payment Code** 2. **Payer's Wallet Decodes the Payment Code** @@ -231,4 +261,4 @@ Future versions of this NIP may consider additional features such as: ## Reference Implementation -Lightning.Pub / ShockWallet offers branches \ No newline at end of file +Lightning.Pub / ShockWallet noffer branches \ No newline at end of file From c6a3a29adf891b0950b5e87516ae4e1d258c8c0f Mon Sep 17 00:00:00 2001 From: shocknet-justin <34176400+shocknet-justin@users.noreply.github.com> Date: Tue, 3 Sep 2024 13:44:01 -0400 Subject: [PATCH 12/24] zap signaling --- 69.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/69.md b/69.md index 43bd696057..8a3f1f22cc 100644 --- a/69.md +++ b/69.md @@ -95,11 +95,13 @@ Example NIP-57 zap request: "tags": [ ["p", ""] ], - "content": "\",\"zap\":}>", + "content": "\",\"zap\":}>", "sig": "" } ``` +There is no requirement on the service to acknowledge the zap requset content, given that spontaneous payments are default behavior. Service implementations and clients should however consider offer identifiers, where `startsWith("zap")`, to indicate that the service will honor zap requests. A service should not error if no zap request is attached to a zap named offer, rather just treat it any other spontaneous payment. + ## General Process Flow 1. **Payer Scans or Clicks the Static Payment Code** From c8ca0b5c455665d27c73a1fc7af7d7cdb41df18e Mon Sep 17 00:00:00 2001 From: shocknet-justin <34176400+shocknet-justin@users.noreply.github.com> Date: Tue, 3 Sep 2024 13:51:58 -0400 Subject: [PATCH 13/24] link handling --- 69.md | 1 + 1 file changed, 1 insertion(+) diff --git a/69.md b/69.md index 8a3f1f22cc..451957d46f 100644 --- a/69.md +++ b/69.md @@ -198,6 +198,7 @@ Clients implementing this NIP may: 2. Implement additional features such as multi-recipient payments or integration with other Lightning-related NIPs. 3. **Use Addressable Events**: Implement addressable events to allow for updates to the recipient key or relay URL associated with the offer. 4. **Attempt Payments by Name**: Use the combination of NIP-05 and NIP-69 to attempt payments by name-based lookups. +5. Parse `noffer` strings with existing `lightning:` link handlers just as they would invoices or legacy LNURL strings ### Prohibited From 62c86a7a9b763b4f83a28853643795943684573a Mon Sep 17 00:00:00 2001 From: shocknet-justin <34176400+shocknet-justin@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:06:21 -0400 Subject: [PATCH 14/24] multiple payees --- 69.md | 1 + 1 file changed, 1 insertion(+) diff --git a/69.md b/69.md index 451957d46f..09fd713eeb 100644 --- a/69.md +++ b/69.md @@ -196,6 +196,7 @@ Clients implementing this NIP may: 1. Support both this protocol and LNURL for backward compatibility during the transition period. 2. Implement additional features such as multi-recipient payments or integration with other Lightning-related NIPs. + - For offers that list multiple recipient keys, clients may "for each" over the recipient keys to pay multiple recipients. 3. **Use Addressable Events**: Implement addressable events to allow for updates to the recipient key or relay URL associated with the offer. 4. **Attempt Payments by Name**: Use the combination of NIP-05 and NIP-69 to attempt payments by name-based lookups. 5. Parse `noffer` strings with existing `lightning:` link handlers just as they would invoices or legacy LNURL strings From 21904814516798aa2a340e77c3ea29747a3a5a76 Mon Sep 17 00:00:00 2001 From: shocknet-justin <34176400+shocknet-justin@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:45:46 -0400 Subject: [PATCH 15/24] wordsmith --- 69.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/69.md b/69.md index 09fd713eeb..cfe5554b4f 100644 --- a/69.md +++ b/69.md @@ -100,7 +100,7 @@ Example NIP-57 zap request: } ``` -There is no requirement on the service to acknowledge the zap requset content, given that spontaneous payments are default behavior. Service implementations and clients should however consider offer identifiers, where `startsWith("zap")`, to indicate that the service will honor zap requests. A service should not error if no zap request is attached to a zap named offer, rather just treat it any other spontaneous payment. +There is no requirement on the service to acknowledge the zap request content, given that spontaneous payments are default behavior. Service implementations and clients should however consider offer identifiers, where `startsWith("zap")`, to indicate that the service will honor zap requests. A service should not error if no zap request is attached to a zap named offer, rather just treat it any other spontaneous payment. ## General Process Flow @@ -196,10 +196,10 @@ Clients implementing this NIP may: 1. Support both this protocol and LNURL for backward compatibility during the transition period. 2. Implement additional features such as multi-recipient payments or integration with other Lightning-related NIPs. - - For offers that list multiple recipient keys, clients may "for each" over the recipient keys to pay multiple recipients. -3. **Use Addressable Events**: Implement addressable events to allow for updates to the recipient key or relay URL associated with the offer. + - Ex: If an offer lists multiple recipient keys, a client might "for each" over them to pay multiple recipients. +3. Use Addressable Events: Nest offers in addressable event for marketplace products where the offer may change more frequently than the product due to price, receiving key, or relay URL associated with the offer. 4. **Attempt Payments by Name**: Use the combination of NIP-05 and NIP-69 to attempt payments by name-based lookups. -5. Parse `noffer` strings with existing `lightning:` link handlers just as they would invoices or legacy LNURL strings +5. Prefix and Parse `noffer` strings with existing `lightning:` link handlers, just as they would invoices or legacy LNURL strings. ### Prohibited @@ -256,12 +256,12 @@ LNURL services wishing to migrate to Nostr Offer STRings should consider adding ## Future Considerations -Future versions of this NIP may consider additional features such as: +Future versions of this NIP may consider standardizing additional features such as: -1. Multi-recipient payments. +1. Multi-recipient payments with weighting. 2. Integration with other Lightning-related NIPs. 3. Extended metadata for more complex payment scenarios. -4. **Addressable Events**: In Nostr apps where the offer is used, consider using addressable events to allow for updates to the recipient key or relay URL associated with the offer. +4. Best practices for use with Addressable Events. ## Reference Implementation From d1f78e891d8d022041f6d289c9cbd86754822b28 Mon Sep 17 00:00:00 2001 From: shocknet-justin <34176400+shocknet-justin@users.noreply.github.com> Date: Tue, 3 Sep 2024 16:34:05 -0400 Subject: [PATCH 16/24] words --- 69.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/69.md b/69.md index cfe5554b4f..3491930e9a 100644 --- a/69.md +++ b/69.md @@ -52,7 +52,7 @@ Example user metadata content with `nip69` field: "pubkey": "hex_pub", "kind": 0, "content": "{\"name\": \"bob\", \"nip05\": \"bob@example.com\", \"nip69\": \"noffer1...\"}" - ... + // ... } ``` @@ -100,7 +100,7 @@ Example NIP-57 zap request: } ``` -There is no requirement on the service to acknowledge the zap request content, given that spontaneous payments are default behavior. Service implementations and clients should however consider offer identifiers, where `startsWith("zap")`, to indicate that the service will honor zap requests. A service should not error if no zap request is attached to a zap named offer, rather just treat it any other spontaneous payment. +There is no inherent requirement on the service to acknowledge zap requests, since spontaneous payments are default behavior. However, both Clients and Service implementations SHOULD consider offer identifiers, where `startsWith("zap")`, indication that the service will honor zap requests for that offer. A service should not error if no zap request was included by the sender on a zap indicated offer, the service should treat it as any other spontaneous payment. ## General Process Flow @@ -197,9 +197,9 @@ Clients implementing this NIP may: 1. Support both this protocol and LNURL for backward compatibility during the transition period. 2. Implement additional features such as multi-recipient payments or integration with other Lightning-related NIPs. - Ex: If an offer lists multiple recipient keys, a client might "for each" over them to pay multiple recipients. -3. Use Addressable Events: Nest offers in addressable event for marketplace products where the offer may change more frequently than the product due to price, receiving key, or relay URL associated with the offer. -4. **Attempt Payments by Name**: Use the combination of NIP-05 and NIP-69 to attempt payments by name-based lookups. -5. Prefix and Parse `noffer` strings with existing `lightning:` link handlers, just as they would invoices or legacy LNURL strings. +3. Use Addressable Events to nest offers in marketplace products etc where the offer variables might change more frequently than the product or service associated with it. +4. **Attempt Payments by Name**: Wallets might first attempt the combination of NIP-05 and NIP-69 before falling back to LNURL on name-based lookups. +5. Prefix and parse `noffer` strings with existing `lightning:` link handlers, just as they would invoices or legacy LNURL strings. ### Prohibited @@ -215,7 +215,7 @@ Clients implementing this NIP MUST NOT: Services implementing this NIP may: 1. Use an account identifier as a default offer string for spontaneous payments without explicit user setup. -2. **NIP-05 Integration**: Add a `nip69` field in the NIP-05 content to provide the offer on name-based lookups for trust-optimized Lightning Addresses. +2. **NIP-05 Integration**: Add a `nip69` field in the NIP-05 content to provide the offer on name-based lookups for trust-minimized Lightning Addresses. ## Error Handling @@ -252,7 +252,7 @@ Clients MUST handle these error responses gracefully and display appropriate mes ## Transition from LNURL -LNURL services wishing to migrate to Nostr Offer STRings should consider adding a `noffer` tag to their responses. +LNURL services wishing to signal the upgrade should add `nip69: ` to the inital GET response described in [LUD-06](https://github.com/lnurl/luds/blob/luds/06.md). Clients seeing this new value on a LNURL server should automatically upgrade the payment flow that was instantiated by the user for that address. ## Future Considerations From cc4b6650e7ec1a7d586e42ceadf24ca8176f31d3 Mon Sep 17 00:00:00 2001 From: shocknet-justin <34176400+shocknet-justin@users.noreply.github.com> Date: Sat, 7 Sep 2024 18:19:25 -0400 Subject: [PATCH 17/24] demo --- 69.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/69.md b/69.md index 3491930e9a..a47dfe051a 100644 --- a/69.md +++ b/69.md @@ -4,7 +4,7 @@ NIP-69 Nostr Offer STRings ------------------- -`wip` `optional` +`rfc` `optional` This NIP proposes a format for static payment codes in Nostr as a successor to LNURL-Pay, enabling users to initiate Lightning Network payments by scanning or clicking a string. @@ -124,7 +124,7 @@ There is no inherent requirement on the service to acknowledge zap requests, sin - Lightning Pre-Image: The Lightning pre-image is proof of payment. - External / WebHook: The receiver may finalize the flow out-of-band. -### Nostr Event +### Nostr Events This NIP specifies the use of event kind `21001` with the following structure: @@ -133,7 +133,7 @@ This NIP specifies the use of event kind `21001` with the following structure: - `p`: Receiver's public key (hex). - `e`: Used in response to the requesting event. -Example event: +Example request event: ```json { @@ -142,8 +142,7 @@ Example event: "created_at": 1234567890, "kind": 21001, "tags": [ - ["p", ""], - ["e", ""] // used only in response by the receiver to identify the original payment request + ["p", ""] ], "content": "", "sig": "" @@ -233,9 +232,9 @@ Error responses should be sent as kind 21001 events with the following structure { "error": "", "code": "", - "range": { - "min": "", - "max": "" + "range": { //sats + "min": 10, + "max": 10000000 } } ``` @@ -263,6 +262,7 @@ Future versions of this NIP may consider standardizing additional features such 3. Extended metadata for more complex payment scenarios. 4. Best practices for use with Addressable Events. -## Reference Implementation +## Reference Implementations -Lightning.Pub / ShockWallet noffer branches \ No newline at end of file +[Lightning.Pub](https://github.com/shocknet/Lightning.Pub/pull/727) / [ShockWallet](https://github.com/shocknet/wallet2/pull/268) +[demo.nip69.dev](https://demo.nip69.dev) \ No newline at end of file From 7b15e7dfed219b4d967ff2294b8b2e8da816e18a Mon Sep 17 00:00:00 2001 From: shocknet-justin <34176400+shocknet-justin@users.noreply.github.com> Date: Sun, 8 Sep 2024 11:09:06 -0400 Subject: [PATCH 18/24] error payloads --- 69.md | 51 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/69.md b/69.md index a47dfe051a..4676e831d9 100644 --- a/69.md +++ b/69.md @@ -226,12 +226,47 @@ To ensure consistent error handling across implementations, this NIP defines the 4. **Unsupported Feature**: When the receiver doesn't support a feature requested by the payer. 5. **Invalid Amount**: When the amount specified is too big or too small, providing the acceptable range. +Error codes: + +- 1: Invalid Offer +- 2: Temporary Failure +- 3: Expired Offer +- 4: Unsupported Feature +- 5: Invalid Amount + +Clients MUST handle these error responses gracefully and display appropriate messages to users. + +### Error Response Payloads + Error responses should be sent as kind 21001 events with the following structure in the encrypted content: ```json { "error": "", - "code": "", + "code": "" + // Additional fields optionally included depending on the error type +} +``` +### Expected Payloads + +3. **Expired Offer** +- **Code**: 3 +- **Payload**: +```json +{ + "error": "Expired Offer", + "code": 3, + "latest": "" +} +``` + +5. **Invalid Amount** +- **Code**: 5 +- **Payload**: +```json +{ + "error": "Invalid Amount", + "code": 5, "range": { //sats "min": 10, "max": 10000000 @@ -239,16 +274,6 @@ Error responses should be sent as kind 21001 events with the following structure } ``` -Error codes: - -- 1: Invalid Offer -- 2: Temporary Failure -- 3: Expired Offer -- 4: Unsupported Feature -- 5: Invalid Amount - -Clients MUST handle these error responses gracefully and display appropriate messages to users. - ## Transition from LNURL LNURL services wishing to signal the upgrade should add `nip69: ` to the inital GET response described in [LUD-06](https://github.com/lnurl/luds/blob/luds/06.md). Clients seeing this new value on a LNURL server should automatically upgrade the payment flow that was instantiated by the user for that address. @@ -264,5 +289,5 @@ Future versions of this NIP may consider standardizing additional features such ## Reference Implementations -[Lightning.Pub](https://github.com/shocknet/Lightning.Pub/pull/727) / [ShockWallet](https://github.com/shocknet/wallet2/pull/268) -[demo.nip69.dev](https://demo.nip69.dev) \ No newline at end of file +- [Lightning.Pub](https://github.com/shocknet/Lightning.Pub/pull/727) / [ShockWallet](https://github.com/shocknet/wallet2/pull/268) +- [demo.nip69.dev](https://demo.nip69.dev) \ No newline at end of file From 45227429ed3d0d6aa1246aab6b0e846c7ee12ec3 Mon Sep 17 00:00:00 2001 From: shocknet-justin <34176400+shocknet-justin@users.noreply.github.com> Date: Sun, 8 Sep 2024 14:14:32 -0400 Subject: [PATCH 19/24] clarify types --- 69.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/69.md b/69.md index 4676e831d9..97827c7d71 100644 --- a/69.md +++ b/69.md @@ -24,9 +24,9 @@ The static payment code is a bech32 (per [NIP-19](19.md)) encoded string prefixe - `1`: The relay URL where the receiving service subscribes to payment requests. - `2`: The offer identifying string. - `3`: A flag indicating the pricing type: - - `0`: Fixed price - - `1`: Variable price - - `2`: Spontaneous payment (payer specifies the amount) + - `0`: Fixed price (Price stated in 4 will not change) + - `1`: Variable price (Price must be calculated and will be reflected in the invoice) + - `2`: Spontaneous payment (Payer specifies the amount in request payload) - `4`: The price in sats (optional for display purposes). If neither the price nor the pricing type flag is present, the sender may assume it is a spontaneous payment offer. From 05cce5f2e804851334640f1c52902dfc3c385b2b Mon Sep 17 00:00:00 2001 From: shocknet-justin <34176400+shocknet-justin@users.noreply.github.com> Date: Sun, 8 Sep 2024 14:37:17 -0400 Subject: [PATCH 20/24] stringified --- 69.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/69.md b/69.md index 97827c7d71..43934427bd 100644 --- a/69.md +++ b/69.md @@ -149,7 +149,7 @@ Example request event: } ``` -The `content` field, after NIP-44 decryption, should contain an object with the following structure: +The `content` field, after NIP-44 decryption, should contain stringified JSON with the following structure: ```json { From 8c5cf20b1f1e361e2a92dc45a8b360f99615a73f Mon Sep 17 00:00:00 2001 From: shocknet-justin <34176400+shocknet-justin@users.noreply.github.com> Date: Sun, 8 Sep 2024 15:05:19 -0400 Subject: [PATCH 21/24] fiat reference --- 69.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/69.md b/69.md index 43934427bd..efc742b6fb 100644 --- a/69.md +++ b/69.md @@ -25,7 +25,7 @@ The static payment code is a bech32 (per [NIP-19](19.md)) encoded string prefixe - `2`: The offer identifying string. - `3`: A flag indicating the pricing type: - `0`: Fixed price (Price stated in 4 will not change) - - `1`: Variable price (Price must be calculated and will be reflected in the invoice) + - `1`: Variable price (Price must be calculated and will be reflected in the invoice, useful for products priced in fiat) - `2`: Spontaneous payment (Payer specifies the amount in request payload) - `4`: The price in sats (optional for display purposes). From 4c3879b998cef69ea056e15f6d324ef1d6be6499 Mon Sep 17 00:00:00 2001 From: shocknet-justin <34176400+shocknet-justin@users.noreply.github.com> Date: Tue, 10 Sep 2024 10:08:52 -0400 Subject: [PATCH 22/24] bridgelet --- 69.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/69.md b/69.md index efc742b6fb..ee2812c5ab 100644 --- a/69.md +++ b/69.md @@ -290,4 +290,5 @@ Future versions of this NIP may consider standardizing additional features such ## Reference Implementations - [Lightning.Pub](https://github.com/shocknet/Lightning.Pub/pull/727) / [ShockWallet](https://github.com/shocknet/wallet2/pull/268) -- [demo.nip69.dev](https://demo.nip69.dev) \ No newline at end of file +- [demo.nip69.dev](https://demo.nip69.dev) +- [Bridgelet](https://github.com/shocknet/bridgelet) \ No newline at end of file From b97779106e6acf3d1b4fdea0824f94e8d0dab3be Mon Sep 17 00:00:00 2001 From: shocknet-justin Date: Tue, 8 Oct 2024 11:02:46 -0400 Subject: [PATCH 23/24] nostr-tools ref --- 69.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/69.md b/69.md index ee2812c5ab..70224b6586 100644 --- a/69.md +++ b/69.md @@ -289,6 +289,8 @@ Future versions of this NIP may consider standardizing additional features such ## Reference Implementations -- [Lightning.Pub](https://github.com/shocknet/Lightning.Pub/pull/727) / [ShockWallet](https://github.com/shocknet/wallet2/pull/268) -- [demo.nip69.dev](https://demo.nip69.dev) -- [Bridgelet](https://github.com/shocknet/bridgelet) \ No newline at end of file +- Wallet Service: [Lightning.Pub](https://github.com/shocknet/Lightning.Pub/pull/727) +- Wallet Client: [ShockWallet](https://github.com/shocknet/wallet2/pull/268) +- Demo Client: [demo.nip69.dev](https://demo.nip69.dev) +- Lightning Address Bridge:[Bridgelet](https://github.com/shocknet/bridgelet) +- Nostr-Tools (temp fork): [nostr-tools](https://github.com/shocknet/nostr-tools) \ No newline at end of file From eca648de99d896d33207bf3e3c7b84ce988e79be Mon Sep 17 00:00:00 2001 From: shocknet-justin Date: Tue, 8 Oct 2024 11:55:06 -0400 Subject: [PATCH 24/24] typo --- 69.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/69.md b/69.md index 70224b6586..a96ce9c057 100644 --- a/69.md +++ b/69.md @@ -292,5 +292,5 @@ Future versions of this NIP may consider standardizing additional features such - Wallet Service: [Lightning.Pub](https://github.com/shocknet/Lightning.Pub/pull/727) - Wallet Client: [ShockWallet](https://github.com/shocknet/wallet2/pull/268) - Demo Client: [demo.nip69.dev](https://demo.nip69.dev) -- Lightning Address Bridge:[Bridgelet](https://github.com/shocknet/bridgelet) +- Lightning Address Bridge: [Bridgelet](https://github.com/shocknet/bridgelet) - Nostr-Tools (temp fork): [nostr-tools](https://github.com/shocknet/nostr-tools) \ No newline at end of file