diff options
| author | Semisol <45574030+Semisol@users.noreply.github.com> | 2023-03-30 00:35:13 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-03-30 00:35:13 +0300 |
| commit | e2f088286fcd324bb4754dcdf5ff10f4dc823b5b (patch) | |
| tree | 7513efc54a0c0a84ff6f14ff1a89583898da7769 /47.md | |
| parent | 133faa07636fff9f8e91c69cb9e3a5cce459b241 (diff) | |
NIP-47 Wallet Connect
Diffstat (limited to '47.md')
| -rw-r--r-- | 47.md | 112 |
1 files changed, 112 insertions, 0 deletions
| @@ -0,0 +1,112 @@ | |||
| 1 | NIP-47 | ||
| 2 | ====== | ||
| 3 | |||
| 4 | Nostr Wallet Connect | ||
| 5 | -------------------- | ||
| 6 | |||
| 7 | `draft` `optional` `author:kiwiidb` `author:bumi` `author:semisol` `author:vitorpamplona` | ||
| 8 | |||
| 9 | ## Rationale | ||
| 10 | |||
| 11 | Paying zaps should be possible without the user needing to open a different app to only pay a Lightning invoice. | ||
| 12 | This NIP describes a way for users to control a remote Lightning node or a custodial Lightning wallet. When self-hosting, this setup does not require the user to run their own server, thereby bypassing certain hurdles that are commonly encountered when trying to connect to a Lightning node remotely. | ||
| 13 | |||
| 14 | ## Terms | ||
| 15 | |||
| 16 | * **client**: Nostr app on any platform that wants to pay Lightning invoices | ||
| 17 | * **wallet service**: Nostr app that typically runs on an always-on computer (eg. in the cloud or on a Raspberry Pi). | ||
| 18 | |||
| 19 | ## Events | ||
| 20 | |||
| 21 | There are two event kinds: | ||
| 22 | - `NIP-47 request`: 23194 | ||
| 23 | - `NIP-47 response`: 23195 | ||
| 24 | |||
| 25 | Both the request and response events SHOULD only 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. | ||
| 26 | |||
| 27 | The content is encrypted with [NIP04](https://github.com/nostr-protocol/nips/blob/master/04.md), and is a JSON object. The content depends on the kind. | ||
| 28 | |||
| 29 | Request: | ||
| 30 | ```jsonc | ||
| 31 | { | ||
| 32 | "cmd": "pay_invoice", // command, string | ||
| 33 | "data": { // data, object | ||
| 34 | "invoice": "lnbc50n1..." // command-related data | ||
| 35 | } | ||
| 36 | } | ||
| 37 | ``` | ||
| 38 | |||
| 39 | Response: | ||
| 40 | ```jsonc | ||
| 41 | { | ||
| 42 | "status": "ok", // status, "ok" | "error" | ||
| 43 | "event": "0123456789abcdef...", // event the command is in response to, string | ||
| 44 | "data": { // response data | ||
| 45 | "preimage": "0123456789abcdef..." // command-related data | ||
| 46 | } | ||
| 47 | } | ||
| 48 | ``` | ||
| 49 | |||
| 50 | The data field SHOULD contain a `message` field with a human readable error message if the status is `error`. | ||
| 51 | |||
| 52 | ## Nostr Wallet Connect URI | ||
| 53 | **client** discovers **wallet service** by scanning a QR code, handling a deeplink or pasting in a URI. | ||
| 54 | |||
| 55 | The **wallet service** generates this connection URI with protocol `nostr+walletconnect:` and base path it's hex-encoded `pubkey` with the following query string parameters: | ||
| 56 | |||
| 57 | - `relay` Required. URL of the relay where the **wallet service** is connected and will be listening for events. May be more than one. | ||
| 58 | - `secret` Required. 32-byte randomly generated hex encoded string. The **client** should use this to sign events when communicating with the **wallet service**. | ||
| 59 | - Authorization does not require passing keys back and forth. | ||
| 60 | - The user can have different keys for different applications. Keys can be revoked and created at will and have arbitrary constraints (eg. budgets). | ||
| 61 | - The key is harder to leak since it is not shown to the user and backed up. | ||
| 62 | - It improves privacy because the user's main key would not be linked to their payments. | ||
| 63 | |||
| 64 | The **client** should then store this connection and use it when the user wants to perform actions like paying an invoice. Optionally it can display metadata about the connected **wallet service** from it's profile (name, image, url). | ||
| 65 | |||
| 66 | ### Example connection string | ||
| 67 | ```sh | ||
| 68 | nostrwalletconnect:b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4?relay=wss%3A%2F%2Frelay.damus.io&secret=71a8c14c1407c113601079c4302dab36460f0ccd0ad506f1f2dc73b5100e4f3c | ||
| 69 | ``` | ||
| 70 | |||
| 71 | ## Commands | ||
| 72 | |||
| 73 | ### `pay_invoice` | ||
| 74 | |||
| 75 | Description: Requests payment of an invoice. | ||
| 76 | |||
| 77 | Request: | ||
| 78 | ```jsonc | ||
| 79 | { | ||
| 80 | "invoice": "lnbc50n1..." // BOLT11 invoice, string | ||
| 81 | } | ||
| 82 | ``` | ||
| 83 | |||
| 84 | Response: | ||
| 85 | ```jsonc | ||
| 86 | { | ||
| 87 | "preimage": "0123456789abcdef..." // preimage after payment, string | ||
| 88 | } | ||
| 89 | ``` | ||
| 90 | |||
| 91 | ### `balance` | ||
| 92 | |||
| 93 | Description: Requests the balance of the wallet. | ||
| 94 | |||
| 95 | Request: an empty JSON object. | ||
| 96 | |||
| 97 | Response: | ||
| 98 | ```jsonc | ||
| 99 | { | ||
| 100 | "balance": 100000 // balance in msat, int | ||
| 101 | } | ||
| 102 | ``` | ||
| 103 | |||
| 104 | ## Example pay invoice flow | ||
| 105 | |||
| 106 | 0. The user scans the QR code generated by the **wallet service** with their **client** application, they follow a `nostrwalletconnect:` deeplink or configure the connection details manually. | ||
| 107 | 1. **client** sends an event to with **wallet service** service with kind `23194`. The content is a `pay_invoice` request. The private key is the secret from the connection string above. | ||
| 108 | 2. **nostr-wallet-connect-service** verifies that the author's key is authorized to perform the payment, decrypts the payload and sends the payment. | ||
| 109 | 3. **nostr-wallet-connect-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. | ||
| 110 | |||
| 111 | ## Using a dedicated relay | ||
| 112 | 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. | ||