upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/47.md
diff options
context:
space:
mode:
authorVitor Pamplona <vitor@vitorpamplona.com>2024-12-19 10:15:46 -0500
committerGitHub <noreply@github.com>2024-12-19 10:15:46 -0500
commitf7d97f3f40dc6677e6f996ffff431142ffe05810 (patch)
tree2eaa8c8628cc9a4b05811ed3869e21221fd85307 /47.md
parentd5b77b6d7348061cd0f16adc35e4d02a3a0b7380 (diff)
parent561059ff85c171b87a12b8381b724b4afc569a97 (diff)
Merge branch 'master' into draft-event
Diffstat (limited to '47.md')
-rw-r--r--47.md142
1 files changed, 122 insertions, 20 deletions
diff --git a/47.md b/47.md
index 983d2c9..d1030a4 100644
--- a/47.md
+++ b/47.md
@@ -8,37 +8,47 @@ Nostr Wallet Connect
8 8
9## Rationale 9## Rationale
10 10
11This NIP describes a way for clients to access a remote Lightning wallet through a standardized protocol. Custodians may implement this, or the user may run a bridge that bridges their wallet/node and the Nostr Wallet Connect protocol. 11This NIP describes a way for clients to access a remote lightning wallet through a standardized protocol. Custodians may implement this, or the user may run a bridge that bridges their wallet/node and the Nostr Wallet Connect protocol.
12 12
13## Terms 13## Terms
14 14
15* **client**: Nostr app on any platform that wants to pay Lightning invoices. 15* **client**: Nostr app on any platform that wants to interact with a lightning wallet.
16* **user**: The person using the **client**, and want's to connect their wallet app to their **client**. 16* **user**: The person using the **client**, and wants to connect their wallet to their **client**.
17* **wallet service**: Nostr app that typically runs on an always-on computer (eg. in the cloud or on a Raspberry Pi). This app has access to the APIs of the wallets it serves. 17* **wallet service**: Nostr app that typically runs on an always-on computer (eg. in the cloud or on a Raspberry Pi). This app has access to the APIs of the wallets it serves.
18 18
19## Theory of Operation 19## Theory of Operation
20 1. **Users** who wish to use this NIP to send lightning payments to other nostr users must first acquire a special "connection" URI from their NIP-47 compliant wallet application. The wallet application may provide this URI using a QR screen, or a pasteable string, or some other means. 20 1. **Users** who wish to use this NIP to allow **client(s)** to interact with their wallet must first acquire a special "connection" URI from their NIP-47 compliant wallet application. The wallet application may provide this URI using a QR screen, or a pasteable string, or some other means.
21 21
22 2. The **user** should then copy this URI into their **client(s)** by pasting, or scanning the QR, etc. The **client(s)** should save this URI and use it later whenever the **user** makes a payment. The **client** should then request an `info` (13194) event from the relay(s) specified in the URI. The **wallet service** will have sent that event to those relays earlier, and the relays will hold it as a replaceable event. 22 2. The **user** should then copy this URI into their **client(s)** by pasting, or scanning the QR, etc. The **client(s)** should save this URI and use it later whenever the **user** (or the **client** on the user's behalf) wants to interact with the wallet. The **client** should then request an `info` (13194) event from the relay(s) specified in the URI. The **wallet service** will have sent that event to those relays earlier, and the relays will hold it as a replaceable event.
23 23
24 3. When the **user** initiates a payment their nostr **client** create a `pay_invoice` request, encrypts it using a token from the URI, and sends it (kind 23194) to the relay(s) specified in the connection URI. The **wallet service** will be listening on those relays and will decrypt the request and then contact the **user's** wallet application to send the payment. The **wallet service** will know how to talk to the wallet application because the connection URI specified relay(s) that have access to the wallet app API. 24 3. When the **user** initiates a payment their nostr **client** create a `pay_invoice` request, encrypts it using a token from the URI, and sends it (kind 23194) to the relay(s) specified in the connection URI. The **wallet service** will be listening on those relays and will decrypt the request and then contact the **user's** wallet application to send the payment. The **wallet service** will know how to talk to the wallet application because the connection URI specified relay(s) that have access to the wallet app API.
25 25
26 4. Once the payment is complete the **wallet service** will send an encrypted `response` (kind 23195) to the **user** over the relay(s) in the URI. 26 4. Once the payment is complete the **wallet service** will send an encrypted `response` (kind 23195) to the **user** over the relay(s) in the URI.
27
28 5. The **wallet service** may send encrypted notifications (kind 23196) of wallet events (such as a received payment) to the **client**.
27 29
28## Events 30## Events
29 31
30There are three event kinds: 32There are four event kinds:
31- `NIP-47 info event`: 13194 33- `NIP-47 info event`: 13194
32- `NIP-47 request`: 23194 34- `NIP-47 request`: 23194
33- `NIP-47 response`: 23195 35- `NIP-47 response`: 23195
36- `NIP-47 notification event`: 23196
37
38### Info Event
39
40The info event should be a replaceable event that is published by the **wallet service** on the relay to indicate which capabilities it supports.
41
42The content should be a plaintext string with the supported capabilities space-separated, eg. `pay_invoice get_balance notifications`.
34 43
35The info event should be a replaceable event that is published by the **wallet service** on the relay to indicate which commands it supports. The content should be 44If the **wallet service** supports notifications, the info event SHOULD contain a `notifications` tag with the supported notification types space-separated, eg. `payment_received payment_sent`.
36a plaintext string with the supported commands, space-separated, eg. `pay_invoice get_balance`. Only the `pay_invoice` command is described in this NIP, but other commands might be defined in different NIPs. 45
46### Request and Response Events
37 47
38Both the request and response events SHOULD contain one `p` tag, containing the public key of the **wallet service** if this is a request, and the public key of the **user** if this is a response. The response event SHOULD contain an `e` tag with the id of the request event it is responding to. 48Both the request and response events SHOULD contain one `p` tag, containing the public key of the **wallet service** if this is a request, and the public key of the **user** if this is a response. The response event SHOULD contain an `e` tag with the id of the request event it is responding to.
39Optionally, a request can have an `expiration` tag that has a unix timestamp in seconds. If the request is received after this timestamp, it should be ignored. 49Optionally, a request can have an `expiration` tag that has a unix timestamp in seconds. If the request is received after this timestamp, it should be ignored.
40 50
41The content of requests and responses is encrypted with [NIP04](https://github.com/nostr-protocol/nips/blob/master/04.md), and is a JSON-RPCish object with a semi-fixed structure: 51The content of requests and responses is encrypted with [NIP04](04.md), and is a JSON-RPCish object with a semi-fixed structure:
42 52
43Request: 53Request:
44```jsonc 54```jsonc
@@ -68,6 +78,22 @@ The `result_type` field MUST contain the name of the method that this event is r
68The `error` field MUST contain a `message` field with a human readable error message and a `code` field with the error code if the command was not successful. 78The `error` field MUST contain a `message` field with a human readable error message and a `code` field with the error code if the command was not successful.
69If the command was successful, the `error` field must be null. 79If the command was successful, the `error` field must be null.
70 80
81### Notification Events
82
83The notification event SHOULD contain one `p` tag, the public key of the **user**.
84
85The content of notifications is encrypted with [NIP04](https://github.com/nostr-protocol/nips/blob/master/04.md), and is a JSON-RPCish object with a semi-fixed structure:
86
87```jsonc
88{
89 "notification_type": "payment_received", //indicates the structure of the notification field
90 "notification": {
91 "payment_hash": "0123456789abcdef..." // notification-related data
92 }
93}
94```
95
96
71### Error codes 97### Error codes
72- `RATE_LIMITED`: The client is sending commands too fast. It should retry in a few seconds. 98- `RATE_LIMITED`: The client is sending commands too fast. It should retry in a few seconds.
73- `NOT_IMPLEMENTED`: The command is not known or is intentionally not implemented. 99- `NOT_IMPLEMENTED`: The command is not known or is intentionally not implemented.
@@ -120,7 +146,8 @@ Response:
120{ 146{
121 "result_type": "pay_invoice", 147 "result_type": "pay_invoice",
122 "result": { 148 "result": {
123 "preimage": "0123456789abcdef..." // preimage of the payment 149 "preimage": "0123456789abcdef...", // preimage of the payment
150 "fees_paid": 123, // value in msats, optional
124 } 151 }
125} 152}
126``` 153```
@@ -148,14 +175,15 @@ Request:
148Response: 175Response:
149 176
150For every invoice in the request, a separate response event is sent. To differentiate between the responses, each 177For every invoice in the request, a separate response event is sent. To differentiate between the responses, each
151response event contains an `d` tag with the id of the invoice it is responding to, if no id was given, then the 178response event contains a `d` tag with the id of the invoice it is responding to, if no id was given, then the
152payment hash of the invoice should be used. 179payment hash of the invoice should be used.
153 180
154```jsonc 181```jsonc
155{ 182{
156 "result_type": "multi_pay_invoice", 183 "result_type": "multi_pay_invoice",
157 "result": { 184 "result": {
158 "preimage": "0123456789abcdef..." // preimage of the payment 185 "preimage": "0123456789abcdef...", // preimage of the payment
186 "fees_paid": 123, // value in msats, optional
159 } 187 }
160} 188}
161``` 189```
@@ -173,7 +201,7 @@ Request:
173 "amount": 123, // invoice amount in msats, required 201 "amount": 123, // invoice amount in msats, required
174 "pubkey": "03...", // payee pubkey, required 202 "pubkey": "03...", // payee pubkey, required
175 "preimage": "0123456789abcdef...", // preimage of the payment, optional 203 "preimage": "0123456789abcdef...", // preimage of the payment, optional
176 "tlv_records: [ // tlv records, optional 204 "tlv_records": [ // tlv records, optional
177 { 205 {
178 "type": 5482373484, // tlv type 206 "type": 5482373484, // tlv type
179 "value": "0123456789abcdef" // hex encoded tlv value 207 "value": "0123456789abcdef" // hex encoded tlv value
@@ -189,6 +217,7 @@ Response:
189 "result_type": "pay_keysend", 217 "result_type": "pay_keysend",
190 "result": { 218 "result": {
191 "preimage": "0123456789abcdef...", // preimage of the payment 219 "preimage": "0123456789abcdef...", // preimage of the payment
220 "fees_paid": 123, // value in msats, optional
192 } 221 }
193} 222}
194``` 223```
@@ -208,7 +237,7 @@ Request:
208 "method": "multi_pay_keysend", 237 "method": "multi_pay_keysend",
209 "params": { 238 "params": {
210 "keysends": [ 239 "keysends": [
211 {"id": "4c5b24a351", pubkey": "03...", "amount": 123}, 240 {"id": "4c5b24a351", "pubkey": "03...", "amount": 123},
212 {"id": "3da52c32a1", "pubkey": "02...", "amount": 567, "preimage": "abc123..", "tlv_records": [{"type": 696969, "value": "77616c5f6872444873305242454d353736"}]}, 241 {"id": "3da52c32a1", "pubkey": "02...", "amount": 567, "preimage": "abc123..", "tlv_records": [{"type": 696969, "value": "77616c5f6872444873305242454d353736"}]},
213 ], 242 ],
214 } 243 }
@@ -225,7 +254,8 @@ pubkey should be used.
225{ 254{
226 "result_type": "multi_pay_keysend", 255 "result_type": "multi_pay_keysend",
227 "result": { 256 "result": {
228 "preimage": "0123456789abcdef..." // preimage of the payment 257 "preimage": "0123456789abcdef...", // preimage of the payment
258 "fees_paid": 123, // value in msats, optional
229 } 259 }
230} 260}
231``` 261```
@@ -358,8 +388,7 @@ Request:
358```jsonc 388```jsonc
359{ 389{
360 "method": "get_balance", 390 "method": "get_balance",
361 "params": { 391 "params": {}
362 }
363} 392}
364``` 393```
365 394
@@ -379,8 +408,7 @@ Request:
379```jsonc 408```jsonc
380{ 409{
381 "method": "get_info", 410 "method": "get_info",
382 "params": { 411 "params": {}
383 }
384} 412}
385``` 413```
386 414
@@ -396,6 +424,59 @@ Response:
396 "block_height": 1, 424 "block_height": 1,
397 "block_hash": "hex string", 425 "block_hash": "hex string",
398 "methods": ["pay_invoice", "get_balance", "make_invoice", "lookup_invoice", "list_transactions", "get_info"], // list of supported methods for this connection 426 "methods": ["pay_invoice", "get_balance", "make_invoice", "lookup_invoice", "list_transactions", "get_info"], // list of supported methods for this connection
427 "notifications": ["payment_received", "payment_sent"], // list of supported notifications for this connection, optional.
428 }
429}
430```
431
432## Notifications
433
434### `payment_received`
435
436Description: A payment was successfully received by the wallet.
437
438Notification:
439```jsonc
440{
441 "notification_type": "payment_received",
442 "notification": {
443 "type": "incoming",
444 "invoice": "string", // encoded invoice
445 "description": "string", // invoice's description, optional
446 "description_hash": "string", // invoice's description hash, optional
447 "preimage": "string", // payment's preimage
448 "payment_hash": "string", // Payment hash for the payment
449 "amount": 123, // value in msats
450 "fees_paid": 123, // value in msats
451 "created_at": unixtimestamp, // invoice/payment creation time
452 "expires_at": unixtimestamp, // invoice expiration time, optional if not applicable
453 "settled_at": unixtimestamp, // invoice/payment settlement time
454 "metadata": {} // generic metadata that can be used to add things like zap/boostagram details for a payer name/comment/etc.
455 }
456}
457```
458
459### `payment_sent`
460
461Description: A payment was successfully sent by the wallet.
462
463Notification:
464```jsonc
465{
466 "notification_type": "payment_sent",
467 "notification": {
468 "type": "outgoing",
469 "invoice": "string", // encoded invoice
470 "description": "string", // invoice's description, optional
471 "description_hash": "string", // invoice's description hash, optional
472 "preimage": "string", // payment's preimage
473 "payment_hash": "string", // Payment hash for the payment
474 "amount": 123, // value in msats
475 "fees_paid": 123, // value in msats
476 "created_at": unixtimestamp, // invoice/payment creation time
477 "expires_at": unixtimestamp, // invoice expiration time, optional if not applicable
478 "settled_at": unixtimestamp, // invoice/payment settlement time
479 "metadata": {} // generic metadata that can be used to add things like zap/boostagram details for a payer name/comment/etc.
399 } 480 }
400} 481}
401``` 482```
@@ -409,3 +490,24 @@ Response:
409 490
410## Using a dedicated relay 491## Using a dedicated relay
411This NIP does not specify any requirements on the type of relays used. However, if the user is using a custodial service it might make sense to use a relay that is hosted by the custodial service. The relay may then enforce authentication to prevent metadata leaks. Not depending on a 3rd party relay would also improve reliability in this case. 492This NIP does not specify any requirements on the type of relays used. However, if the user is using a custodial service it might make sense to use a relay that is hosted by the custodial service. The relay may then enforce authentication to prevent metadata leaks. Not depending on a 3rd party relay would also improve reliability in this case.
493
494## Appendix
495
496### Example NIP-47 info event
497
498```jsonc
499{
500 "id": "df467db0a9f9ec77ffe6f561811714ccaa2e26051c20f58f33c3d66d6c2b4d1c",
501 "pubkey": "c04ccd5c82fc1ea3499b9c6a5c0a7ab627fbe00a0116110d4c750faeaecba1e2",
502 "created_at": 1713883677,
503 "kind": 13194,
504 "tags": [
505 [
506 "notifications",
507 "payment_received payment_sent"
508 ]
509 ],
510 "content": "pay_invoice pay_keysend get_balance get_info make_invoice lookup_invoice list_transactions multi_pay_invoice multi_pay_keysend sign_message notifications",
511 "sig": "31f57b369459b5306a5353aa9e03be7fbde169bc881c3233625605dd12f53548179def16b9fe1137e6465d7e4d5bb27ce81fd6e75908c46b06269f4233c845d8"
512}
513```