mirror of
https://github.com/nostr-protocol/nips.git
synced 2026-02-17 13:24:32 +00:00
Compare commits
10 Commits
hyperloglo
...
nip-collab
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5a16a3264 | ||
|
|
b914aeffd8 | ||
|
|
5a4734f8b7 | ||
|
|
5d232e6525 | ||
|
|
e83326e6d4 | ||
|
|
567ad57a4b | ||
|
|
3d71a4a78c | ||
|
|
01838f302d | ||
|
|
90a60bd210 | ||
|
|
18b948abda |
6
05.md
6
05.md
@@ -6,11 +6,11 @@ Mapping Nostr keys to DNS-based internet identifiers
|
||||
|
||||
`final` `optional`
|
||||
|
||||
On events of kind `0` (`user 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` (`user 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, the `<local-part>` part MUST only use characters `a-z0-9-_.`.
|
||||
|
||||
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>`.
|
||||
|
||||
The result should be a JSON document object with a key `"names"` that should then be a mapping of names to hex formatted public keys. If the public key for the given `<name>` matches the `pubkey` from the `user metadata` event, the client then concludes that the given pubkey can indeed be referenced by its identifier.
|
||||
The result should be a JSON document object with a key `"names"` that should then be a mapping of names to hex formatted public keys, in lowercase. If the public key for the given `<name>` matches the `pubkey` from the `user metadata` event, the client then concludes that the given pubkey can indeed be referenced by its identifier.
|
||||
|
||||
### Example
|
||||
|
||||
@@ -73,7 +73,7 @@ For example, if after finding that `bob@bob.com` has the public key `abc...def`,
|
||||
|
||||
### Public keys must be in hex format
|
||||
|
||||
Keys must be returned in hex format. Keys in NIP-19 `npub` format are only meant to be used for display in client UIs, not in this NIP.
|
||||
Keys must be returned in hex format, in lowercase. Keys in NIP-19 `npub` format are only meant to be used for display in client UIs, not in this NIP.
|
||||
|
||||
### Showing just the domain as an identifier
|
||||
|
||||
|
||||
233
11.md
233
11.md
@@ -22,8 +22,7 @@ When a relay receives an HTTP(s) request with an `Accept` header of `application
|
||||
"supported_nips": <a list of NIP numbers supported by the relay>,
|
||||
"software": <string identifying relay software URL>,
|
||||
"version": <string version identifier>,
|
||||
"privacy_policy": <a link to a text file describing the relay's privacy policy>,
|
||||
"terms_of_service": <a link to a text file describing the relay's term of service>,
|
||||
"terms_of_service": <a link to a text file describing the relay's term of service>
|
||||
}
|
||||
```
|
||||
|
||||
@@ -81,15 +80,9 @@ The relay server implementation MAY be provided in the `software` attribute. If
|
||||
|
||||
The relay MAY choose to publish its software version as a string attribute. The string format is defined by the relay implementation. It is recommended this be a version number or commit identifier.
|
||||
|
||||
### Privacy Policy
|
||||
|
||||
The relay owner/admin MAY choose to link to a privacy policy document, which describes how the relay utilizes user data. Data collection, data usage, data retention, monetization of data, and third party data sharing SHOULD be included.
|
||||
|
||||
### Terms of Service
|
||||
|
||||
The relay owner/admin MAY choose to link to a terms of service document.
|
||||
|
||||
|
||||
The relay MAY choose to publish its software version as a string attribute. The string format is defined by the relay implementation. It is recommended this be a version number or commit identifier.
|
||||
|
||||
Extra Fields
|
||||
------------
|
||||
@@ -167,112 +160,6 @@ a specific niche kind or content. Normal anti-spam heuristics, for example, do n
|
||||
|
||||
- `default_limit`: The maximum returned events if you send a filter without a `limit`.
|
||||
|
||||
### Event Retention
|
||||
|
||||
There may be a cost associated with storing data forever, so relays
|
||||
may wish to state retention times. The values stated here are defaults
|
||||
for unauthenticated users and visitors. Paid users would likely have
|
||||
other policies.
|
||||
|
||||
Retention times are given in seconds, with `null` indicating infinity.
|
||||
If zero is provided, this means the event will not be stored at
|
||||
all, and preferably an error will be provided when those are received.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"retention": [
|
||||
{"kinds": [0, 1, [5, 7], [40, 49]], "time": 3600},
|
||||
{"kinds": [[40000, 49999]], "time": 100},
|
||||
{"kinds": [[30000, 39999]], "count": 1000},
|
||||
{"time": 3600, "count": 10000}
|
||||
],
|
||||
// other fields...
|
||||
}
|
||||
```
|
||||
|
||||
`retention` is a list of specifications: each will apply to either all kinds, or
|
||||
a subset of kinds. Ranges may be specified for the kind field as a tuple of inclusive
|
||||
start and end values. Events of indicated kind (or all) are then limited to a `count`
|
||||
and/or time period.
|
||||
|
||||
It is possible to effectively blacklist Nostr-based protocols that rely on
|
||||
a specific `kind` number, by giving a retention time of zero for those `kind` values.
|
||||
While that is unfortunate, it does allow clients to discover servers that will
|
||||
support their protocol quickly via a single HTTP fetch.
|
||||
|
||||
There is no need to specify retention times for _ephemeral events_ since they are not retained.
|
||||
|
||||
### Content Limitations
|
||||
|
||||
Some relays may be governed by the arbitrary laws of a nation state. This
|
||||
may limit what content can be stored in clear-text on those relays. All
|
||||
clients are encouraged to use encryption to work around this limitation.
|
||||
|
||||
It is not possible to describe the limitations of each country's laws
|
||||
and policies which themselves are typically vague and constantly shifting.
|
||||
|
||||
Therefore, this field allows the relay operator to indicate which
|
||||
countries' laws might end up being enforced on them, and then
|
||||
indirectly on their users' content.
|
||||
|
||||
Users should be able to avoid relays in countries they don't like,
|
||||
and/or select relays in more favorable zones. Exposing this
|
||||
flexibility is up to the client software.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"relay_countries": [ "CA", "US" ],
|
||||
// other fields...
|
||||
}
|
||||
```
|
||||
|
||||
- `relay_countries`: a list of two-level ISO country codes (ISO 3166-1 alpha-2) whose
|
||||
laws and policies may affect this relay. `EU` may be used for European Union countries. A `*` can be used for global relays.
|
||||
|
||||
Remember that a relay may be hosted in a country which is not the
|
||||
country of the legal entities who own the relay, so it's very
|
||||
likely a number of countries are involved.
|
||||
|
||||
|
||||
### Community Preferences
|
||||
|
||||
For public text notes at least, a relay may try to foster a
|
||||
local community. This would encourage users to follow the global
|
||||
feed on that relay, in addition to their usual individual follows.
|
||||
To support this goal, relays MAY specify some of the following values.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"language_tags": ["en", "en-419"],
|
||||
"tags": ["sfw-only", "bitcoin-only", "anime"],
|
||||
"posting_policy": "https://example.com/posting-policy.html",
|
||||
// other fields...
|
||||
}
|
||||
```
|
||||
|
||||
- `language_tags` is an ordered list
|
||||
of [IETF language tags](https://en.wikipedia.org/wiki/IETF_language_tag) indicating
|
||||
the major languages spoken on the relay. A `*` can be used for global relays.
|
||||
|
||||
- `tags` is a list of limitations on the topics to be discussed.
|
||||
For example `sfw-only` indicates that only "Safe For Work" content
|
||||
is encouraged on this relay. This relies on assumptions of what the
|
||||
"work" "community" feels "safe" talking about. In time, a common
|
||||
set of tags may emerge that allow users to find relays that suit
|
||||
their needs, and client software will be able to parse these tags easily.
|
||||
The `bitcoin-only` tag indicates that any *altcoin*, *"crypto"* or *blockchain*
|
||||
comments will be ridiculed without mercy.
|
||||
|
||||
- `posting_policy` is a link to a human-readable page which specifies the
|
||||
community policies for the relay. In cases where `sfw-only` is True, it's
|
||||
important to link to a page which gets into the specifics of your posting policy.
|
||||
|
||||
The `description` field should be used to describe your community
|
||||
goals and values, in brief. The `posting_policy` is for additional
|
||||
detail and legal terms. Use the `tags` field to signify limitations
|
||||
on content, or topics to be discussed, which could be machine
|
||||
processed by appropriate client software.
|
||||
|
||||
### Pay-to-Relay
|
||||
|
||||
Relays that require payments may want to expose their fee schedules.
|
||||
@@ -291,82 +178,68 @@ Relays that require payments may want to expose their fee schedules.
|
||||
|
||||
### Examples
|
||||
|
||||
As of 25 March 2025 the following command provided these results:
|
||||
|
||||
```bash
|
||||
curl -H "Accept: application/nostr+json" https://jellyfish.land | jq
|
||||
```
|
||||
|
||||
```json
|
||||
```yaml
|
||||
~> curl -H "Accept: application/nostr+json" https://nostr.wine | jq
|
||||
{
|
||||
"name": "JellyFish",
|
||||
"description": "Stay Immortal!",
|
||||
"banner": "https://image.nostr.build/7fdefea2dec1f1ec25b8ce69362566c13b2b7f13f1726c2e4584f05f64f62496.jpg",
|
||||
"pubkey": "bf2bee5281149c7c350f5d12ae32f514c7864ff10805182f4178538c2c421007",
|
||||
"contact": "hi@dezh.tech",
|
||||
"software": "https://github.com/dezh-tech/immortal",
|
||||
"supported_nips": [
|
||||
1,
|
||||
9,
|
||||
11,
|
||||
13,
|
||||
17,
|
||||
40,
|
||||
42,
|
||||
59,
|
||||
62,
|
||||
70
|
||||
],
|
||||
"version": "immortal - 0.0.9",
|
||||
"relay_countries": [
|
||||
"*"
|
||||
],
|
||||
"language_tags": [
|
||||
"*"
|
||||
],
|
||||
"tags": [],
|
||||
"posting_policy": "https://jellyfish.land/tos.txt",
|
||||
"payments_url": "https://jellyfish.land/relay",
|
||||
"icon": "https://image.nostr.build/2547e9ec4b23589e09bc7071e0806c3d4293f76284c58ff331a64bce978aaee8.jpg",
|
||||
"retention": [],
|
||||
"contact": "wino@nostr.wine",
|
||||
"description": "A paid nostr relay for wine enthusiasts and everyone else.",
|
||||
"fees": {
|
||||
"subscription": [
|
||||
"admission": [
|
||||
{
|
||||
"amount": 3000,
|
||||
"period": 2628003,
|
||||
"unit": "sats"
|
||||
},
|
||||
{
|
||||
"amount": 8000,
|
||||
"period": 7884009,
|
||||
"unit": "sats"
|
||||
},
|
||||
{
|
||||
"amount": 15000,
|
||||
"period": 15768018,
|
||||
"unit": "sats"
|
||||
},
|
||||
{
|
||||
"amount": 28000,
|
||||
"period": 31536036,
|
||||
"unit": "sats"
|
||||
"amount": 18888000,
|
||||
"unit": "msats"
|
||||
}
|
||||
]
|
||||
},
|
||||
"icon": "https://image.nostr.build/30acdce4a81926f386622a07343228ae99fa68d012d54c538c0b2129dffe400c.png",
|
||||
"limitation": {
|
||||
"auth_required": false,
|
||||
"max_message_length": 70000,
|
||||
"max_subid_length": 256,
|
||||
"max_subscriptions": 350,
|
||||
"created_at_lower_limit": 94608000,
|
||||
"created_at_upper_limit": 300,
|
||||
"max_event_tags": 4000,
|
||||
"max_limit": 1000,
|
||||
"max_message_length": 524288,
|
||||
"max_subid_length": 71,
|
||||
"max_subscriptions": 50,
|
||||
"min_pow_difficulty": 0,
|
||||
"payment_required": true,
|
||||
"restricted_writes": true,
|
||||
"restricted_writes": true
|
||||
},
|
||||
"name": "nostr.wine",
|
||||
"payments_url": "https://nostr.wine/invoices",
|
||||
"pubkey": "4918eb332a41b71ba9a74b1dc64276cfff592e55107b93baae38af3520e55975",
|
||||
"software": "https://nostr.wine",
|
||||
"supported_nips": [ 1, 2, 4, 9, 11, 40, 42, 50, 70, 77 ],
|
||||
"terms_of_service": "https://nostr.wine/terms",
|
||||
"version": "0.3.3"
|
||||
}
|
||||
|
||||
~> curl -H "Accept: application/nostr+json" https://nostr.land | jq
|
||||
{
|
||||
"description": "[✨ NFDB] nostr.land family of relays (fi-01 [tiger])",
|
||||
"name": "[✨ NFDB] nostr.land",
|
||||
"pubkey": "52b4a076bcbbbdc3a1aefa3735816cf74993b1b8db202b01c883c58be7fad8bd",
|
||||
"software": "NFDB",
|
||||
"icon": "https://i.nostr.build/b3thno790aodH8lE.jpg",
|
||||
"supported_nips": [ 1, 2, 4, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 27, 28, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 42, 44, 46, 47, 48, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 65, 68, 69, 71, 72, 73, 75, 78, 84, 88, 89, 90, 92, 99 ],
|
||||
"version": "1.0.0",
|
||||
"limitation": {
|
||||
"payment_required": true,
|
||||
"max_message_length": 65535,
|
||||
"max_event_tags": 2000,
|
||||
"max_content_length": 70000,
|
||||
"created_at_lower_limit": 0,
|
||||
"created_at_upper_limit": 2147483647,
|
||||
"default_limit": 500,
|
||||
"max_limit": 5000
|
||||
"max_subscriptions": 200,
|
||||
"auth_required": false
|
||||
},
|
||||
"payments_url": "https://nostr.land",
|
||||
"fees": {
|
||||
"subscription": [
|
||||
{
|
||||
"amount": 4000000,
|
||||
"unit": "msats",
|
||||
"period": 2592000
|
||||
}
|
||||
]
|
||||
},
|
||||
"terms_of_service": "https://nostr.land/terms"
|
||||
}
|
||||
```
|
||||
|
||||
2
22.md
2
22.md
@@ -192,7 +192,7 @@ A reply to a podcast comment:
|
||||
// this is a reference to the above comment
|
||||
["e", "80c48d992a38f9c445b943a9c9f1010b396676013443765750431a9004bdac05", "wss://example.relay", "252f10c83610ebca1a059c0bae8255eba2f95be4d1d7bcfa89d7248a82d9f111"],
|
||||
// the parent comment kind
|
||||
["k", "1111"]
|
||||
["k", "1111"],
|
||||
["p", "252f10c83610ebca1a059c0bae8255eba2f95be4d1d7bcfa89d7248a82d9f111"]
|
||||
]
|
||||
// other fields
|
||||
|
||||
11
39.md
11
39.md
@@ -8,16 +8,11 @@ External Identities in Profiles
|
||||
|
||||
## Abstract
|
||||
|
||||
Nostr protocol users may have other online identities such as usernames, profile pages, keypairs etc. they control and they may want to include this data in their profile metadata so clients can parse, validate and display this information.
|
||||
|
||||
## `i` tag on a metadata event
|
||||
|
||||
A new optional `i` tag is introduced for `kind 0` metadata event defined in [NIP-01](01.md):
|
||||
Users can declare their control over one or more online identities such as usernames, profile pages, keypairs in kind `10011` using `i` tags.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"id": <id>,
|
||||
"pubkey": <pubkey>,
|
||||
"kind": 10011,
|
||||
"tags": [
|
||||
["i", "github:semisol", "9721ce4ee4fceb91c9711ca2a6c9a5ab"],
|
||||
["i", "twitter:semisol_public", "1619358434134196225"],
|
||||
@@ -28,7 +23,7 @@ A new optional `i` tag is introduced for `kind 0` metadata event defined in [NIP
|
||||
}
|
||||
```
|
||||
|
||||
An `i` tag will have two parameters, which are defined as the following:
|
||||
An `i` tag MUST have two parameters, which are defined as the following:
|
||||
1. `platform:identity`: This is the platform name (for example `github`) and the identity on that platform (for example `semisol`) joined together with `:`.
|
||||
2. `proof`: String or object that points to the proof of owning this identity.
|
||||
|
||||
|
||||
221
47.md
221
47.md
@@ -28,7 +28,7 @@ Fundamentally NWC is communication between a **client** and **wallet service** b
|
||||
|
||||
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 23197 or 23196) of wallet events (such as a received payment) to the **client**.
|
||||
5. The **wallet service** may send encrypted notifications (kind 23197) of wallet events (such as a received payment) to the **client**.
|
||||
|
||||
## Events
|
||||
|
||||
@@ -134,8 +134,6 @@ The content of notifications is encrypted with [NIP44](44.md) (or NIP-04 for leg
|
||||
}
|
||||
```
|
||||
|
||||
_Note on backwards-compatibility:_ If a **wallet service** supports both nip44 and nip04 for legacy client apps, it should publish both notification events for each notification - kind 23196 encrypted with NIP-04, and kind 23197 encrypted with NIP-44. It is up to the **client** to decide which event to listen to based on its supported encryption and declared supported encryption schemes of the **wallet service** in the `info` event.
|
||||
|
||||
### Error codes
|
||||
- `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.
|
||||
@@ -207,42 +205,6 @@ Response:
|
||||
Errors:
|
||||
- `PAYMENT_FAILED`: The payment failed. This may be due to a timeout, exhausting all routes, insufficient capacity or similar.
|
||||
|
||||
### `multi_pay_invoice`
|
||||
|
||||
Description: Requests payment of multiple invoices.
|
||||
|
||||
Request:
|
||||
```jsonc
|
||||
{
|
||||
"method": "multi_pay_invoice",
|
||||
"params": {
|
||||
"invoices": [
|
||||
{"id":"4da52c32a1", "invoice": "lnbc1...", "amount": 123}, // bolt11 invoice and amount in msats, amount is optional
|
||||
{"id":"3da52c32a1", "invoice": "lnbc50n1...", "metadata": {} }, // generic metadata that can be used to add things like zap/boostagram details for a payer name/comment/etc, optional
|
||||
],
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
For every invoice in the request, a separate response event is sent. To differentiate between the responses, each
|
||||
response event contains a `d` tag with the id of the invoice it is responding to; if no id was given, then the
|
||||
payment hash of the invoice should be used.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"result_type": "multi_pay_invoice",
|
||||
"result": {
|
||||
"preimage": "0123456789abcdef...", // preimage of the payment
|
||||
"fees_paid": 123, // value in msats, optional
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Errors:
|
||||
- `PAYMENT_FAILED`: The payment failed. This may be due to a timeout, exhausting all routes, insufficient capacity or similar.
|
||||
|
||||
### `pay_keysend`
|
||||
|
||||
Request:
|
||||
@@ -277,44 +239,6 @@ Response:
|
||||
Errors:
|
||||
- `PAYMENT_FAILED`: The payment failed. This may be due to a timeout, exhausting all routes, insufficient capacity or similar.
|
||||
|
||||
### `multi_pay_keysend`
|
||||
|
||||
Description: Requests multiple keysend payments.
|
||||
|
||||
Has an array of keysends, these follow the same semantics as `pay_keysend`, just done in a batch
|
||||
|
||||
Request:
|
||||
```jsonc
|
||||
{
|
||||
"method": "multi_pay_keysend",
|
||||
"params": {
|
||||
"keysends": [
|
||||
{"id": "4c5b24a351", "pubkey": "03...", "amount": 123},
|
||||
{"id": "3da52c32a1", "pubkey": "02...", "amount": 567, "preimage": "abc123..", "tlv_records": [{"type": 696969, "value": "77616c5f6872444873305242454d353736"}]},
|
||||
],
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
For every keysend in the request, a separate response event is sent. To differentiate between the responses, each
|
||||
response event contains a `d` tag with the id of the keysend it is responding to; if no id was given, then the
|
||||
pubkey should be used.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"result_type": "multi_pay_keysend",
|
||||
"result": {
|
||||
"preimage": "0123456789abcdef...", // preimage of the payment
|
||||
"fees_paid": 123, // value in msats, optional
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Errors:
|
||||
- `PAYMENT_FAILED`: The payment failed. This may be due to a timeout, exhausting all routes, insufficient capacity or similar.
|
||||
|
||||
### `make_invoice`
|
||||
|
||||
Request:
|
||||
@@ -371,7 +295,7 @@ Response:
|
||||
"result_type": "lookup_invoice",
|
||||
"result": {
|
||||
"type": "incoming", // "incoming" for invoices, "outgoing" for payments
|
||||
"state": "pending", // can be "pending", "settled", "expired" (for invoices) or "failed" (for payments), optional
|
||||
"state": "pending", // can be "pending", "settled", "accepted" (for hold invoices), "expired" (for invoices) or "failed" (for payments), optional
|
||||
"invoice": "string", // encoded invoice, optional
|
||||
"description": "string", // invoice's description, optional
|
||||
"description_hash": "string", // invoice's description hash, optional
|
||||
@@ -420,7 +344,7 @@ Response:
|
||||
"transactions": [
|
||||
{
|
||||
"type": "incoming", // "incoming" for invoices, "outgoing" for payments
|
||||
"state": "pending", // can be "pending", "settled", "expired" (for invoices) or "failed" (for payments), optional
|
||||
"state": "pending", // can be "pending", "settled", "accepted" (for hold invoices), "expired" (for invoices) or "failed" (for payments), optional
|
||||
"invoice": "string", // encoded invoice, optional
|
||||
"description": "string", // invoice's description, optional
|
||||
"description_hash": "string", // invoice's description hash, optional
|
||||
@@ -485,6 +409,89 @@ Response:
|
||||
}
|
||||
```
|
||||
|
||||
### `make_hold_invoice`
|
||||
|
||||
Creates a hold invoice using a pre-generated preimage.
|
||||
|
||||
Request:
|
||||
```jsonc
|
||||
{
|
||||
"method": "make_hold_invoice",
|
||||
"params": {
|
||||
"amount": 123, // value in msats
|
||||
"description": "string", // invoice's description, optional
|
||||
"description_hash": "string", // invoice's description hash, optional
|
||||
"expiry": 213 // expiry in seconds from time invoice is created for a payment to be initiated, optional. This does not determine how long a payment can be held (see `settle_deadline`)
|
||||
"payment_hash": "string" // Payment hash for the payment generated from the preimage
|
||||
"min_cltv_expiry_delta": 144 // The minimum CLTV delta to use for the final hop, optional
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
```jsonc
|
||||
{
|
||||
"result_type": "make_hold_invoice",
|
||||
"result": {
|
||||
"type": "incoming", // "incoming" for invoices, "outgoing" for payments
|
||||
"invoice": "string", // encoded invoice, optional
|
||||
"description": "string", // invoice's description, optional
|
||||
"description_hash": "string", // invoice's description hash, optional
|
||||
"payment_hash": "string", // Payment hash for the payment
|
||||
"amount": 123, // value in msats
|
||||
"created_at": unixtimestamp, // invoice/payment creation time
|
||||
"expires_at": unixtimestamp, // invoice expiration time, optional if not applicable
|
||||
"metadata": {} // generic metadata that can be used to add things like zap/boostagram details for a payer name/comment/etc.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `cancel_hold_invoice`
|
||||
|
||||
Cancels a hold invoice using the payment hash
|
||||
|
||||
Request:
|
||||
```jsonc
|
||||
{
|
||||
"method": "cancel_hold_invoice",
|
||||
"params": {
|
||||
"payment_hash": "string" // Payment hash for the payment generated from the preimage
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
```jsonc
|
||||
{
|
||||
"result_type": "cancel_hold_invoice",
|
||||
"result": {}
|
||||
}
|
||||
```
|
||||
|
||||
### `settle_hold_invoice`
|
||||
|
||||
Settles a hold invoice using the preimage
|
||||
|
||||
|
||||
Request:
|
||||
```jsonc
|
||||
{
|
||||
"method": "settle_hold_invoice",
|
||||
"params": {
|
||||
"preimage": "string" // preimage for the payment
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
```jsonc
|
||||
{
|
||||
"result_type": "settle_hold_invoice",
|
||||
"result": {}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Notifications
|
||||
|
||||
### `payment_received`
|
||||
@@ -539,6 +546,30 @@ Notification:
|
||||
}
|
||||
```
|
||||
|
||||
### `hold_invoice_accepted`
|
||||
|
||||
Description: Sent when a payer accepts (locks in) a hold invoice. To avoid locking up funds in channels the hold invoice SHOULD be settled or canceled within a few minutes of receiving this event.
|
||||
|
||||
Notification:
|
||||
```jsonc
|
||||
{
|
||||
"notification_type": "hold_invoice_accepted",
|
||||
"notification": {
|
||||
"type": "incoming",
|
||||
"state": "accepted", // optional
|
||||
"invoice": "string", // encoded invoice
|
||||
"description": "string", // invoice's description, optional
|
||||
"description_hash": "string", // invoice's description hash, optional
|
||||
"payment_hash": "string", // Payment hash for the payment
|
||||
"amount": 123, // value in msats
|
||||
"created_at": unixtimestamp, // invoice/payment creation time
|
||||
"expires_at": unixtimestamp, // invoice expiration time
|
||||
"settle_deadline": blocknumber, // invoice can only be safely settled or canceled before this block number.
|
||||
"metadata": {} // generic metadata that can be used to add things like zap/boostagram details for a payer name/comment/etc.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Example pay invoice flow
|
||||
|
||||
0. The user scans the QR code generated by the **wallet service** with their **client** application, they follow a `nostr+walletconnect://` deeplink or configure the connection details manually.
|
||||
@@ -564,23 +595,6 @@ The negotiation works as follows.
|
||||
1. The **wallet service** includes an `encryption` tag in the `info` event. This tag contains a space-separated list of encryption schemes that the **wallet service** supports (eg. `nip44_v2 nip04`)
|
||||
2. The **client application** includes an `encryption` tag in each request event. This tag contains the encryption scheme which should be used for the request. The **client application** should always prefer nip44 if supported by the **wallet service**.
|
||||
|
||||
### Info event
|
||||
|
||||
First, the **wallet service** adds an `encryption` tag to its `info` event containing a space-separated list of encryption schemes it supports. For example,
|
||||
if a wallet service supports nip44, but also allows backwards-compatibility to nip04 client applications, its `encryption` tag in the `info` event might look something like:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"kind": 13194,
|
||||
"tags": [
|
||||
["encryption", "nip44_v2 nip04"],
|
||||
// ...
|
||||
],
|
||||
"content": "pay_invoice get_balance make_invoice lookup_invoice list_transactions get_info",
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
When a **client application** establishes a connection, it should read the info event and look for the `encryption` tag.
|
||||
|
||||
**Absence of this tag implies that the wallet only supports nip04.**
|
||||
@@ -607,7 +621,7 @@ If the **wallet service** does not support the specified encryption scheme, it w
|
||||
|
||||
### Notification events
|
||||
|
||||
As described above in the [Notifications](#notifications) section, if a **wallet service** supports both nip04 and nip44, it should publish two notification events for each notification - kind 23196 encrypted with NIP-04, and kind 23197 encrypted with NIP-44. If the **wallet service** only supports nip44, it should only publish kind 23197 events.
|
||||
If a **wallet service** supports both nip04 and nip44, it should publish two notification events for each notification - kind 23196 encrypted with NIP-04, and kind 23197 encrypted with NIP-44. If the **wallet service** only supports nip44, it should only publish kind 23197 events.
|
||||
|
||||
The **client** should check the `encryption` tag in the `info` event to determine which encryption schemes the **wallet service** supports, and listen to the appropriate notification event.
|
||||
|
||||
@@ -668,6 +682,17 @@ Here are some properties that are recognized by some NWC clients:
|
||||
}
|
||||
```
|
||||
|
||||
### Example Hold Invoice Support Flow
|
||||
|
||||
1. Client generates a 32-byte hex-encoded preimage.
|
||||
2. Computes SHA-256 to derive payment hash.
|
||||
3. Sends `make_hold_invoice` with payment hash and desired parameters.
|
||||
4. Waits for `hold_invoice_accepted` notification.
|
||||
5. Upon receiving notification, either:
|
||||
|
||||
* Calls `settle_hold_invoice` with the original preimage to release funds, or
|
||||
* Calls `cancel_hold_invoice` with payment hash to abort.
|
||||
|
||||
### Deep-links
|
||||
|
||||
Wallet applications can register deeplinks in mobile systems to make it possible to create a linking UX that doesn't require the user scanning a QR code or pasting some code.
|
||||
@@ -683,5 +708,3 @@ URI parameters:
|
||||
|
||||
Once a connection has been created by the wallet, it should be returned to the client by opening the callback with the following parameters
|
||||
* `value` -- NWC pairing code (e.g. `nostr+walletconnect://...`)
|
||||
|
||||
|
||||
|
||||
1
51.md
1
51.md
@@ -135,7 +135,6 @@ Some clients have used these lists in the past, but they should work on transiti
|
||||
["e", "340e0326b340e0326b4941ed78ba340e0326b4941ed78ba340e0326b49ed78ba"], // PWA
|
||||
["a", "32267:d6dc95542e18b8b7aec2f14610f55c335abebec76f3db9e58c254661d0593a0c:com.example.app"] // Reference to parent software application
|
||||
],
|
||||
"content": "Example App is a decentralized marketplace for apps",
|
||||
"sig": "a9a4e2192eede77e6c9d24ddfab95ba3ff7c03fbd07ad011fff245abea431fb4d3787c2d04aad001cb039cb8de91d83ce30e9a94f82ac3c5a2372aa1294a96bd"
|
||||
}
|
||||
```
|
||||
|
||||
6
52.md
6
52.md
@@ -95,6 +95,7 @@ Aside from the common tags, this also takes the following tags:
|
||||
* `end` (optional) exclusive end Unix timestamp in seconds. If omitted, the calendar event ends instantaneously.
|
||||
* `start_tzid` (optional) time zone of the start timestamp, as defined by the IANA Time Zone Database. e.g., `America/Costa_Rica`
|
||||
* `end_tzid` (optional) time zone of the end timestamp, as defined by the IANA Time Zone Database. e.g., `America/Costa_Rica`. If omitted and `start_tzid` is provided, the time zone of the end timestamp is the same as the start timestamp.
|
||||
* `D` (required) the day-granularity unix timestamp on which the event takes place, calculated as `floor(unix_seconds() / seconds_in_one_day)`. Multiple tags SHOULD be included to cover the event's timeframe.
|
||||
|
||||
```yaml
|
||||
{
|
||||
@@ -113,6 +114,7 @@ Aside from the common tags, this also takes the following tags:
|
||||
// timestamps
|
||||
["start", "<unix timestamp in seconds>"],
|
||||
["end", "<unix timestamp in seconds>"],
|
||||
["D", "82549"],
|
||||
|
||||
["start_tzid", "<IANA Time Zone Database identifier>"],
|
||||
["end_tzid", "<IANA Time Zone Database identifier>"],
|
||||
@@ -203,10 +205,6 @@ The list of tags is as follows:
|
||||
}
|
||||
```
|
||||
|
||||
## Unsolved Limitations
|
||||
|
||||
* No private events
|
||||
|
||||
## Intentionally Unsupported Scenarios
|
||||
|
||||
### Recurring Calendar Events
|
||||
|
||||
2
55.md
2
55.md
@@ -249,7 +249,7 @@ launcher.launch(intent)
|
||||
```kotlin
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("nostrsigner:$encryptedText"))
|
||||
intent.`package` = "com.example.signer"
|
||||
intent.putExtra("type", "nip04_decrypt")
|
||||
intent.putExtra("type", "nip44_decrypt")
|
||||
// to control the result in your application in case you are not waiting the result before sending another intent
|
||||
intent.putExtra("id", "some_id")
|
||||
// Send the current logged in user pubkey
|
||||
|
||||
119
C1.md
Normal file
119
C1.md
Normal file
@@ -0,0 +1,119 @@
|
||||
NIP-C1
|
||||
======
|
||||
|
||||
Collaborative Ownership
|
||||
-----------------------
|
||||
|
||||
`draft` `optional`
|
||||
|
||||
This NIP defines a mechanism for multiple pubkeys to collaboratively maintain addressable events while preserving backwards compatibility.
|
||||
|
||||
## Motivation
|
||||
|
||||
Certain applications require shared ownership where:
|
||||
|
||||
1. **Attribution matters**: Each collaborator signs with their own key
|
||||
2. **Dynamic membership**: Owners can be added or removed
|
||||
3. **Backwards compatibility**: Non-supporting clients see normal events
|
||||
|
||||
## Specification
|
||||
|
||||
### Collaborative Pointer Event
|
||||
|
||||
A new addressable event kind `39382` serves as a pointer to collaboratively-owned content:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"kind": 39382,
|
||||
"pubkey": "<creator-pubkey>",
|
||||
"tags": [
|
||||
["d", "<target-kind>-<slug>"],
|
||||
["k", "<target-kind>"],
|
||||
["p", "<owner-1-pubkey>"],
|
||||
["p", "<owner-2-pubkey>"],
|
||||
["p", "<owner-3-pubkey>"],
|
||||
["relay", "wss://relay1.example.com"],
|
||||
["relay", "wss://relay2.example.com"]
|
||||
],
|
||||
"content": "",
|
||||
"created_at": 1234567890
|
||||
}
|
||||
```
|
||||
|
||||
#### Tag Definitions
|
||||
|
||||
| Tag | Required | Description |
|
||||
|-----|----------|-------------|
|
||||
| `d` | Yes | `<target-kind>-<slug>` - prevents collisions across kinds |
|
||||
| `k` | Yes | Target event kind (avoids string parsing of `d` tag) |
|
||||
| `p` | Yes | Owner pubkeys (one or more) |
|
||||
| `relay` | No | Relay hints; if absent, use NIP-65 outbox model |
|
||||
|
||||
### Resolution Algorithm
|
||||
|
||||
To resolve the current state of collaboratively-owned content:
|
||||
|
||||
1. Parse the `39382` pointer event to extract owners (`p` tags) and target kind (`k` tag)
|
||||
2. Extract the slug from the `d` tag (everything after the first `-`)
|
||||
3. Query: `{"kinds": [<target-kind>], "authors": [<all-owners>], "#d": ["<slug>"], "limit": 1}`
|
||||
4. Use `relay` tags if present; otherwise fall back to NIP-65 outbox relays
|
||||
5. Return the event with the highest `created_at`
|
||||
|
||||
### Back-Reference (Optional)
|
||||
|
||||
Target events MAY include an `a` tag pointing to the `39382` pointer:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"kind": 30023,
|
||||
"tags": [
|
||||
["d", "my-article"],
|
||||
["a", "39382:<pointer-creator-pubkey>:30023-my-article"]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
This enables clients to discover that an event is part of a collaborative set.
|
||||
|
||||
## Example
|
||||
|
||||
### Pointer Event
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"kind": 39382,
|
||||
"pubkey": "alice-pubkey",
|
||||
"tags": [
|
||||
["d", "30023-collaborative-guide"],
|
||||
["k", "30023"],
|
||||
["p", "alice-pubkey"],
|
||||
["p", "bob-pubkey"],
|
||||
["p", "carol-pubkey"],
|
||||
["relay", "wss://relay.example.com"]
|
||||
],
|
||||
"content": ""
|
||||
}
|
||||
```
|
||||
|
||||
### Target Article (by any owner)
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"kind": 30023,
|
||||
"pubkey": "bob-pubkey",
|
||||
"tags": [
|
||||
["d", "collaborative-guide"],
|
||||
["title", "A Collaborative Guide"],
|
||||
["a", "39382:alice-pubkey:30023-collaborative-guide"]
|
||||
],
|
||||
"content": "..."
|
||||
}
|
||||
```
|
||||
|
||||
### Client Resolution
|
||||
|
||||
1. Client receives `naddr` for the `39382` pointer
|
||||
2. Parses owners: `[alice, bob, carol]`
|
||||
3. Queries: `{"kinds": [30023], "authors": ["alice", "bob", "carol"], "#d": ["collaborative-guide"], "limit": 1}`
|
||||
4. Returns most recent version regardless of which owner published it
|
||||
|
||||
@@ -109,6 +109,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
- [NIP-B7: Blossom](B7.md)
|
||||
- [NIP-BE: Nostr BLE Communications Protocol](BE.md)
|
||||
- [NIP-C0: Code Snippets](C0.md)
|
||||
- [NIP-C1: Collaborative Ownership](C1.md)
|
||||
- [NIP-C7: Chats](C7.md)
|
||||
- [NIP-EE: E2EE Messaging using MLS Protocol](EE.md) --- **unrecommended**: superseded by the [Marmot Protocol](https://github.com/marmot-protocol/marmot)
|
||||
|
||||
@@ -294,6 +295,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
| `39000-9` | Group metadata events | [29](29.md) |
|
||||
| `39089` | Starter packs | [51](51.md) |
|
||||
| `39092` | Media starter packs | [51](51.md) |
|
||||
| `39382` | Collaborative Pointer | [C1](C1.md) |
|
||||
| `39701` | Web bookmarks | [B0](B0.md) |
|
||||
|
||||
[NUD: Custom Feeds]: https://wikifreedia.xyz/cip-01/
|
||||
@@ -348,6 +350,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
| `A` | root address | relay URL | [22](22.md) |
|
||||
| `c` | commit id | | [34](34.md) |
|
||||
| `d` | identifier | -- | [01](01.md) |
|
||||
| `D` | day | -- | [52](52.md) |
|
||||
| `e` | event id (hex) | relay URL, marker, pubkey (hex) | [01](01.md), [10](10.md) |
|
||||
| `E` | root event id | relay URL | [22](22.md) |
|
||||
| `f` | currency code | -- | [69](69.md) |
|
||||
|
||||
Reference in New Issue
Block a user