mirror of
https://github.com/nostr-protocol/nips.git
synced 2024-12-22 00:25:50 -05:00
Merge pull request #1164 from rolznz/feat/nip-47-notifications
NIP-47 notifications
This commit is contained in:
commit
84aeb10d39
128
47.md
128
47.md
|
@ -8,32 +8,42 @@ Nostr Wallet Connect
|
||||||
|
|
||||||
## Rationale
|
## Rationale
|
||||||
|
|
||||||
This 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.
|
This 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.
|
||||||
|
|
||||||
## Terms
|
## Terms
|
||||||
|
|
||||||
* **client**: Nostr app on any platform that wants to pay Lightning invoices.
|
* **client**: Nostr app on any platform that wants to interact with a lightning wallet.
|
||||||
* **user**: The person using the **client**, and want's to connect their wallet app to their **client**.
|
* **user**: The person using the **client**, and wants to connect their wallet to their **client**.
|
||||||
* **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.
|
* **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.
|
||||||
|
|
||||||
## Theory of Operation
|
## Theory of Operation
|
||||||
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.
|
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.
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
|
5. The **wallet service** may send encrypted notifications (kind 23196) of wallet events (such as a received payment) to the **client**.
|
||||||
|
|
||||||
## Events
|
## Events
|
||||||
|
|
||||||
There are three event kinds:
|
There are four event kinds:
|
||||||
- `NIP-47 info event`: 13194
|
- `NIP-47 info event`: 13194
|
||||||
- `NIP-47 request`: 23194
|
- `NIP-47 request`: 23194
|
||||||
- `NIP-47 response`: 23195
|
- `NIP-47 response`: 23195
|
||||||
|
- `NIP-47 notification event`: 23196
|
||||||
|
|
||||||
The 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
|
### Info Event
|
||||||
a 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.
|
|
||||||
|
The info event should be a replaceable event that is published by the **wallet service** on the relay to indicate which capabilities it supports.
|
||||||
|
|
||||||
|
The content should be a plaintext string with the supported capabilities space-separated, eg. `pay_invoice get_balance notifications`.
|
||||||
|
|
||||||
|
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`.
|
||||||
|
|
||||||
|
### Request and Response Events
|
||||||
|
|
||||||
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 **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.
|
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 **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.
|
||||||
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.
|
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,6 +78,22 @@ The `result_type` field MUST contain the name of the method that this event is r
|
||||||
The `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.
|
The `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.
|
||||||
If the command was successful, the `error` field must be null.
|
If the command was successful, the `error` field must be null.
|
||||||
|
|
||||||
|
### Notification Events
|
||||||
|
|
||||||
|
The notification event SHOULD contain one `p` tag, the public key of the **user**.
|
||||||
|
|
||||||
|
The 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:
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
{
|
||||||
|
"notification_type": "payment_received", //indicates the structure of the notification field
|
||||||
|
"notification": {
|
||||||
|
"payment_hash": "0123456789abcdef..." // notification-related data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### Error codes
|
### Error codes
|
||||||
- `RATE_LIMITED`: The client is sending commands too fast. It should retry in a few seconds.
|
- `RATE_LIMITED`: The client is sending commands too fast. It should retry in a few seconds.
|
||||||
- `NOT_IMPLEMENTED`: The command is not known or is intentionally not implemented.
|
- `NOT_IMPLEMENTED`: The command is not known or is intentionally not implemented.
|
||||||
|
@ -120,7 +146,8 @@ Response:
|
||||||
{
|
{
|
||||||
"result_type": "pay_invoice",
|
"result_type": "pay_invoice",
|
||||||
"result": {
|
"result": {
|
||||||
"preimage": "0123456789abcdef..." // preimage of the payment
|
"preimage": "0123456789abcdef...", // preimage of the payment
|
||||||
|
"fees_paid": 123, // value in msats, optional
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -155,7 +182,8 @@ payment hash of the invoice should be used.
|
||||||
{
|
{
|
||||||
"result_type": "multi_pay_invoice",
|
"result_type": "multi_pay_invoice",
|
||||||
"result": {
|
"result": {
|
||||||
"preimage": "0123456789abcdef..." // preimage of the payment
|
"preimage": "0123456789abcdef...", // preimage of the payment
|
||||||
|
"fees_paid": 123, // value in msats, optional
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -189,6 +217,7 @@ Response:
|
||||||
"result_type": "pay_keysend",
|
"result_type": "pay_keysend",
|
||||||
"result": {
|
"result": {
|
||||||
"preimage": "0123456789abcdef...", // preimage of the payment
|
"preimage": "0123456789abcdef...", // preimage of the payment
|
||||||
|
"fees_paid": 123, // value in msats, optional
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -225,7 +254,8 @@ pubkey should be used.
|
||||||
{
|
{
|
||||||
"result_type": "multi_pay_keysend",
|
"result_type": "multi_pay_keysend",
|
||||||
"result": {
|
"result": {
|
||||||
"preimage": "0123456789abcdef..." // preimage of the payment
|
"preimage": "0123456789abcdef...", // preimage of the payment
|
||||||
|
"fees_paid": 123, // value in msats, optional
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -394,6 +424,59 @@ Response:
|
||||||
"block_height": 1,
|
"block_height": 1,
|
||||||
"block_hash": "hex string",
|
"block_hash": "hex string",
|
||||||
"methods": ["pay_invoice", "get_balance", "make_invoice", "lookup_invoice", "list_transactions", "get_info"], // list of supported methods for this connection
|
"methods": ["pay_invoice", "get_balance", "make_invoice", "lookup_invoice", "list_transactions", "get_info"], // list of supported methods for this connection
|
||||||
|
"notifications": ["payment_received", "payment_sent"], // list of supported notifications for this connection, optional.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notifications
|
||||||
|
|
||||||
|
### `payment_received`
|
||||||
|
|
||||||
|
Description: A payment was successfully received by the wallet.
|
||||||
|
|
||||||
|
Notification:
|
||||||
|
```jsonc
|
||||||
|
{
|
||||||
|
"notification_type": "payment_received",
|
||||||
|
"notification": {
|
||||||
|
"type": "incoming",
|
||||||
|
"invoice": "string", // encoded invoice
|
||||||
|
"description": "string", // invoice's description, optional
|
||||||
|
"description_hash": "string", // invoice's description hash, optional
|
||||||
|
"preimage": "string", // payment's preimage
|
||||||
|
"payment_hash": "string", // Payment hash for the payment
|
||||||
|
"amount": 123, // value in msats
|
||||||
|
"fees_paid": 123, // value in msats
|
||||||
|
"created_at": unixtimestamp, // invoice/payment creation time
|
||||||
|
"expires_at": unixtimestamp, // invoice expiration time, optional if not applicable
|
||||||
|
"settled_at": unixtimestamp, // invoice/payment settlement time
|
||||||
|
"metadata": {} // generic metadata that can be used to add things like zap/boostagram details for a payer name/comment/etc.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `payment_sent`
|
||||||
|
|
||||||
|
Description: A payment was successfully sent by the wallet.
|
||||||
|
|
||||||
|
Notification:
|
||||||
|
```jsonc
|
||||||
|
{
|
||||||
|
"notification_type": "payment_sent",
|
||||||
|
"notification": {
|
||||||
|
"type": "outgoing",
|
||||||
|
"invoice": "string", // encoded invoice
|
||||||
|
"description": "string", // invoice's description, optional
|
||||||
|
"description_hash": "string", // invoice's description hash, optional
|
||||||
|
"preimage": "string", // payment's preimage
|
||||||
|
"payment_hash": "string", // Payment hash for the payment
|
||||||
|
"amount": 123, // value in msats
|
||||||
|
"fees_paid": 123, // value in msats
|
||||||
|
"created_at": unixtimestamp, // invoice/payment creation time
|
||||||
|
"expires_at": unixtimestamp, // invoice expiration time, optional if not applicable
|
||||||
|
"settled_at": unixtimestamp, // invoice/payment settlement time
|
||||||
|
"metadata": {} // generic metadata that can be used to add things like zap/boostagram details for a payer name/comment/etc.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -407,3 +490,24 @@ Response:
|
||||||
|
|
||||||
## Using a dedicated relay
|
## Using a dedicated relay
|
||||||
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.
|
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.
|
||||||
|
|
||||||
|
## Appendix
|
||||||
|
|
||||||
|
### Example NIP-47 info event
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
{
|
||||||
|
"id": "df467db0a9f9ec77ffe6f561811714ccaa2e26051c20f58f33c3d66d6c2b4d1c",
|
||||||
|
"pubkey": "c04ccd5c82fc1ea3499b9c6a5c0a7ab627fbe00a0116110d4c750faeaecba1e2",
|
||||||
|
"created_at": 1713883677,
|
||||||
|
"kind": 13194,
|
||||||
|
"tags": [
|
||||||
|
[
|
||||||
|
"notifications",
|
||||||
|
"payment_received payment_sent"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"content": "pay_invoice pay_keysend get_balance get_info make_invoice lookup_invoice list_transactions multi_pay_invoice multi_pay_keysend sign_message notifications",
|
||||||
|
"sig": "31f57b369459b5306a5353aa9e03be7fbde169bc881c3233625605dd12f53548179def16b9fe1137e6465d7e4d5bb27ce81fd6e75908c46b06269f4233c845d8"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
Loading…
Reference in New Issue
Block a user