diff options
| -rw-r--r-- | 47.md | 148 |
1 files changed, 127 insertions, 21 deletions
| @@ -28,15 +28,16 @@ Fundamentally NWC is communication between a **client** and **wallet service** b | |||
| 28 | 28 | ||
| 29 | 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. | 29 | 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. |
| 30 | 30 | ||
| 31 | 5. The **wallet service** may send encrypted notifications (kind 23196) of wallet events (such as a received payment) to the **client**. | 31 | 5. The **wallet service** may send encrypted notifications (kind 23197 or 23196) of wallet events (such as a received payment) to the **client**. |
| 32 | 32 | ||
| 33 | ## Events | 33 | ## Events |
| 34 | 34 | ||
| 35 | There are four event kinds: | 35 | There are four event kinds: |
| 36 | |||
| 36 | - `NIP-47 info event`: 13194 | 37 | - `NIP-47 info event`: 13194 |
| 37 | - `NIP-47 request`: 23194 | 38 | - `NIP-47 request`: 23194 |
| 38 | - `NIP-47 response`: 23195 | 39 | - `NIP-47 response`: 23195 |
| 39 | - `NIP-47 notification event`: 23196 | 40 | - `NIP-47 notification event`: 23197 (23196 for backwards compatibility with NIP-04) |
| 40 | 41 | ||
| 41 | ### Info Event | 42 | ### Info Event |
| 42 | 43 | ||
| @@ -46,34 +47,71 @@ The content should be a plaintext string with the supported capabilities space-s | |||
| 46 | 47 | ||
| 47 | If 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`. | 48 | If 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`. |
| 48 | 49 | ||
| 50 | It should also contain supported encryption modes as described in the [Encryption](#encryption) section. For example: | ||
| 51 | |||
| 52 | ```jsonc | ||
| 53 | { | ||
| 54 | "kind": 13194, | ||
| 55 | "tags": [ | ||
| 56 | ["encryption", "nip44_v2 nip04"], // List of supported encryption schemes as described in the Encryption section. | ||
| 57 | ["notifications", "payment_received payment_sent"] | ||
| 58 | // ... | ||
| 59 | ], | ||
| 60 | "content": "pay_invoice get_balance make_invoice lookup_invoice list_transactions get_info notifications", | ||
| 61 | // ... | ||
| 62 | } | ||
| 63 | ``` | ||
| 64 | |||
| 49 | ### Request and Response Events | 65 | ### Request and Response Events |
| 50 | 66 | ||
| 51 | Both 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 **client** if this is a response. The response event SHOULD contain an `e` tag with the id of the request event it is responding to. | 67 | Both 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 **client** if this is a response. The response event SHOULD contain an `e` tag with the id of the request event it is responding to. |
| 52 | Optionally, 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. | 68 | Optionally, 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. |
| 53 | 69 | ||
| 54 | The content of requests and responses is encrypted with [NIP04](04.md), and is a JSON-RPCish object with a semi-fixed structure: | 70 | The content of requests and responses is encrypted with [NIP44](44.md), and is a JSON-RPCish object with a semi-fixed structure. |
| 55 | 71 | ||
| 56 | Request: | 72 | **Important note for backwards-compatibility:** The initial version of the protocol used [NIP04](04.md). If a **wallet service** or client app does not include the `encryption` tag in the |
| 57 | ```jsonc | 73 | `info` or request events, it should be assumed that the connection is using NIP04 for encryption. See the [Encryption](#encryption) section for more information. |
| 74 | |||
| 75 | Example request: | ||
| 76 | |||
| 77 | ```js | ||
| 58 | { | 78 | { |
| 59 | "method": "pay_invoice", // method, string | 79 | "kind" 23194, |
| 60 | "params": { // params, object | 80 | "tags": [ |
| 61 | "invoice": "lnbc50n1..." // command-related data | 81 | ["encryption", "nip44_v2"], |
| 62 | } | 82 | ["p", "03..." ] // public key of the wallet service. |
| 83 | // ... | ||
| 84 | ], | ||
| 85 | "content": nip44_encrypt({ // Encryption type corresponds to the `encryption` tag. | ||
| 86 | "method": "pay_invoice", // method, string | ||
| 87 | "params": { // params, object | ||
| 88 | "invoice": "lnbc50n1..." // command-related data | ||
| 89 | } | ||
| 90 | }), | ||
| 63 | } | 91 | } |
| 64 | ``` | 92 | ``` |
| 65 | 93 | ||
| 66 | Response: | 94 | Example response: |
| 67 | ```jsonc | 95 | |
| 96 | ```js | ||
| 68 | { | 97 | { |
| 69 | "result_type": "pay_invoice", //indicates the structure of the result field | 98 | "kind" 23195, |
| 70 | "error": { //object, non-null in case of error | 99 | "tags": [ |
| 71 | "code": "UNAUTHORIZED", //string error code, see below | 100 | ["p", "03..." ] // public key of the requesting client app |
| 72 | "message": "human readable error message" | 101 | ["e", "1234"] // id of the request event this is responding to |
| 73 | }, | 102 | // ... |
| 74 | "result": { // result, object. null in case of error. | 103 | ], |
| 75 | "preimage": "0123456789abcdef..." // command-related data | 104 | "content": nip44_encrypt({ // Encrypted using the scheme requested by the client. |
| 76 | } | 105 | "result_type": "pay_invoice", //indicates the structure of the result field |
| 106 | "error": { //object, non-null in case of error | ||
| 107 | "code": "UNAUTHORIZED", //string error code, see below | ||
| 108 | "message": "human readable error message" | ||
| 109 | }, | ||
| 110 | "result": { // result, object. null in case of error. | ||
| 111 | "preimage": "0123456789abcdef..." // command-related data | ||
| 112 | } | ||
| 113 | }) | ||
| 114 | // ... | ||
| 77 | } | 115 | } |
| 78 | ``` | 116 | ``` |
| 79 | 117 | ||
| @@ -83,9 +121,9 @@ If the command was successful, the `error` field must be null. | |||
| 83 | 121 | ||
| 84 | ### Notification Events | 122 | ### Notification Events |
| 85 | 123 | ||
| 86 | The notification event SHOULD contain one `p` tag, the public key of the **client**. | 124 | The notification event is a kind 23197 event SHOULD contain one `p` tag, the public key of the **client**. |
| 87 | 125 | ||
| 88 | The content of notifications is encrypted with [NIP04](04.md), and is a JSON-RPCish object with a semi-fixed structure: | 126 | The content of notifications is encrypted with [NIP44](44.md) (or NIP-04 for legacy client apps), and is a JSON-RPCish object with a semi-fixed structure: |
| 89 | 127 | ||
| 90 | ```jsonc | 128 | ```jsonc |
| 91 | { | 129 | { |
| @@ -96,6 +134,7 @@ The content of notifications is encrypted with [NIP04](04.md), and is a JSON-RPC | |||
| 96 | } | 134 | } |
| 97 | ``` | 135 | ``` |
| 98 | 136 | ||
| 137 | _Note on backwards-compatibility:_ If a **wallet service** supports both nip44 and nip04 for legacy client apps, it should publish both notification events for each notification - kind 23196 encrypted with NIP-04, and kind 23197 encrypted with NIP-44. It is up to the **client** to decide which event to listen to based on its supported encryption and declared supported encryption schemes of the **wallet service** in the `info` event. | ||
| 99 | 138 | ||
| 100 | ### Error codes | 139 | ### Error codes |
| 101 | - `RATE_LIMITED`: The client is sending commands too fast. It should retry in a few seconds. | 140 | - `RATE_LIMITED`: The client is sending commands too fast. It should retry in a few seconds. |
| @@ -105,6 +144,7 @@ The content of notifications is encrypted with [NIP04](04.md), and is a JSON-RPC | |||
| 105 | - `RESTRICTED`: This public key is not allowed to do this operation. | 144 | - `RESTRICTED`: This public key is not allowed to do this operation. |
| 106 | - `UNAUTHORIZED`: This public key has no wallet connected. | 145 | - `UNAUTHORIZED`: This public key has no wallet connected. |
| 107 | - `INTERNAL`: An internal error. | 146 | - `INTERNAL`: An internal error. |
| 147 | - `UNSUPPORTED_ENCRYPTION`: The encryption type of the request is not supported by the wallet service. | ||
| 108 | - `OTHER`: Other error. | 148 | - `OTHER`: Other error. |
| 109 | 149 | ||
| 110 | ## Nostr Wallet Connect URI | 150 | ## Nostr Wallet Connect URI |
| @@ -499,6 +539,71 @@ Notification: | |||
| 499 | 2. **wallet service** verifies that the author's key is authorized to perform the payment, decrypts the payload and sends the payment. | 539 | 2. **wallet service** verifies that the author's key is authorized to perform the payment, decrypts the payload and sends the payment. |
| 500 | 3. **wallet service** responds to the event by sending an event with kind `23195` and content being a response either containing an error message or a preimage. | 540 | 3. **wallet service** responds to the event by sending an event with kind `23195` and content being a response either containing an error message or a preimage. |
| 501 | 541 | ||
| 542 | ## Encryption | ||
| 543 | |||
| 544 | The initial version of NWC used [NIP-04](04.md) for encryption which has been deprecated and replaced by [NIP-44](44.md). NIP-44 should always be preferred for encryption, but there may be legacy cases | ||
| 545 | where the **wallet service** or **client** has not yet migrated to NIP-44. The **wallet service** and **client** should negotiate the encryption method to use based on the `encryption` tag in the `info` event. | ||
| 546 | |||
| 547 | The encryption tag can contain either `nip44_v2` or `nip04`. The absence of this tag implies that the wallet only supports `nip04`. | ||
| 548 | |||
| 549 | | Encryption code | Use | Notes | | ||
| 550 | |-----------------|----------------------|---------------------------------------------------------| | ||
| 551 | | `nip44_v2` | NIP-44 | Required | | ||
| 552 | | `nip04` | NIP-04 | Deprecated and only here for backward compatibility | | ||
| 553 | | `<not present>` | NIP-04 | Deprecated and only here for backward compatibility | | ||
| 554 | |||
| 555 | The negotiation works as follows. | ||
| 556 | |||
| 557 | 1. The **wallet service** includes an `encryption` tag in the `info` event. This tag contains a space-separated list of encryption schemes that the **wallet service** supports (eg. `nip44_v2 nip04`) | ||
| 558 | 2. The **client application** includes an `encryption` tag in each request event. This tag contains the encryption scheme which should be used for the request. The **client application** should always prefer nip44 if supported by the **wallet service**. | ||
| 559 | |||
| 560 | ### Info event | ||
| 561 | |||
| 562 | First, the **wallet service** adds an `encryption` tag to its `info` event containing a space-separated list of encryption schemes it supports. For example, | ||
| 563 | if a wallet service supports nip44, but also allows backwards-compatibility to nip04 client applications, its `encryption` tag in the `info` event might look something like: | ||
| 564 | |||
| 565 | ```jsonc | ||
| 566 | { | ||
| 567 | "kind": 13194, | ||
| 568 | "tags": [ | ||
| 569 | ["encryption", "nip44_v2 nip04"], | ||
| 570 | // ... | ||
| 571 | ], | ||
| 572 | "content": "pay_invoice get_balance make_invoice lookup_invoice list_transactions get_info", | ||
| 573 | // ... | ||
| 574 | } | ||
| 575 | ``` | ||
| 576 | |||
| 577 | When a **client application** establishes a connection, it should read the info event and look for the `encryption` tag. | ||
| 578 | |||
| 579 | **Absence of this tag implies that the wallet only supports nip04.** | ||
| 580 | |||
| 581 | If the `encryption` tag is present, the **client application** will choose optimal encryption supported by both itself, and the **wallet service**, which should always be nip44 if possible. | ||
| 582 | |||
| 583 | ### Request events | ||
| 584 | |||
| 585 | When a **client application** sends a request event, it should include a `encryption` tag with the encryption scheme it is using. The scheme MUST be supported by the **wallet service** as indicated by the info event. | ||
| 586 | For example, if the client application supports nip44, the request event might look like: | ||
| 587 | |||
| 588 | ```jsonc | ||
| 589 | { | ||
| 590 | "kind": 23194, | ||
| 591 | "tags": [ | ||
| 592 | ["encryption", "nip44_v2"], | ||
| 593 | // ... | ||
| 594 | ], | ||
| 595 | // ... | ||
| 596 | } | ||
| 597 | ``` | ||
| 598 | |||
| 599 | If the **wallet service** does not support the specified encryption scheme, it will return an `UNSUPPORTED_ENCRYPTION` error. Absence of the `encryption` tag indicates use of nip04 for encryption. | ||
| 600 | |||
| 601 | ### Notification events | ||
| 602 | |||
| 603 | As described above in the [Notifications](#notifications) section, if a **wallet service** supports both nip04 and nip44, it should publish two notification events for each notification - kind 23196 encrypted with NIP-04, and kind 23197 encrypted with NIP-44. If the **wallet service** only supports nip44, it should only publish kind 23197 events. | ||
| 604 | |||
| 605 | The **client** should check the `encryption` tag in the `info` event to determine which encryption schemes the **wallet service** supports, and listen to the appropriate notification event. | ||
| 606 | |||
| 502 | ## Using a dedicated relay | 607 | ## Using a dedicated relay |
| 503 | This 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. | 608 | This 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. |
| 504 | 609 | ||
| @@ -513,6 +618,7 @@ This NIP does not specify any requirements on the type of relays used. However, | |||
| 513 | "created_at": 1713883677, | 618 | "created_at": 1713883677, |
| 514 | "kind": 13194, | 619 | "kind": 13194, |
| 515 | "tags": [ | 620 | "tags": [ |
| 621 | [ "encryption", "nip44_v2 nip04" ], | ||
| 516 | [ | 622 | [ |
| 517 | "notifications", | 623 | "notifications", |
| 518 | "payment_received payment_sent" | 624 | "payment_received payment_sent" |