mirror of
https://github.com/nostr-protocol/nips.git
synced 2025-12-09 00:28:51 +00:00
Compare commits
75 Commits
nip93-nson
...
key-invali
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e057fa01ca | ||
|
|
e0fc913719 | ||
|
|
fab6a21a77 | ||
|
|
852bd7f872 | ||
|
|
1b35f1153d | ||
|
|
3893fa7f7c | ||
|
|
9ffd3638d7 | ||
|
|
73e93d09ad | ||
|
|
1f6c79f6d2 | ||
|
|
7668507cdf | ||
|
|
83cbd3e17a | ||
|
|
36e9fd59e9 | ||
|
|
c8c2ab60ab | ||
|
|
1412eb89c2 | ||
|
|
ece0dda45b | ||
|
|
b481651e81 | ||
|
|
58f1667479 | ||
|
|
992b045aa7 | ||
|
|
bef3e6c941 | ||
|
|
61849b5a6b | ||
|
|
92ce49dda0 | ||
|
|
363d112e33 | ||
|
|
114302517f | ||
|
|
057d097e74 | ||
|
|
4e8f3adf43 | ||
|
|
2372874b98 | ||
|
|
5b32def861 | ||
|
|
95f537e90d | ||
|
|
34910c8674 | ||
|
|
68b9331b62 | ||
|
|
621340e267 | ||
|
|
a9f2c6a2f1 | ||
|
|
3331b5610c | ||
|
|
2b34e9f417 | ||
|
|
fb5f5a1a97 | ||
|
|
2e842b496a | ||
|
|
3e03b4b67f | ||
|
|
d435ffc39c | ||
|
|
75c05b547c | ||
|
|
6baacf6fb1 | ||
|
|
964bc5b5ce | ||
|
|
89b308d540 | ||
|
|
14a887d43b | ||
|
|
0d962cbe74 | ||
|
|
c78856d281 | ||
|
|
867c8bb334 | ||
|
|
fe9ed69dc3 | ||
|
|
cabbaadb69 | ||
|
|
3a38583c06 | ||
|
|
b12c93c452 | ||
|
|
4f04de2afd | ||
|
|
a56d1c2877 | ||
|
|
0495931355 | ||
|
|
1c916953c1 | ||
|
|
ccbdfb95c1 | ||
|
|
835ec26141 | ||
|
|
d9caf9d7b4 | ||
|
|
4ea0e8e9f2 | ||
|
|
1457399664 | ||
|
|
00491aa9fa | ||
|
|
89e3c01b14 | ||
|
|
9076b8486d | ||
|
|
64ac0710de | ||
|
|
2619482200 | ||
|
|
4cbb672d1c | ||
|
|
2c1ed74c49 | ||
|
|
e5302f84c7 | ||
|
|
de1aec64d2 | ||
|
|
f75d91551c | ||
|
|
30620c8e54 | ||
|
|
2d31ddd38a | ||
|
|
29f26e72b5 | ||
|
|
b8aec7dad5 | ||
|
|
e91ce3409e | ||
|
|
1c728516df |
11
01.md
11
01.md
@@ -16,7 +16,7 @@ The only object type that exists is the `event`, which has the following format
|
||||
|
||||
```json
|
||||
{
|
||||
"id": <32-bytes lowercase hex-encoded sha256 of the serialized event data>
|
||||
"id": <32-bytes lowercase hex-encoded sha256 of the serialized event data>,
|
||||
"pubkey": <32-bytes lowercase hex-encoded public key of the event creator>,
|
||||
"created_at": <unix timestamp in seconds>,
|
||||
"kind": <integer>,
|
||||
@@ -66,8 +66,8 @@ Clients can send 3 types of messages, which must be JSON arrays, according to th
|
||||
"kinds": <a list of a kind numbers>,
|
||||
"#e": <a list of event ids that are referenced in an "e" tag>,
|
||||
"#p": <a list of pubkeys that are referenced in a "p" tag>,
|
||||
"since": <an integer unix timestamp, events must be newer than this to pass>,
|
||||
"until": <an integer unix timestamp, events must be older than this to pass>,
|
||||
"since": <an integer unix timestamp in seconds, events must be newer than this to pass>,
|
||||
"until": <an integer unix timestamp in seconds, events must be older than this to pass>,
|
||||
"limit": <maximum number of events to be returned in the initial query>
|
||||
}
|
||||
```
|
||||
@@ -99,7 +99,7 @@ This NIP defines no rules for how `NOTICE` messages should be sent or treated.
|
||||
## Basic Event Kinds
|
||||
|
||||
- `0`: `set_metadata`: the `content` is set to a stringified JSON object `{name: <username>, about: <string>, picture: <url, string>}` describing the user who created the event. A relay may delete past `set_metadata` events once it gets a new one for the same pubkey.
|
||||
- `1`: `text_note`: the `content` is set to the plaintext content of a note (anything the user wants to say). Do not use Markdown! Clients should not have to guess how to interpret content like `[]()`. Use different event kinds for parsable content.
|
||||
- `1`: `text_note`: the `content` is set to the **plaintext** content of a note (anything the user wants to say). Content that must be parsed, such as Markdown and HTML, should not be used. Clients should also not parse content as those.
|
||||
- `2`: `recommend_server`: the `content` is set to the URL (e.g., `wss://somerelay.com`) of a relay the event creator wants to recommend to its followers.
|
||||
|
||||
A relay may choose to treat different message kinds differently, and it may or may not choose to have a default way to handle kinds it doesn't know about.
|
||||
@@ -107,6 +107,7 @@ A relay may choose to treat different message kinds differently, and it may or m
|
||||
## Other Notes:
|
||||
|
||||
- Clients should not open more than one websocket to each relay. One channel can support an unlimited number of subscriptions, so clients should do that.
|
||||
- The `tags` array can store a tag identifier as the first element of each subarray, plus arbitrary information afterward (always as strings). This NIP defines `"p"` — meaning "pubkey", which points to a pubkey of someone that is referred to in the event —, and `"e"` — meaning "event", which points to the id of an event this event is quoting, replying to or referring to somehow. See [NIP-10](https://github.com/nostr-protocol/nips/blob/127d5518bfa9a4e4e7510490c0b8d95e342dfa4b/10.md) for a detailed description of "e" and "p" tags.
|
||||
- The `tags` array can store a tag identifier as the first element of each subarray, plus arbitrary information afterward (always as strings). This NIP defines `"p"` — meaning "pubkey", which points to a pubkey of someone that is referred to in the event —, and `"e"` — meaning "event", which points to the id of an event this event is quoting, replying to or referring to somehow. See [NIP-10](10.md) for a detailed description of "e" and "p" tags.
|
||||
- The `<recommended relay URL>` item present on the `"e"` and `"p"` tags is an optional (could be set to `""`) URL of a relay the client could attempt to connect to fetch the tagged event or other events from a tagged profile. It MAY be ignored, but it exists to increase censorship resistance and make the spread of relay addresses more seamless across clients.
|
||||
- Clients should use the created_at field to judge the age of a metadata event and completely replace older metadata events with newer metadata events regardless of the order in which they arrive. Clients should not merge any filled fields within older metadata events into empty fields of newer metadata events.
|
||||
- When a websocket is closed by the relay with a status code 4000 that means the client shouldn't try to connect again.
|
||||
|
||||
6
05.md
6
05.md
@@ -6,7 +6,7 @@ Mapping Nostr keys to DNS-based internet identifiers
|
||||
|
||||
`final` `optional` `author:fiatjaf` `author:mikedilger`
|
||||
|
||||
On events of kind `0` (`set_metadata`) one can specify the key `"nip05"` with an [internet identifier](https://datatracker.ietf.org/doc/html/rfc5322#section-3.4.1) (an email-like address) as the value. Although there is a link to a very liberal "internet identifier" specification above, NIP-05 assumes the `<local-part>` part will be restricted to the characters `a-z0-9-_.`, case insensitive.
|
||||
On events of kind `0` (`set_metadata`) one can specify the key `"nip05"` with an [internet identifier](https://datatracker.ietf.org/doc/html/rfc5322#section-3.4.1) (an email-like address) as the value. Although there is a link to a very liberal "internet identifier" specification above, NIP-05 assumes the `<local-part>` part will be restricted to the characters `a-z0-9-_.`, case-insensitive.
|
||||
|
||||
Upon seeing that, the client splits the identifier into `<local-part>` and `<domain>` and use these values to make a GET request to `https://<domain>/.well-known/nostr.json?name=<local-part>`.
|
||||
|
||||
@@ -50,7 +50,7 @@ or with the **optional** `"relays"` attribute:
|
||||
|
||||
If the pubkey matches the one given in `"names"` (as in the example above) that means the association is right and the `"nip05"` identifier is valid and can be displayed.
|
||||
|
||||
The optional `"relays"` attribute may contain an object with public keys as properties and arrays of relay URLs as values. When present, that can be used to help clients learn in which relays that user may be found. Web servers which serve `/.well-known/nostr.json` files dynamically based on the query string SHOULD also serve the relays data for any name they serve in the same reply when that is available.
|
||||
The optional `"relays"` attribute may contain an object with public keys as properties and arrays of relay URLs as values. When present, that can be used to help clients learn in which relays the specific user may be found. Web servers which serve `/.well-known/nostr.json` files dynamically based on the query string SHOULD also serve the relays data for any name they serve in the same reply when that is available.
|
||||
|
||||
## Finding users from their NIP-05 identifier
|
||||
|
||||
@@ -76,7 +76,7 @@ Clients may treat the identifier `_@domain` as the "root" identifier, and choose
|
||||
|
||||
### Reasoning for the `/.well-known/nostr.json?name=<local-part>` format
|
||||
|
||||
By adding the `<local-part>` as a query string instead of as part of the path the protocol can support both dynamic servers that can generate JSON on-demand and static servers with a JSON file in it that may contain multiple names.
|
||||
By adding the `<local-part>` as a query string instead of as part of the path, the protocol can support both dynamic servers that can generate JSON on-demand and static servers with a JSON file in it that may contain multiple names.
|
||||
|
||||
### Allowing access from JavaScript apps
|
||||
|
||||
|
||||
5
07.md
5
07.md
@@ -26,7 +26,10 @@ async window.nostr.nip04.decrypt(pubkey, ciphertext): string // takes ciphertext
|
||||
|
||||
- [horse](https://github.com/fiatjaf/horse) (Chrome and derivatives)
|
||||
- [nos2x](https://github.com/fiatjaf/nos2x) (Chrome and derivatives)
|
||||
- [Alby](https://getalby.com) (Chrome and derivatives, Firefox, Safari)
|
||||
- [Alby](https://getalby.com) (Chrome and derivatives, Firefox)
|
||||
- [Blockcore](https://www.blockcore.net/wallet) (Chrome and derivatives)
|
||||
- [nos2x-fox](https://diegogurpegui.com/nos2x-fox/) (Firefox)
|
||||
- [Flamingo](https://www.getflamingo.org/) (Chrome and derivatives)
|
||||
- [AKA Profiles](https://github.com/neilck/aka-extension) (Chrome, stores multiple keys)
|
||||
- [TokenPocket](https://www.tokenpocket.pro/) (Android, IOS, Chrome and derivatives)
|
||||
- [Nostrmo](https://github.com/haorendashu/nostrmo_faq#download) (Android, IOS)
|
||||
|
||||
3
09.md
3
09.md
@@ -8,7 +8,7 @@ Event Deletion
|
||||
|
||||
A special event with kind `5`, meaning "deletion" is defined as having a list of one or more `e` tags, each referencing an event the author is requesting to be deleted.
|
||||
|
||||
Each tag entry must contain an "e" event id intended for deletion.
|
||||
Each tag entry must contain an "e" event id and/or NIP-33 `a` tags intended for deletion.
|
||||
|
||||
The event's `content` field MAY contain a text note describing the reason for the deletion.
|
||||
|
||||
@@ -21,6 +21,7 @@ For example:
|
||||
"tags": [
|
||||
["e", "dcd59..464a2"],
|
||||
["e", "968c5..ad7a4"],
|
||||
["a", "<kind>:<pubkey>:<d-identifier>"]
|
||||
],
|
||||
"content": "these posts were published by accident",
|
||||
...other fields
|
||||
|
||||
15
11.md
15
11.md
@@ -255,6 +255,18 @@ Relays that require payments may want to expose their fee schedules.
|
||||
}
|
||||
```
|
||||
|
||||
### Icon ###
|
||||
|
||||
A URL pointing to an image to be used as an icon for the relay. Recommended to be squared in shape.
|
||||
|
||||
```json
|
||||
{
|
||||
...
|
||||
"icon": "https://nostr.build/i/53866b44135a27d624e99c6165cabd76ac8f72797209700acb189fce75021f47.jpg",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### Examples ###
|
||||
As of 2 May 2023 the following `curl` command provided these results.
|
||||
|
||||
@@ -281,4 +293,5 @@ As of 2 May 2023 the following `curl` command provided these results.
|
||||
"payment_required":true},
|
||||
"payments_url":"https://eden.nostr.land/invoices",
|
||||
"fees":{"admission":[{"amount":5000000,"unit":"msats"}],
|
||||
"publication":[]}}
|
||||
"publication":[]}},
|
||||
"icon": "https://nostr.build/i/53866b44135a27d624e99c6165cabd76ac8f72797209700acb189fce75021f47.jpg"
|
||||
|
||||
4
15.md
4
15.md
@@ -38,8 +38,8 @@ A merchant can publish these events:
|
||||
| `0 ` | `set_meta` | The merchant description (similar with any `nostr` public key). | [NIP01 ](https://github.com/nostr-protocol/nips/blob/master/01.md) |
|
||||
| `30017` | `set_stall` | Create or update a stall. | [NIP33](https://github.com/nostr-protocol/nips/blob/master/33.md) (Parameterized Replaceable Event) |
|
||||
| `30018` | `set_product` | Create or update a product. | [NIP33](https://github.com/nostr-protocol/nips/blob/master/33.md) (Parameterized Replaceable Event) |
|
||||
| `4 ` | `direct_message` | Communicate with the customer. The messages can be plain-text or JSON. | [NIP09](https://github.com/nostr-protocol/nips/blob/master/09.md) |
|
||||
| `5 ` | `delete` | Delete a product or a stall. | [NIP05](https://github.com/nostr-protocol/nips/blob/master/05.md) |
|
||||
| `4 ` | `direct_message` | Communicate with the customer. The messages can be plain-text or JSON. | [NIP04](https://github.com/nostr-protocol/nips/blob/master/04.md) |
|
||||
| `5 ` | `delete` | Delete a product or a stall. | [NIP09](https://github.com/nostr-protocol/nips/blob/master/09.md) |
|
||||
|
||||
### Event `30017`: Create or update a stall.
|
||||
|
||||
|
||||
2
16.md
2
16.md
@@ -20,6 +20,8 @@ Upon a replaceable event with a newer timestamp than the currently known latest
|
||||
effectively replacing what gets returned when querying for
|
||||
`author:kind` tuples.
|
||||
|
||||
If two events have the same timestamp, the event with the lowest id (first in lexical order) SHOULD be retained, and the other discarded.
|
||||
|
||||
Ephemeral Events
|
||||
----------------
|
||||
An *ephemeral event* is defined as an event with a kind `20000 <= n < 30000`.
|
||||
|
||||
21
18.md
21
18.md
@@ -6,11 +6,10 @@ Reposts
|
||||
|
||||
`draft` `optional` `author:jb55` `author:fiatjaf` `author:arthurfranca`
|
||||
|
||||
A repost is a `kind 6` note that is used to signal to followers
|
||||
that another event is worth reading.
|
||||
A repost is a `kind 6` event that is used to signal to followers
|
||||
that a `kind 1` text note is worth reading.
|
||||
|
||||
The `content` of a repost event is empty. Optionally, it MAY contain
|
||||
the stringified JSON of the reposted note event for quick look up.
|
||||
The `content` of a repost event is _the stringified JSON of the reposted note_. It MAY also be empty, but that is not recommended.
|
||||
|
||||
The repost event MUST include an `e` tag with the `id` of the note that is
|
||||
being reposted. That tag MUST include a relay URL as its third entry
|
||||
@@ -21,5 +20,15 @@ reposted.
|
||||
|
||||
## Quote Reposts
|
||||
|
||||
Quote reposts are `kind 1` events with an embedded `e` tag (see [NIP-08](08.md) and [NIP-27](27.md)).
|
||||
Because a quote repost includes an `e` tag, it may show up along replies to the reposted note.
|
||||
Quote reposts are `kind 1` events with an embedded `e` tag
|
||||
(see [NIP-08](08.md) and [NIP-27](27.md)). Because a quote repost includes
|
||||
an `e` tag, it may show up along replies to the reposted note.
|
||||
|
||||
## Generic Reposts
|
||||
|
||||
Since `kind 6` reposts are reserved for `kind 1` contents, we use `kind 16`
|
||||
as a "generic repost", that can include any kind of event inside other than
|
||||
`kind 1`.
|
||||
|
||||
`kind 16` reposts SHOULD contain a `k` tag with the stringified kind number
|
||||
of the reposted event as its value.
|
||||
|
||||
2
23.md
2
23.md
@@ -6,7 +6,7 @@ Long-form Content
|
||||
|
||||
`draft` `optional` `author:fiatjaf`
|
||||
|
||||
This NIP defines `kind:30023` (a parameterized replaceable event according to [NIP-33](33.md)) for long-form text content, generally referred to as "articles" or "blog posts".
|
||||
This NIP defines `kind:30023` (a parameterized replaceable event according to [NIP-33](33.md)) for long-form text content, generally referred to as "articles" or "blog posts". `kind:30024` has the same structure as `kind:30023` and is used to save long form drafts.
|
||||
|
||||
"Social" clients that deal primarily with `kind:1` notes should not be expected to implement this NIP.
|
||||
|
||||
|
||||
8
26.md
8
26.md
@@ -1,4 +1,4 @@
|
||||
NIP: 26
|
||||
NIP-26
|
||||
=======
|
||||
|
||||
Delegated Event Signing
|
||||
@@ -52,7 +52,9 @@ For example, the following condition strings are valid:
|
||||
- `kind=0&kind=1&created_at>1675721813`
|
||||
- `kind=1&created_at>1674777689&created_at<1675721813`
|
||||
|
||||
For the vast majority of use-cases, it is advisable that query strings should include a `created_at` ***after*** condition reflecting the current time, to prevent the delegatee from publishing historic notes on the delegator's behalf.
|
||||
For the vast majority of use-cases, it is advisable that:
|
||||
1. Query strings should include a `created_at` ***after*** condition reflecting the current time, to prevent the delegatee from publishing historic notes on the delegator's behalf.
|
||||
2. Query strings should include a `created_at` ***before*** condition that is not empty and is not some extremely distant time in the future. If delegations are not limited in time scope, they expose similar security risks to simply using the root key for authentication.
|
||||
|
||||
#### Example
|
||||
|
||||
@@ -105,4 +107,4 @@ Clients should display the delegated note as if it was published directly by the
|
||||
|
||||
Relays should answer requests such as `["REQ", "", {"authors": ["A"]}]` by querying both the `pubkey` and delegation tags `[1]` value.
|
||||
|
||||
Relays SHOULD allow the delegator (8e0d3d3e) to delete the events published by the delegatee (477318cf).
|
||||
Relays SHOULD allow the delegator (8e0d3d3e) to delete the events published by the delegatee (477318cf).
|
||||
|
||||
2
28.md
2
28.md
@@ -37,7 +37,7 @@ In the channel creation `content` field, Client SHOULD include basic channel met
|
||||
|
||||
Update a channel's public metadata.
|
||||
|
||||
Clients and relays SHOULD handle kind 41 events similar to kind 0 `metadata` events.
|
||||
Clients and relays SHOULD handle kind 41 events similar to kind 33 replaceable events, where the information is used to update the metadata, without modifying the event id for the channel. Only the most recent kind 41 is needed to be stored.
|
||||
|
||||
Clients SHOULD ignore kind 41s from pubkeys other than the kind 40 pubkey.
|
||||
|
||||
|
||||
56
30.md
Normal file
56
30.md
Normal file
@@ -0,0 +1,56 @@
|
||||
NIP-30
|
||||
======
|
||||
|
||||
Custom Emoji
|
||||
------------
|
||||
|
||||
`draft` `optional` `author:alexgleason`
|
||||
|
||||
Custom emoji may be added to **kind 0** and **kind 1** events by including one or more `"emoji"` tags, in the form:
|
||||
|
||||
```
|
||||
["emoji", <shortcode>, <image-url>]
|
||||
```
|
||||
|
||||
Where:
|
||||
|
||||
- `<shortcode>` is a name given for the emoji, which MUST be comprised of only alphanumeric characters and underscores.
|
||||
- `<image-url>` is a URL to the corresponding image file of the emoji.
|
||||
|
||||
For each emoji tag, clients should parse emoji shortcodes (aka "emojify") like `:shortcode:` in the event to display custom emoji.
|
||||
|
||||
Clients may allow users to add custom emoji to an event by including `:shortcode:` identifier in the event, and adding the relevant `"emoji"` tags.
|
||||
|
||||
### Kind 0 events
|
||||
|
||||
In kind 0 events, the `name` and `about` fields should be emojified.
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 0,
|
||||
"content": "{\"name\":\"Alex Gleason :soapbox:\"}",
|
||||
"tags": [
|
||||
["emoji", "soapbox", "https://gleasonator.com/emoji/Gleasonator/soapbox.png"]
|
||||
],
|
||||
"pubkey": "79c2cae114ea28a981e7559b4fe7854a473521a8d22a66bbab9fa248eb820ff6",
|
||||
"created_at": 1682790000
|
||||
}
|
||||
```
|
||||
|
||||
### Kind 1 events
|
||||
|
||||
In kind 1 events, the `content` should be emojified.
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 1,
|
||||
"content": "Hello :gleasonator: 😂 :ablobcatrainbow: :disputed: yolo",
|
||||
"tags": [
|
||||
["emoji", "ablobcatrainbow", "https://gleasonator.com/emoji/blobcat/ablobcatrainbow.png"],
|
||||
["emoji", "disputed", "https://gleasonator.com/emoji/Fun/disputed.png"],
|
||||
["emoji", "gleasonator", "https://gleasonator.com/emoji/Gleasonator/gleasonator.png"]
|
||||
],
|
||||
"pubkey": "79c2cae114ea28a981e7559b4fe7854a473521a8d22a66bbab9fa248eb820ff6",
|
||||
"created_at": 1682630000
|
||||
}
|
||||
```
|
||||
15
31.md
Normal file
15
31.md
Normal file
@@ -0,0 +1,15 @@
|
||||
NIP-31
|
||||
======
|
||||
|
||||
Dealing with unknown event kinds
|
||||
--------------------------------
|
||||
|
||||
`draft` `optional` `author:pablof7z` `author:fiatjaf`
|
||||
|
||||
When creating a new custom event kind that is part of a custom protocol and isn't meant to be read as text (like `kind:1`), clients should use an `alt` tag to write a short human-readable plaintext summary of what that event is about.
|
||||
|
||||
The intent is that social clients, used to display only `kind:1` notes, can still show something in case a custom event pops up in their timelines. The content of the `alt` tag should provide enough context for a user that doesn't know anything about this event kind to understand what it is.
|
||||
|
||||
These clients that only know `kind:1` are not expected to ask relays for events of different kinds, but users could still reference these weird events on their notes, and without proper context these could be nonsensical notes. Having the fallback text makes that situation much better -- even if only for making the user aware that they should try to view that custom event elsewhere.
|
||||
|
||||
`kind:1`-centric clients can make interacting with these event kinds more functional by supporting [NIP-89](https://github.com/nostr-protocol/nips/blob/master/89.md).
|
||||
126
32.md
Normal file
126
32.md
Normal file
@@ -0,0 +1,126 @@
|
||||
NIP-32
|
||||
======
|
||||
|
||||
Labeling
|
||||
---------
|
||||
|
||||
`draft` `optional` `author:staab` `author:gruruya` `author:s3x-jay`
|
||||
|
||||
A label is a `kind 1985` event that is used to label other entities. This supports a number of use cases, from distributed moderation and content recommendations to reviews and ratings.
|
||||
|
||||
Label Target
|
||||
----
|
||||
|
||||
The label event MUST include one or more tags representing the object or objects being
|
||||
labeled: `e`, `p`, `a`, `r`, or `t` tags. This allows for labeling of events, people, relays,
|
||||
or topics respectively. As with NIP-01, a relay hint SHOULD be included when using `e` and
|
||||
`p` tags.
|
||||
|
||||
Label Tag
|
||||
----
|
||||
|
||||
This NIP introduces a new tag `l` which denotes a label, and a new `L` tag which denotes a label namespace.
|
||||
A label MUST include a mark matching an `L` tag. `L` tags refer to a tag type within nostr, or a nomenclature
|
||||
external to nostr defined either formally or by convention. Any string can be a namespace, but publishers SHOULD
|
||||
ensure they are unambiguous by using a well-defined namespace (such as an ISO standard) or reverse domain name notation.
|
||||
|
||||
Namespaces starting with `#` indicate that the label target should be associated with the label's value.
|
||||
This is a way of attaching standard nostr tags to events, pubkeys, relays, urls, etc.
|
||||
|
||||
Some examples:
|
||||
|
||||
- `["l", "footstr", "#t"]` - the publisher thinks the given entity should have the `footstr` topic applied.
|
||||
- `["l", "<pubkey>", "#p"]` - the publisher thinks the given entity is related to `<pubkey>`
|
||||
- `["l", "IT-MI", "ISO-3166-2"]` - Milano, Italy using ISO 3166-2.
|
||||
- `["l", "VI-hum", "com.example.ontology"]` - Violence toward a human being as defined by ontology.example.com.
|
||||
|
||||
`L` tags containing the label namespaces MUST be included in order to support searching by
|
||||
namespace rather than by a specific tag. The special `ugc` ("user generated content") namespace
|
||||
MAY be used when the label content is provided by an end user.
|
||||
|
||||
`l` and `L` tags MAY be added to other event kinds to support self-reporting. For events
|
||||
with a kind other than 1985, labels refer to the event itself.
|
||||
|
||||
Label Annotations
|
||||
-----
|
||||
|
||||
A label tag MAY include a 4th positional element detailing extra metadata about the label in question. This string
|
||||
should be a json-encoded object. Any key MAY be used, but the following are recommended:
|
||||
|
||||
- `quality` may have a value of 0 to 1. This allows for an absolute, granular scale that can be represented in any way (5 stars, color scale, etc).
|
||||
- `confidence` may have a value of 0 to 1. This indicates the certainty which the author has about their rating.
|
||||
- `context` may be an array of urls (including NIP-21 urls) indicating other context that should be considered when interpreting labels.
|
||||
|
||||
Content
|
||||
-------
|
||||
|
||||
Labels should be short, meaningful strings. Longer discussions, such as for a review, or an
|
||||
explanation of why something was labeled the way it was, should go in the event's `content` field.
|
||||
|
||||
Example events
|
||||
--------------
|
||||
|
||||
A suggestion that multiple pubkeys be associated with the `permies` topic.
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 1985,
|
||||
"tags": [
|
||||
["L", "#t"],
|
||||
["l", "permies", "#t"],
|
||||
["p", <pubkey1>, <relay_url>],
|
||||
["p", <pubkey2>, <relay_url>]
|
||||
],
|
||||
"content": "",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
A review of a relay.
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 1985,
|
||||
"tags": [
|
||||
["L", "com.example.ontology"],
|
||||
["l", "relay/review", "com.example.ontology", "{\"quality\": 0.1}"],
|
||||
["r", <relay_url>]
|
||||
],
|
||||
"content": "This relay is full of mean people.",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Publishers can self-label by adding `l` tags to their own non-1985 events.
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 1,
|
||||
"tags": [
|
||||
["L", "com.example.ontology"],
|
||||
["l", "IL-frd", "com.example.ontology"]
|
||||
],
|
||||
"content": "Send me 100 sats and I'll send you 200 back",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Other Notes
|
||||
-----------
|
||||
|
||||
When using this NIP to bulk-label many targets at once, events may be deleted and a replacement
|
||||
may be published. We have opted not to use parameterizable/replaceable events for this due to the
|
||||
complexity in coming up with a standard `d` tag. In order to avoid ambiguity when querying,
|
||||
publishers SHOULD limit labeling events to a single namespace.
|
||||
|
||||
Before creating a vocabulary, explore how your use case may have already been designed and
|
||||
imitate that design if possible. Reverse domain name notation is encouraged to avoid
|
||||
namespace clashes, but for the sake of interoperability all namespaces should be
|
||||
considered open for public use, and not proprietary. In other words, if there is a
|
||||
namespace that fits your use case, use it even if it points to someone else's domain name.
|
||||
|
||||
Vocabularies MAY choose to fully qualify all labels within a namespace (for example,
|
||||
`["l", "com.example.vocabulary:my-label"]`. This may be preferred when defining more
|
||||
formal vocabularies that should not be confused with another namespace when querying
|
||||
without an `L` tag. For these vocabularies, all labels SHOULD include the namespace
|
||||
(rather than mixing qualified and unqualified labels).
|
||||
4
33.md
4
33.md
@@ -10,7 +10,7 @@ This NIP adds a new event range that allows for replacement of events that have
|
||||
|
||||
Implementation
|
||||
--------------
|
||||
The value of a tag is defined as the first parameter of a tag after the tag name.
|
||||
The value of a tag can be any string and is defined as the first parameter of a tag after the tag name.
|
||||
|
||||
A *parameterized replaceable event* is defined as an event with a kind `30000 <= n < 40000`.
|
||||
Upon a parameterized replaceable event with a newer timestamp than the currently known latest
|
||||
@@ -18,6 +18,8 @@ replaceable event with the same kind, author and first `d` tag value being recei
|
||||
SHOULD be discarded, effectively replacing what gets returned when querying for
|
||||
`author:kind:d-tag` tuples.
|
||||
|
||||
If two events have the same timestamp, the event with the lowest id (first in lexical order) SHOULD be retained, and the other discarded.
|
||||
|
||||
A missing or a `d` tag with no value should be interpreted equivalent to a `d` tag with the
|
||||
value as an empty string. Events from the same author with any of the following `tags`
|
||||
replace each other:
|
||||
|
||||
9
36.md
9
36.md
@@ -9,12 +9,15 @@ Sensitive Content / Content Warning
|
||||
The `content-warning` tag enables users to specify if the event's content needs to be approved by readers to be shown.
|
||||
Clients can hide the content until the user acts on it.
|
||||
|
||||
`l` and `L` tags MAY be also be used as defined in [NIP-32](32.md) with the `content-warning` or other namespace to support
|
||||
further qualification and querying.
|
||||
|
||||
#### Spec
|
||||
|
||||
```
|
||||
tag: content-warning
|
||||
options:
|
||||
- [reason]: optional
|
||||
- [reason]: optional
|
||||
```
|
||||
|
||||
#### Example
|
||||
@@ -26,6 +29,10 @@ options:
|
||||
"kind": 1,
|
||||
"tags": [
|
||||
["t", "hastag"],
|
||||
["L", "content-warning"],
|
||||
["l", "reason", "content-warning"],
|
||||
["L", "social.nos.ontology"],
|
||||
["l", "NS-nud", "social.nos.ontology"],
|
||||
["content-warning", "reason"] /* reason is optional */
|
||||
],
|
||||
"content": "sensitive content with #hastag\n",
|
||||
|
||||
95
37.md
Normal file
95
37.md
Normal file
@@ -0,0 +1,95 @@
|
||||
NIP-37
|
||||
======
|
||||
|
||||
Methods for dealing with lost or compromised keys
|
||||
-------------------------------------------------
|
||||
|
||||
`draft` `optional` `author:fiatjaf`
|
||||
|
||||
This NIP defines a series of methods that can be used to make catastrophic key loss events less horrible.
|
||||
|
||||
The intention here is not to claim that there is a generalized "key rotation" scheme on Nostr, but still make it
|
||||
so that in most cases people are able to move to new keys and not lost 100% of their followers and reputation
|
||||
when that happens, and also that it is possible to prevent most of the reputational damage that could be
|
||||
caused by having an evil hacker take control of someone else's keys.
|
||||
|
||||
The implementation of this NIP could be done directly in social clients or in dedicated clients that users would
|
||||
visit from time to time in order to have an automated scan be done on their contacts and then the dedicated app
|
||||
could suggest migrating from old keys to new keys, or suggest stop following compromised keys, or even perform
|
||||
these migrations automatically.
|
||||
|
||||
### Method A: Simple Key Deletion
|
||||
|
||||
Based on https://github.com/nostr-protocol/nips/pull/377, the idea is that someone, after noticing that their key
|
||||
has been compromised and deciding that it is not possible to use any of the other methods here described, can
|
||||
proceed to publish the following event:
|
||||
|
||||
```js
|
||||
{
|
||||
"kind": 10529,
|
||||
"pubkey": "<compromised-pubkey>",
|
||||
"tags": [
|
||||
["reason", "I typed my key on anigma"]
|
||||
|
||||
// this is unnecessary, but it's an extra requirement to prevent people from making a 10529 event by chance
|
||||
["key-compromised"],
|
||||
],
|
||||
"content": "",
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Upon receiving this, relays implementing this NIP SHOULD somehow mark it as invalid and refuse to store any more
|
||||
events from this key. Relays MAY also decide to also delete all events from this key.
|
||||
|
||||
Upon receiving this, clients implementing this NIP SHOULD stop following the key.
|
||||
|
||||
Clients may give users the option to "delete your public key" with this type of event. Clients SHOULD display a
|
||||
prominent message explaining that the action is not reversible, SHOULD explain that this does not guarantee their
|
||||
posts are deleted forever, and SHOULD require special confirmation such as requiring the user to type a message.
|
||||
|
||||
### Method B: Social Key Migration
|
||||
|
||||
The idea here is that users could pick some friends from their contact list and a threshold number to signal to
|
||||
the rest that the old key has been lost and what is the new key -- e.g. Alice can determine that, from Bob, Carol
|
||||
and Derek, if any 2 of these 3 agree, their recommendation is authoritative.
|
||||
|
||||
This is done by publishing an event like this (for example):
|
||||
|
||||
```js
|
||||
{
|
||||
"kind": 10520,
|
||||
"pubkey": "<user-pubkey-that-will-be-compromised>",
|
||||
"tags": [
|
||||
["p", "<friend1-pubkey>"],
|
||||
["p", "<friend2-pubkey>"],
|
||||
["p", "<friend3-pubkey>"],
|
||||
["threshold", "2"]
|
||||
],
|
||||
"content": "",
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
And then, when the friends want to recommend the switch to a new pubkey, they can publish events like
|
||||
|
||||
```js
|
||||
{
|
||||
"kind": 1521,
|
||||
"pubkey": "<friend1-pubkey>",
|
||||
"tags": [
|
||||
["p", "<compromised-pubkey>"],
|
||||
["e", "<event-of-kind-10520-that-this-refers-to>"],
|
||||
["new-key", "<new-key>"]
|
||||
],
|
||||
"content": "",
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Very importantly, when evaluating events of kind `1521` for a given `p`, clients should ensure that their corresponding
|
||||
event `10520` is at least 3 months older **and that an OpenTimestamps proof exists for that**.
|
||||
|
||||
### Method C: Hierarchically Pregenerated Keys
|
||||
|
||||
I'll write this later, just a placeholder. It's probably better to see if methods A and B work first.
|
||||
6
47.md
6
47.md
@@ -33,7 +33,7 @@ There are three event kinds:
|
||||
- `NIP-47 response`: 23195
|
||||
|
||||
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
|
||||
a plaintext string with the supported commands, space-seperated, eg. `pay_invoice get_balance`. Only the `pay_invoice` command is described in this NIP, but other commands might be defined in different NIPs.
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
@@ -64,8 +64,8 @@ Response:
|
||||
```
|
||||
|
||||
The `result_type` field MUST contain the name of the method that this event is responding to.
|
||||
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 succesful.
|
||||
If the command was succesful, the `error` field must be null.
|
||||
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.
|
||||
|
||||
### Error codes
|
||||
- `RATE_LIMITED`: The client is sending commands too fast. It should retry in a few seconds.
|
||||
|
||||
15
56.md
15
56.md
@@ -32,6 +32,9 @@ being reported, which consists of the following report types:
|
||||
|
||||
Some report tags only make sense for profile reports, such as `impersonation`
|
||||
|
||||
`l` and `L` tags MAY be also be used as defined in [NIP-32](32.md) to support
|
||||
further qualification and querying.
|
||||
|
||||
Example events
|
||||
--------------
|
||||
|
||||
@@ -39,7 +42,9 @@ Example events
|
||||
{
|
||||
"kind": 1984,
|
||||
"tags": [
|
||||
[ "p", <pubkey>, "nudity"]
|
||||
["p", <pubkey>, "nudity"]
|
||||
["L", "social.nos.ontology"],
|
||||
["l", "NS-nud", "social.nos.ontology"],
|
||||
],
|
||||
"content": "",
|
||||
...
|
||||
@@ -48,8 +53,8 @@ Example events
|
||||
{
|
||||
"kind": 1984,
|
||||
"tags": [
|
||||
[ "e", <eventId>, "illegal"],
|
||||
[ "p", <pubkey>]
|
||||
["e", <eventId>, "illegal"],
|
||||
["p", <pubkey>]
|
||||
],
|
||||
"content": "He's insulting the king!",
|
||||
...
|
||||
@@ -58,8 +63,8 @@ Example events
|
||||
{
|
||||
"kind": 1984,
|
||||
"tags": [
|
||||
[ "p", <impersonator pubkey>, "impersonation"],
|
||||
[ "p", <victim pubkey>]
|
||||
["p", <impersonator pubkey>, "impersonation"],
|
||||
["p", <victim pubkey>]
|
||||
],
|
||||
"content": "Profile is imitating #[1]",
|
||||
...
|
||||
|
||||
44
57.md
44
57.md
@@ -6,21 +6,21 @@ Lightning Zaps
|
||||
|
||||
`draft` `optional` `author:jb55` `author:kieran`
|
||||
|
||||
This NIP defines two new event types for recording lightning payments between users. `9734` is a `zap request`, representing a payer's request to a recipient's lightning wallet for an invoice. `9735` is a `zap receipt`, representing the confirmation by the recipient's lightning wallet that the invoice issued in response to a zap request has been paid.
|
||||
This NIP defines two new event types for recording lightning payments between users. `9734` is a `zap request`, representing a payer's request to a recipient's lightning wallet for an invoice. `9735` is a `zap receipt`, representing the confirmation by the recipient's lightning wallet that the invoice issued in response to a `zap request` has been paid.
|
||||
|
||||
Having lightning receipts on nostr allows clients to display lightning payments from entities on the network. These can be used for fun or for spam deterrence.
|
||||
|
||||
## Protocol flow
|
||||
|
||||
1. Client calculates a recipient's lnurl pay request url from the `zap` tag on the event being zapped (see Appendix G), or by decoding their lud06 or lud16 field on their profile according to the [lnurl specifications](https://github.com/lnurl/luds). The client MUST send a GET request to this url and parse the response. If `allowsNostr` exists and it is `true`, and if `nostrPubkey` exists and is a valid BIP 340 public key in hex, the client should associate this information with the user, along with the response's `callback`, `minSendable`, and `maxSendable` values.
|
||||
2. Clients may choose to display a lightning zap button on each post or on a user's profile. If the user's lnurl pay request endpoint supports nostr, the client SHOULD use this NIP to request a zap receipt rather than a normal lnurl invoice.
|
||||
2. Clients may choose to display a lightning zap button on each post or on a user's profile. If the user's lnurl pay request endpoint supports nostr, the client SHOULD use this NIP to request a `zap receipt` rather than a normal lnurl invoice.
|
||||
3. When a user (the "sender") indicates they want to send a zap to another user (the "recipient"), the client should create a `zap request` event as described in Appendix A of this NIP and sign it.
|
||||
4. Instead of publishing the `zap request`, the `9734` event should instead be sent to the `callback` url received from the lnurl pay endpoint for the recipient using a GET request. See Appendix B for details and an example.
|
||||
5. The recipient's lnurl server will receive this request and validate it. See Appendix C for details on how to properly configure an lnurl server to support zaps, and Appendix D for details on how to validate the `nostr` query parameter.
|
||||
6. If the request is valid, the server should fetch a description hash invoice where the description is this note and this note only. No additional lnurl metadata is included in the description. This will be returned in the response according to [LUD06](https://github.com/lnurl/luds/blob/luds/06.md).
|
||||
5. The recipient's lnurl server will receive this `zap request` and validate it. See Appendix C for details on how to properly configure an lnurl server to support zaps, and Appendix D for details on how to validate the `nostr` query parameter.
|
||||
6. If the `zap request` is valid, the server should fetch a description hash invoice where the description is this `zap request` note and this note only. No additional lnurl metadata is included in the description. This will be returned in the response according to [LUD06](https://github.com/lnurl/luds/blob/luds/06.md).
|
||||
7. On receiving the invoice, the client MAY pay it or pass it to an app that can pay the invoice.
|
||||
8. Once the invoice is paid, the recipient's lnurl server MUST generate a `zap receipt` as described in Appendix E, and publish it to the `relays` specified in the `zap request`.
|
||||
9. Clients MAY fetch zap notes on posts and profiles, but MUST authorize their validity as described in Appendix F. If the zap request note contains a non-empty `content`, it may display a zap comment. Generally clients should show users the `zap request` note, and use the `zap note` to show "zap authorized by ..." but this is optional.
|
||||
9. Clients MAY fetch `zap receipt`s on posts and profiles, but MUST authorize their validity as described in Appendix F. If the `zap request` note contains a non-empty `content`, it may display a zap comment. Generally clients should show users the `zap request` note, and use the `zap receipt` to show "zap authorized by ..." but this is optional.
|
||||
|
||||
## Reference and examples
|
||||
|
||||
@@ -60,10 +60,10 @@ Example:
|
||||
|
||||
### Appendix B: Zap Request HTTP Request
|
||||
|
||||
A signed zap request event is not published, but is instead sent using a HTTP GET request to the recipient's `callback` url, which was provided by the recipient's lnurl pay endpoint. This request should have the following query parameters defined:
|
||||
A signed `zap request` event is not published, but is instead sent using a HTTP GET request to the recipient's `callback` url, which was provided by the recipient's lnurl pay endpoint. This request should have the following query parameters defined:
|
||||
|
||||
- `amount` is the amount in _millisats_ the sender intends to pay
|
||||
- `nostr` is the `9734` zap request event, JSON encoded then URI encoded
|
||||
- `nostr` is the `9734` `zap request` event, JSON encoded then URI encoded
|
||||
- `lnurl` is the lnurl pay url of the recipient, encoded using bech32 with the prefix `lnurl`
|
||||
|
||||
This request should return a JSON response with a `pr` key, which is the invoice the sender must pay to finalize his zap. Here is an example flow:
|
||||
@@ -97,18 +97,18 @@ const {pr: invoice} = await fetchJson(`${callback}?amount=${amount}&nostr=${even
|
||||
|
||||
The lnurl server will need some additional pieces of information so that clients can know that zap invoices are supported:
|
||||
|
||||
1. Add a `nostrPubkey` to the lnurl-pay static endpoint `/.well-known/lnurlp/<user>`, where `nostrPubkey` is the nostr pubkey your server will use to sign `zap receipt` events. Clients will use this to validate zap receipts.
|
||||
1. Add a `nostrPubkey` to the lnurl-pay static endpoint `/.well-known/lnurlp/<user>`, where `nostrPubkey` is the nostr pubkey your server will use to sign `zap receipt` events. Clients will use this to validate `zap receipt`s.
|
||||
2. Add an `allowsNostr` field and set it to true.
|
||||
|
||||
### Appendix D: LNURL Server Zap Request Validation
|
||||
|
||||
When a client sends a zap request event to a server's lnurl-pay callback URL, there will be a `nostr` query parameter where the contents of the event are URI- and JSON-encoded. If present, the zap request event must be validated in the following ways:
|
||||
When a client sends a `zap request` event to a server's lnurl-pay callback URL, there will be a `nostr` query parameter whose value is that event which is URI- and JSON-encoded. If present, the `zap request` event must be validated in the following ways:
|
||||
|
||||
1. It MUST have a valid nostr signature
|
||||
2. It MUST have tags
|
||||
3. It MUST have only one `p` tag
|
||||
4. It MUST have 0 or 1 `e` tags
|
||||
5. There should be a `relays` tag with the relays to send the `zap` note to.
|
||||
5. There should be a `relays` tag with the relays to send the `zap receipt` to.
|
||||
6. If there is an `amount` tag, it MUST be equal to the `amount` query parameter.
|
||||
7. If there is an `a` tag, it MUST be a valid NIP-33 event coordinate
|
||||
|
||||
@@ -116,29 +116,29 @@ The event MUST then be stored for use later, when the invoice is paid.
|
||||
|
||||
### Appendix E: Zap Receipt Event
|
||||
|
||||
A `zap receipt` is created by a lightning node when an invoice generated by a `zap request` is paid. Zap receipts are only created when the invoice description (committed to the description hash) contains a zap request note.
|
||||
A `zap receipt` is created by a lightning node when an invoice generated by a `zap request` is paid. `Zap receipt`s are only created when the invoice description (committed to the description hash) contains a `zap request` note.
|
||||
|
||||
When receiving a payment, the following steps are executed:
|
||||
|
||||
1. Get the description for the invoice. This needs to be saved somewhere during the generation of the description hash invoice. It is saved automatically for you with CLN, which is the reference implementation used here.
|
||||
2. Parse the bolt11 description as a JSON nostr event. This SHOULD be validated based on the requirements in Appendix D, either when it is received, or before the invoice is paid.
|
||||
3. Create a nostr event of kind `9735` as described below, and publish it to the `relays` declared in the zap request.
|
||||
3. Create a nostr event of kind `9735` as described below, and publish it to the `relays` declared in the `zap request`.
|
||||
|
||||
The following should be true of the zap receipt event:
|
||||
The following should be true of the `zap receipt` event:
|
||||
|
||||
- The content SHOULD be empty.
|
||||
- The `created_at` date SHOULD be set to the invoice `paid_at` date for idempotency.
|
||||
- `tags` MUST include the `p` tag AND optional `e` tag from the zap request.
|
||||
- The zap receipt MUST have a `bolt11` tag containing the description hash bolt11 invoice.
|
||||
- The zap receipt MUST contain a `description` tag which is the JSON-encoded invoice description.
|
||||
- `tags` MUST include the `p` tag AND optional `e` tag from the `zap request`.
|
||||
- The `zap receipt` MUST have a `bolt11` tag containing the description hash bolt11 invoice.
|
||||
- The `zap receipt` MUST contain a `description` tag which is the JSON-encoded invoice description.
|
||||
- `SHA256(description)` MUST match the description hash in the bolt11 invoice.
|
||||
- The zap receipt MAY contain a `preimage` tag to match against the payment hash of the bolt11 invoice. This isn't really a payment proof, there is no real way to prove that the invoice is real or has been paid. You are trusting the author of the zap receipt for the legitimacy of the payment.
|
||||
- The `zap receipt` MAY contain a `preimage` tag to match against the payment hash of the bolt11 invoice. This isn't really a payment proof, there is no real way to prove that the invoice is real or has been paid. You are trusting the author of the `zap receipt` for the legitimacy of the payment.
|
||||
|
||||
The zap receipt is not a proof of payment, all it proves is that some nostr user fetched an invoice. The existence of the zap receipt implies the invoice as paid, but it could be a lie given a rogue implementation.
|
||||
The `zap receipt` is not a proof of payment, all it proves is that some nostr user fetched an invoice. The existence of the `zap receipt` implies the invoice as paid, but it could be a lie given a rogue implementation.
|
||||
|
||||
A reference implementation for a zap-enabled lnurl server can be found [here](https://github.com/jb55/cln-nostr-zapper).
|
||||
|
||||
Example zap receipt:
|
||||
Example `zap receipt`:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -160,7 +160,7 @@ Example zap receipt:
|
||||
|
||||
### Appendix F: Validating Zap Receipts
|
||||
|
||||
A client can retrieve `zap receipts` on events and pubkeys using a NIP-01 filter, for example `{"kinds": [9735], "#e": [...]}`. Zaps MUST be validated using the following steps:
|
||||
A client can retrieve `zap receipt`s on events and pubkeys using a NIP-01 filter, for example `{"kinds": [9735], "#e": [...]}`. Zaps MUST be validated using the following steps:
|
||||
|
||||
- The `zap receipt` event's `pubkey` MUST be the same as the recipient's lnurl provider's `nostrPubkey` (retrieved in step 1 of the protocol flow).
|
||||
- The `invoiceAmount` contained in the `bolt11` tag of the `zap receipt` MUST equal the `amount` tag of the `zap request` (if present).
|
||||
@@ -168,7 +168,7 @@ A client can retrieve `zap receipts` on events and pubkeys using a NIP-01 filter
|
||||
|
||||
### Appendix G: `zap` tag on zapped event
|
||||
|
||||
When an event includes a `zap` tag, clients SHOULD calculate the lnurl pay request based on it's value instead of the profile's field. An optional third argument on the tag specifies the type of value, either `lud06` or `lud16`.
|
||||
When an event includes a `zap` tag, clients SHOULD calculate the lnurl pay request based on its value instead of the profile's field. An optional third argument on the tag specifies the type of value, either `lud06` or `lud16`.
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -180,4 +180,4 @@ When an event includes a `zap` tag, clients SHOULD calculate the lnurl pay reque
|
||||
|
||||
## Future Work
|
||||
|
||||
Zaps can be extended to be more private by encrypting zap request notes to the target user, but for simplicity it has been left out of this initial draft.
|
||||
Zaps can be extended to be more private by encrypting `zap request` notes to the target user, but for simplicity it has been left out of this initial draft.
|
||||
|
||||
116
89.md
Normal file
116
89.md
Normal file
@@ -0,0 +1,116 @@
|
||||
NIP-89
|
||||
======
|
||||
|
||||
Recommended Application Handlers
|
||||
--------------------------------
|
||||
|
||||
`draft` `optional` `author:pablof7z`
|
||||
|
||||
This NIP describes `kind:31989` and `kind:31990`: a way to discover applications that can handle unknown event-kinds.
|
||||
|
||||
## Rationale
|
||||
Nostr's discoverability and transparent event interaction is one of its most interesting/novel mechanics.
|
||||
This NIP provides a simple way for clients to discover applications that handle events of a specific kind to ensure smooth cross-client and cross-kind interactions.
|
||||
|
||||
### Parties involved
|
||||
There are three actors to this workflow:
|
||||
|
||||
* application that handles a specific event kind (note that an application doesn't necessarily need to be a distinct entity and it could just be the same pubkey as user A)
|
||||
* Publishes `kind:31990`, detailing how apps should redirect to it
|
||||
* user A, who recommends an app that handles a specific event kind
|
||||
* Publishes `kind:31989`
|
||||
* user B, who seeks a recommendation for an app that handles a specific event kind
|
||||
* Queries for `kind:31989` and, based on results, queries for `kind:31990`
|
||||
|
||||
# Events
|
||||
|
||||
## Recommendation event
|
||||
```json
|
||||
{
|
||||
"kind": 31989,
|
||||
"pubkey": <recommender-user-pubkey>,
|
||||
"tags": [
|
||||
[ "d", <supported-event-kind> ],
|
||||
[ "a", "31990:app1-pubkey:<d-identifier>", "wss://relay1", "ios" ],
|
||||
[ "a", "31990:app2-pubkey:<d-identifier>", "wss://relay2", "web" ]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The `d` tag in `kind:31989` is the supported event kind this event is recommending.
|
||||
|
||||
Multiple `a` tags can appear on the same `kind:31989`.
|
||||
|
||||
The second value of the tag SHOULD be a relay hint.
|
||||
The third value of the tag SHOULD be the platform where this recommendation might apply.
|
||||
|
||||
## Handler information
|
||||
```json
|
||||
{
|
||||
"kind": 31990,
|
||||
"pubkey": <pubkey>,
|
||||
"content": "<optional-kind:0-style-metadata>",
|
||||
"tags": [
|
||||
[ "d", <random-id> ],
|
||||
[ "k", <supported-event-kind> ],
|
||||
[ "web", "https://..../a/<bech32>", "nevent" ],
|
||||
[ "web", "https://..../p/<bech32>", "nprofile" ],
|
||||
[ "web", "https://..../e/<bech32>" ],
|
||||
[ "ios", ".../<bech32>" ]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
* `content` is an optional `set_metadata`-like stringified JSON object, as described in NIP-01. This content is useful when the pubkey creating the `kind:31990` is not an application. If `content` is empty, the `kind:0` of the pubkey should be used to display application information (e.g. name, picture, web, LUD16, etc.)
|
||||
|
||||
* `k` tags' value is the event kind that is supported by this `kind:31990`.
|
||||
Using a `k` tag(s) (instead of having the kind onf the NIP-33 `d` tag) provides:
|
||||
* Multiple `k` tags can exist in the same event if the application supports more than one event kind and their handler URLs are the same.
|
||||
* The same pubkey can have multiple events with different apps that handle the same event kind.
|
||||
|
||||
* `bech32` in a URL MUST be replaced by clients with the NIP-19-encoded entity that should be loaded by the application.
|
||||
|
||||
Multiple tags might be registered by the app, following NIP-19 nomenclature as the second value of the array.
|
||||
|
||||
A tag without a second value in the array SHOULD be considered a generic handler for any NIP-19 entity that is not handled by a different tag.
|
||||
|
||||
# User flow
|
||||
A user A who uses a non-`kind:1`-centric nostr app could choose to announce/recommend a certain kind-handler application.
|
||||
|
||||
When user B sees an unknown event kind, e.g. in a social-media centric nostr client, the client would allow user B to interact with the unknown-kind event (e.g. tapping on it).
|
||||
|
||||
The client MIGHT query for the user's and the user's follows handler.
|
||||
|
||||
# Example
|
||||
|
||||
## User A recommends a `kind:31337`-handler
|
||||
User A might be a user of Zapstr, a `kind:31337`-centric client (tracks). Using Zapstr, user A publishes an event recommending Zapstr as a `kind:31337`-handler.
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 31989,
|
||||
"tags": [
|
||||
[ "d", "31337" ],
|
||||
[ "a", "31990:1743058db7078661b94aaf4286429d97ee5257d14a86d6bfa54cb0482b876fb0:abcd", <relay-url>, "web" ]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## User B interacts with a `kind:31337`-handler
|
||||
User B might see in their timeline an event referring to a `kind:31337` event
|
||||
(e.g. a `kind:1` tagging a `kind:31337`).
|
||||
|
||||
User B's client, not knowing how to handle a `kind:31337` might display the event
|
||||
using its `alt` tag (as described in NIP-31). When the user clicks on the event,
|
||||
the application queries for a handler for this `kind`:
|
||||
|
||||
`["REQ", <id>, '[{ "kinds": [31989], "#d": ["31337"], 'authors': [<user>, <users-contact-list>] }]']`
|
||||
|
||||
User B, who follows User A, sees that `kind:31989` event and fetches the `a`-tagged event for the app and handler information.
|
||||
|
||||
User B's client sees the application's `kind:31990` which includes the information to redirect the user to the relevant URL with the desired entity replaced in the URL.
|
||||
|
||||
## Alternative query bypassing `kind:31989`
|
||||
Alternatively, users might choose to query directly for `kind:31990` for an event kind. Clients SHOULD be careful doing this and use spam-prevention mechanisms to avoid directing users to malicious handlers.
|
||||
|
||||
`["REQ", <id>, '[{ "kinds": [31990], "#k": [<desired-event-kind>], 'authors': [...] }]']`
|
||||
180
93.md
180
93.md
@@ -1,180 +0,0 @@
|
||||
NIP-93
|
||||
======
|
||||
|
||||
NSON
|
||||
----
|
||||
|
||||
`draft` `optional` `author:fiatjaf`
|
||||
|
||||
### Preamble
|
||||
|
||||
Some [benchmarks](https://github.com/fiatjaf/nostr-json-benchmarks/tree/2f254fff91b3ad063ef9726bb4a3d25316cf12d8) made using all libraries available on Golang show that JSON decoding is very slow. And even when people do assembly-level optimizations things only improve up to a point (e.g. for decoding a Nostr event, the "Sonic" library uses about 50% of that of the standard library).
|
||||
|
||||
Meanwhile, doing a simple TLV encoding reduces the decoding time to 35% and a simpler static binary format for Nostr events makes that number drop to 4%. However, it would be bad for Nostr if a binary encoding was introduced, as it would be likely to cause compatibility issues, centralize the protocol and/or increase the work for everybody, more about this in [this comment](https://github.com/nostr-protocol/nips/pull/512#issuecomment-1542368664).
|
||||
|
||||
### The actual NIP
|
||||
|
||||
NSON is a crazy idea that, according to the benchmarks above, reduces the decoding time to 14% of that of the standard library. It works by having the JSON sender encode the event _as JSON_, but in a specific, very strict, order of fields (taking advantage of the fact that Nostr events have static fields, static lengths for some fields, and an overall rigid structure) and include in the JSON object a new field called `"nson"` that contains metadata the JSON receiver can read to help in the decoding process.
|
||||
|
||||
Here's an example of a NSON-encoded Nostr event:
|
||||
|
||||
`{"id":"57ff66490a6a2af3992accc26ae95f3f60c6e5f84ed0ddf6f59c534d3920d3d2","pubkey":"79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798","sig":"504d142aed7fa7e0f6dab5bcd7eed63963b0277a8e11bbcb03b94531beb4b95a12f1438668b02746bd5362161bc782068e6b71494060975414e793f9e19f57ea","created_at":1683762317,"nson":"2801000b0203000100400005040001004000000014","kind":1,"content":"hello world","tags":[["e","b6de44a9dd47d1c000f795ea0453046914f44ba7d5e369608b04867a575ea83e","reply"],["p","c26f7b252cea77a5b94f42b1a4771021be07d4df766407e47738605f7e3ab774","","wss://relay.damus.io"]]}`
|
||||
|
||||
The idea is that `"id"` comes first, so it can be accessed by reading a slice of the string from character `7` to character `71`, `pubkey` from character `83` to `147` and so on. `"content"`, `"kind"` and `"tags"` have dynamic sizes, so their sizes are given by the values inside the `"nson"` field (which is also dynamic, its size given by its first byte).
|
||||
|
||||
### Anatomy of the `"nson"` field
|
||||
|
||||
It is hex-encoded. Some fields are a single byte, others are two bytes (4 characters), big-endian.
|
||||
|
||||
tt: number of tags (let's say it's two)
|
||||
nn: number of items on the first tag (let's say it's 3)
|
||||
1111: number of chars on the first item
|
||||
2222: number of chars on the second item
|
||||
3333: number of chars on the third item
|
||||
nn: number of items on the second tag (let's say it's 2)
|
||||
1111: number of chars on the first item
|
||||
2222: number of chars on the second item
|
||||
"nson":"xxkkccccttnn111122223333nn11112222"
|
||||
xx: nson size
|
||||
kk: kind chars
|
||||
cccc: content chars
|
||||
|
||||
### Reference implementation
|
||||
|
||||
```go
|
||||
func decodeNson(data string) *Event {
|
||||
evt := &Event{}
|
||||
|
||||
// static fields
|
||||
evt.ID = data[7 : 7+64]
|
||||
evt.PubKey = data[83 : 83+64]
|
||||
evt.Sig = data[156 : 156+128]
|
||||
ts, _ := strconv.ParseInt(data[299:299+10], 10, 64)
|
||||
evt.CreatedAt = Timestamp(ts)
|
||||
|
||||
// nson values
|
||||
nsonSizeBytes, _ := hex.DecodeString(data[318 : 318+2])
|
||||
nsonSize := int(nsonSizeBytes[0])
|
||||
nsonDescriptors, _ := hex.DecodeString(data[320 : 320+nsonSize])
|
||||
|
||||
// dynamic fields
|
||||
// kind
|
||||
kindChars := int(nsonDescriptors[0])
|
||||
kindStart := 320 + nsonSize + 9 // len(`","kind":`)
|
||||
evt.Kind, _ = strconv.Atoi(data[kindStart : kindStart+kindChars])
|
||||
|
||||
// content
|
||||
contentChars := int(binary.BigEndian.Uint16(nsonDescriptors[1:3]))
|
||||
contentStart := kindStart + kindChars + 12 // len(`,"content":"`)
|
||||
evt.Content, _ = strconv.Unquote(`"` + data[contentStart:contentStart+contentChars] + `"`)
|
||||
|
||||
// tags
|
||||
nTags := int(nsonDescriptors[3])
|
||||
evt.Tags = make(Tags, nTags)
|
||||
tagsStart := contentStart + contentChars + 9 // len(`","tags":`)
|
||||
|
||||
nsonIndex := 3
|
||||
tagsIndex := tagsStart
|
||||
for t := 0; t < nTags; t++ {
|
||||
nsonIndex++
|
||||
tagsIndex += 1 // len(`[`) or len(`,`)
|
||||
nItems := int(nsonDescriptors[nsonIndex])
|
||||
tag := make(Tag, nItems)
|
||||
for n := 0; n < nItems; n++ {
|
||||
nsonIndex++
|
||||
itemStart := tagsIndex + 2 // len(`["`) or len(`,"`)
|
||||
itemChars := int(binary.BigEndian.Uint16(nsonDescriptors[nsonIndex:]))
|
||||
nsonIndex++
|
||||
tag[n], _ = strconv.Unquote(`"` + data[itemStart:itemStart+itemChars] + `"`)
|
||||
tagsIndex = itemStart + itemChars + 1 // len(`"`)
|
||||
}
|
||||
tagsIndex += 1 // len(`]`)
|
||||
evt.Tags[t] = tag
|
||||
}
|
||||
|
||||
return evt
|
||||
}
|
||||
|
||||
func encodeNson(evt *Event) string {
|
||||
// start building the nson descriptors (without the first byte that represents the nson size)
|
||||
nsonBuf := make([]byte, 256)
|
||||
|
||||
// build the tags
|
||||
nTags := len(evt.Tags)
|
||||
nsonBuf[3] = uint8(nTags)
|
||||
nsonIndex := 3 // start here
|
||||
|
||||
tagBuilder := strings.Builder{}
|
||||
tagBuilder.Grow(1000) // a guess
|
||||
tagBuilder.WriteString(`[`)
|
||||
for t, tag := range evt.Tags {
|
||||
nItems := len(tag)
|
||||
nsonIndex++
|
||||
nsonBuf[nsonIndex] = uint8(nItems)
|
||||
|
||||
tagBuilder.WriteString(`[`)
|
||||
for i, item := range tag {
|
||||
v := strconv.Quote(item)
|
||||
nsonIndex++
|
||||
binary.BigEndian.PutUint16(nsonBuf[nsonIndex:], uint16(len(v)-2))
|
||||
nsonIndex++
|
||||
tagBuilder.WriteString(v)
|
||||
if nItems > i+1 {
|
||||
tagBuilder.WriteString(`,`)
|
||||
}
|
||||
}
|
||||
tagBuilder.WriteString(`]`)
|
||||
if nTags > t+1 {
|
||||
tagBuilder.WriteString(`,`)
|
||||
}
|
||||
}
|
||||
tagBuilder.WriteString(`]}`)
|
||||
nsonBuf = nsonBuf[0 : nsonIndex+1]
|
||||
|
||||
kind := strconv.Itoa(evt.Kind)
|
||||
kindChars := len(kind)
|
||||
nsonBuf[0] = uint8(kindChars)
|
||||
|
||||
content := strconv.Quote(evt.Content)
|
||||
contentChars := len(content) - 2
|
||||
binary.BigEndian.PutUint16(nsonBuf[1:3], uint16(contentChars))
|
||||
|
||||
// actually build the json
|
||||
base := strings.Builder{}
|
||||
base.Grow(320 + // everything up to "nson":
|
||||
2 + len(nsonBuf)*2 + // nson
|
||||
9 + kindChars + // kind and its label
|
||||
12 + contentChars + // content and its label
|
||||
9 + tagBuilder.Len() + // tags and its label
|
||||
2, // the end
|
||||
)
|
||||
base.WriteString(`{"id":"` + evt.ID + `","pubkey":"` + evt.PubKey + `","sig":"` + evt.Sig + `","created_at":` + strconv.FormatInt(int64(evt.CreatedAt), 10) + `,"nson":"`)
|
||||
base.WriteString(hex.EncodeToString([]byte{uint8(len(nsonBuf) * 2)})) // nson size
|
||||
base.WriteString(hex.EncodeToString(nsonBuf)) // nson descriptors
|
||||
base.WriteString(`","kind":` + kind + `,"content":` + content + `,"tags":`)
|
||||
base.WriteString(tagBuilder.String() /* includes the end */)
|
||||
|
||||
return base.String()
|
||||
}
|
||||
```
|
||||
|
||||
### Other restrictions
|
||||
|
||||
Besides the field ordering and the presence of the `"nson"` field, other restrictions must be applied:
|
||||
|
||||
- the `"created_at"` field must have 10, characters, which gives us a range of dates from about 20 years ago up to 250 years in the future.
|
||||
- to simplify decoding of `"content"` and `"tags"` strings, escape codes like `\uXXXX` are forbidden in NSON, UTF-8 must be used instead. `\n`, `\\` and `\"` are the only valid escaped sequences.
|
||||
|
||||
### Backwards-compatibility
|
||||
|
||||
Any reader who is not aware of the NSON-encoding can receive these events and decode them using whatever means they want. The `"nson"` field will just be ignored and life will continue as normal.
|
||||
|
||||
Also, other event fields that may be present (for example, the NIP-03 `"ots"` field) can be added at the end, after `"tags"`, with no loss to anyone.
|
||||
|
||||
### Other points worth mentioning
|
||||
|
||||
- Relays can receive non-nsonified events from clients, then reformat and store them nsonified so they can serve future clients better by sending them NSON always.
|
||||
|
||||
### Open questions to be edited out of the NIP
|
||||
|
||||
- How to signal NSON support? I thought it would work to have an initial field `"n":1` (before `"id"`) on the JSON, which could be read very fast, but I don't know.
|
||||
68
98.md
Normal file
68
98.md
Normal file
@@ -0,0 +1,68 @@
|
||||
NIP-98
|
||||
======
|
||||
|
||||
HTTP Auth
|
||||
-------------------------
|
||||
|
||||
`draft` `optional` `author:kieran` `author:melvincarvalho`
|
||||
|
||||
This NIP defines an ephemerial event used to authorize requests to HTTP servers using nostr events.
|
||||
|
||||
This is useful for HTTP services which are build for Nostr and deal with Nostr user accounts.
|
||||
|
||||
## Nostr event
|
||||
|
||||
A `kind 27235` (In reference to [RFC 7235](https://www.rfc-editor.org/rfc/rfc7235)) event is used.
|
||||
|
||||
The `content` SHOULD be empty.
|
||||
|
||||
The following tags are defined as REQUIRED.
|
||||
|
||||
* `u` - absolute URL
|
||||
* `method` - HTTP Request Method
|
||||
|
||||
Example event:
|
||||
```json
|
||||
{
|
||||
"id": "fe964e758903360f28d8424d092da8494ed207cba823110be3a57dfe4b578734",
|
||||
"pubkey": "63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed",
|
||||
"content": "",
|
||||
"kind": 27235,
|
||||
"created_at": 1682327852,
|
||||
"tags": [
|
||||
[
|
||||
"u",
|
||||
"https://api.snort.social/api/v1/n5sp/list"
|
||||
],
|
||||
[
|
||||
"method",
|
||||
"GET"
|
||||
]
|
||||
],
|
||||
"sig": "5ed9d8ec958bc854f997bdc24ac337d005af372324747efe4a00e24f4c30437ff4dd8308684bed467d9d6be3e5a517bb43b1732cc7d33949a3aaf86705c22184"
|
||||
}
|
||||
```
|
||||
|
||||
Servers MUST perform the following checks in order to validate the event:
|
||||
1. The `kind` MUST be `27235`.
|
||||
2. The `created_at` MUST be within a reasonable time window (suggestion 60 seconds).
|
||||
3. The `u` tag MUST be exactly the same as the absolute request URL (including query parameters).
|
||||
4. The `method` tag MUST be the same HTTP method used for the requested resource.
|
||||
|
||||
When the request contains a body (as in POST/PUT/PATCH methods) clients SHOULD include a SHA256 hash of the request body in a `payload` tag as hex (`["payload", "<sha256-hex>"]`), servers MAY check this to validate that the requested payload is authorized.
|
||||
|
||||
If one of the checks was to fail the server SHOULD respond with a 401 Unauthorized response code.
|
||||
|
||||
All other checks which server MAY do are OPTIONAL, and implementation specific.
|
||||
|
||||
## Request Flow
|
||||
|
||||
Using the `Authorization` header, the `kind 27235` event MUST be `base64` encoded and use the Authorization scheme `Nostr`
|
||||
|
||||
Example HTTP Authorization header:
|
||||
```
|
||||
Authorization: Nostr eyJpZCI6ImZlOTY0ZTc1ODkwMzM2MGYyOGQ4NDI0ZDA5MmRhODQ5NGVkMjA3Y2JhODIzMTEwYmUzYTU3ZGZlNGI1Nzg3MzQiLCJwdWJrZXkiOiI2M2ZlNjMxOGRjNTg1ODNjZmUxNjgxMGY4NmRkMDllMThiZmQ3NmFhYmMyNGEwMDgxY2UyODU2ZjMzMDUwNGVkIiwiY29udGVudCI6IiIsImtpbmQiOjI3MjM1LCJjcmVhdGVkX2F0IjoxNjgyMzI3ODUyLCJ0YWdzIjpbWyJ1cmwiLCJodHRwczovL2FwaS5zbm9ydC5zb2NpYWwvYXBpL3YxL241c3AvbGlzdCJdLFsibWV0aG9kIiwiR0VUIl1dLCJzaWciOiI1ZWQ5ZDhlYzk1OGJjODU0Zjk5N2JkYzI0YWMzMzdkMDA1YWYzNzIzMjQ3NDdlZmU0YTAwZTI0ZjRjMzA0MzdmZjRkZDgzMDg2ODRiZWQ0NjdkOWQ2YmUzZTVhNTE3YmI0M2IxNzMyY2M3ZDMzOTQ5YTNhYWY4NjcwNWMyMjE4NCJ9
|
||||
```
|
||||
|
||||
## Reference Implementations
|
||||
- C# ASP.NET `AuthenticationHandler` [NostrAuth.cs](https://gist.github.com/v0l/74346ae530896115bfe2504c8cd018d3)
|
||||
16
README.md
16
README.md
@@ -45,6 +45,9 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
- [NIP-26: Delegated Event Signing](26.md)
|
||||
- [NIP-27: Text Note References](27.md)
|
||||
- [NIP-28: Public Chat](28.md)
|
||||
- [NIP-30: Custom Emoji](30.md)
|
||||
- [NIP-31: Dealing with Unknown Events](31.md)
|
||||
- [NIP-32: Labeling](32.md)
|
||||
- [NIP-33: Parameterized Replaceable Events](33.md)
|
||||
- [NIP-36: Sensitive Content](36.md)
|
||||
- [NIP-39: External Identities in Profiles](39.md)
|
||||
@@ -60,7 +63,9 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
- [NIP-58: Badges](58.md)
|
||||
- [NIP-65: Relay List Metadata](65.md)
|
||||
- [NIP-78: Application-specific data](78.md)
|
||||
- [NIP-89: Recommended Application Handlers](89.md)
|
||||
- [NIP-94: File Metadata](94.md)
|
||||
- [NIP-98: HTTP Auth](98.md)
|
||||
|
||||
## Event Kinds
|
||||
|
||||
@@ -72,9 +77,10 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
| `3` | Contacts | [2](02.md) |
|
||||
| `4` | Encrypted Direct Messages | [4](04.md) |
|
||||
| `5` | Event Deletion | [9](09.md) |
|
||||
| `6` | Reposts | [18](18.md) |
|
||||
| `6` | Repost | [18](18.md) |
|
||||
| `7` | Reaction | [25](25.md) |
|
||||
| `8` | Badge Award | [58](58.md) |
|
||||
| `16` | Generic Repost | [18](18.md) |
|
||||
| `40` | Channel Creation | [28](28.md) |
|
||||
| `41` | Channel Metadata | [28](28.md) |
|
||||
| `42` | Channel Message | [28](28.md) |
|
||||
@@ -82,6 +88,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
| `44` | Channel Mute User | [28](28.md) |
|
||||
| `1063` | File Metadata | [94](94.md) |
|
||||
| `1984` | Reporting | [56](56.md) |
|
||||
| `1985` | Label | [32](32.md) |
|
||||
| `9734` | Zap Request | [57](57.md) |
|
||||
| `9735` | Zap | [57](57.md) |
|
||||
| `10000` | Mute List | [51](51.md) |
|
||||
@@ -92,6 +99,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
| `23194` | Wallet Request | [47](47.md) |
|
||||
| `23195` | Wallet Response | [47](47.md) |
|
||||
| `24133` | Nostr Connect | [46](46.md) |
|
||||
| `27235` | HTTP Auth | [98](98.md) |
|
||||
| `30000` | Categorized People List | [51](51.md) |
|
||||
| `30001` | Categorized Bookmark List | [51](51.md) |
|
||||
| `30008` | Profile Badges | [58](58.md) |
|
||||
@@ -100,6 +108,8 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
| `30018` | Create or update a product | [15](15.md) |
|
||||
| `30023` | Long-form Content | [23](23.md) |
|
||||
| `30078` | Application-specific Data | [78](78.md) |
|
||||
| `31989` | Handler recommendation | [89](89.md) |
|
||||
| `31990` | Handler information | [89](89.md) |
|
||||
|
||||
### Event Kind Ranges
|
||||
|
||||
@@ -142,10 +152,13 @@ When experimenting with kinds, keep in mind the classification introduced by [NI
|
||||
| name | value | other parameters | NIP |
|
||||
| ----------------- | ------------------------------------ | -------------------- | ------------------------ |
|
||||
| `a` | coordinates to an event | relay URL | [33](33.md), [23](23.md) |
|
||||
| `alt` | Alt tag | -- | [31](31.md) |
|
||||
| `d` | identifier | -- | [33](33.md) |
|
||||
| `e` | event id (hex) | relay URL, marker | [1](01.md), [10](10.md) |
|
||||
| `g` | geohash | -- | [12](12.md) |
|
||||
| `i` | identity | proof | [39](39.md) |
|
||||
| `l` | label, label namespace | annotations | [32](32.md) |
|
||||
| `L` | label namespace | -- | [32](32.md) |
|
||||
| `p` | pubkey (hex) | relay URL | [1](01.md) |
|
||||
| `r` | a reference (URL, etc) | -- | [12](12.md) |
|
||||
| `t` | hashtag | -- | [12](12.md) |
|
||||
@@ -156,6 +169,7 @@ When experimenting with kinds, keep in mind the classification introduced by [NI
|
||||
| `delegation` | pubkey, conditions, delegation token | -- | [26](26.md) |
|
||||
| `description` | badge description | -- | [58](58.md) |
|
||||
| `description` | invoice description | -- | [57](57.md) |
|
||||
| `emoji` | shortcode | image URL | [30](30.md) |
|
||||
| `expiration` | unix timestamp (string) | -- | [40](40.md) |
|
||||
| `image` | image URL | dimensions in pixels | [23](23.md), [58](58.md) |
|
||||
| `lnurl` | `bech32` encoded `lnurl` | -- | [57](57.md) |
|
||||
|
||||
Reference in New Issue
Block a user