Summary
Kind 10050 (NIP-17 DM Relays List) is the replaceable event a user publishes to advertise which relays they want to receive gift-wrapped (kind:1059) private DMs on. The Haven mobile app publishes and reads these against Wisp for its NIP-17 / Marmot messaging. Structure: replaceable, empty content, tags of the form ["relay", "wss://..."] (NIP-17 §Publishing, NIP-51).
Investigation — this already works today
Kind 10050 is in the NIP-16 replaceable range (10000–19999) and is handled generically, with no per-kind special casing:
- Classification:
10000 <= kind < 20000 → replaceable (nostr lib src/event.zig Kind.classify, used by kindType).
- Ingest gate: the only kind-based check on EVENT is the opt-in NIP-86 allowlist
isKindAllowed() (src/handler.zig:259), which returns true for every kind unless an operator has explicitly populated an allowlist (src/management_store.zig:256-262). There is no hardcoded kind denylist.
- Storage:
storeInTxn routes replaceable/addressable through handleReplaceable (src/store.zig:97-104), which keys by pubkey || kind_be for replaceable events (nostr lib src/replaceable.zig buildKey, no d tag for replaceable) and keeps latest-wins by created_at/id (shouldReplace). So Wisp stores exactly one 10050 per (pubkey, kind) — correct NIP-16 behavior.
- Query: REQ
{kinds:[10050], authors:[...]} resolves through the generic idx_kind / idx_pubkey indexes (src/store.zig:527-551, 147-160); nothing filters 10050 out.
Verdict: acceptance, replaceable storage, and querying of 10050 all work generically today. The only real gap is advertising/documentation.
Actual change requested
- Advertise NIP-17 (and NIP-51, which defines the list) in NIP-11
supported_nips (src/nip11.zig:44, currently [1,2,9,11,13,16,33,40,42,45,50,65,70,77,86]).
- Add NIP-17/51 to the supported-NIPs line in
README.md:44.
- Add an integration assertion in
tests/integration.sh mirroring the existing NIP-16 replaceable block (tests/integration.sh:66-73): publish two 10050 events with relay tags, assert a single stored event and latest-wins.
Note: NIP-17 also says relays SHOULD serve kind:1059 only to the p-tagged recipient under NIP-42 AUTH. That is a separate privacy hardening item, out of scope here.
Summary
Kind
10050(NIP-17 DM Relays List) is the replaceable event a user publishes to advertise which relays they want to receive gift-wrapped (kind:1059) private DMs on. The Haven mobile app publishes and reads these against Wisp for its NIP-17 / Marmot messaging. Structure: replaceable, emptycontent, tags of the form["relay", "wss://..."](NIP-17 §Publishing, NIP-51).Investigation — this already works today
Kind
10050is in the NIP-16 replaceable range (10000–19999) and is handled generically, with no per-kind special casing:10000 <= kind < 20000→replaceable(nostrlibsrc/event.zigKind.classify, used bykindType).isKindAllowed()(src/handler.zig:259), which returnstruefor every kind unless an operator has explicitly populated an allowlist (src/management_store.zig:256-262). There is no hardcoded kind denylist.storeInTxnroutesreplaceable/addressablethroughhandleReplaceable(src/store.zig:97-104), which keys bypubkey || kind_befor replaceable events (nostrlibsrc/replaceable.zigbuildKey, nodtag for replaceable) and keeps latest-wins bycreated_at/id (shouldReplace). So Wisp stores exactly one10050per(pubkey, kind)— correct NIP-16 behavior.{kinds:[10050], authors:[...]}resolves through the genericidx_kind/idx_pubkeyindexes (src/store.zig:527-551,147-160); nothing filters10050out.Verdict: acceptance, replaceable storage, and querying of
10050all work generically today. The only real gap is advertising/documentation.Actual change requested
supported_nips(src/nip11.zig:44, currently[1,2,9,11,13,16,33,40,42,45,50,65,70,77,86]).README.md:44.tests/integration.shmirroring the existing NIP-16 replaceable block (tests/integration.sh:66-73): publish two10050events withrelaytags, assert a single stored event and latest-wins.Note: NIP-17 also says relays SHOULD serve
kind:1059only to the p-tagged recipient under NIP-42 AUTH. That is a separate privacy hardening item, out of scope here.