From e2d150b69515425ee976f186b2d67364c5d5658a Mon Sep 17 00:00:00 2001 From: "William K. Santiago" Date: Tue, 14 Jul 2026 11:29:54 -0400 Subject: [PATCH 1/3] Advertise NIP-17/51 and add kind 10050 replaceable test --- README.md | 7 ++++++- src/nip11.zig | 2 +- tests/integration.sh | 9 +++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a01b166..f7f58ae 100644 --- a/README.md +++ b/README.md @@ -41,12 +41,17 @@ For more options, see `wisp.toml.example`. ## Features -* NIPs: 1, 2, 9, 11, 13, 16, 33, 40, 42, 45, 50, 65, 70, 77, 86 +* NIPs: 1, 2, 9, 11, 13, 16, 17, 33, 40, 42, 45, 50, 51, 65, 70, 77, 86 * LMDB storage (no external database) * Spider mode for syncing events from external relays * Import/export to JSONL * Prometheus metrics at `GET /metrics` +Marmot/MLS compatible: Wisp's generic NIP-16/NIP-33 handling stores and serves +kind 10050 (DM/inbox relays, replaceable), 10051 (KeyPackage relays, +replaceable), 30443 (KeyPackage, addressable) / legacy 443, and 1059 gift +wraps, so Haven, WhiteNoise, and other Marmot clients work without extra setup. + ## Monitoring Operational metrics are exposed in Prometheus format at `GET /metrics` on the diff --git a/src/nip11.zig b/src/nip11.zig index f80eb94..46d27b5 100644 --- a/src/nip11.zig +++ b/src/nip11.zig @@ -41,7 +41,7 @@ pub fn write(config: *const Config, nip86: *const Nip86Handler, w: anytype) !voi try writeJsonString(w, contact); } - try w.writeAll(",\"supported_nips\":[1,2,9,11,13,16,33,40,42,45,50,65,70,77,86]"); + try w.writeAll(",\"supported_nips\":[1,2,9,11,13,16,17,33,40,42,45,50,51,65,70,77,86]"); try w.writeAll(",\"software\":\"https://github.com/privkeyio/wisp\""); try w.writeAll(",\"version\":\"0.5.12\""); diff --git a/tests/integration.sh b/tests/integration.sh index 206a42f..373992d 100755 --- a/tests/integration.sh +++ b/tests/integration.sh @@ -72,6 +72,15 @@ chk "NIP-16 replaceable kept single" 1 "$(req -k 0 -a "$PK2")" chk "NIP-16 replaceable keeps latest" "v2" \ "$(timeout 10 noz req -k 0 -a "$PK2" "$R" 2>/dev/null | grep -o 'v[12]' | head -1)" +# --- NIP-17/NIP-51 DM relays list (kind 10050) replaceable, latest wins --- +dmbase=$(($(date +%s) - 20)) +pub --sec $SEC2 -k 10050 --ts $dmbase -t relay=wss://relay.one -c "" +pub --sec $SEC2 -k 10050 --ts $((dmbase + 1)) -t relay=wss://relay.two -c "" +sleep 0.5 +chk "NIP-17/51 kind 10050 kept single" 1 "$(req -k 10050 -a "$PK2")" +chk "NIP-17/51 kind 10050 keeps latest" "wss://relay.two" \ + "$(timeout 10 noz req -k 10050 -a "$PK2" "$R" 2>/dev/null | grep -oE 'wss://relay\.(one|two)' | head -1)" + # --- NIP-16 ephemeral (kind 20000) not stored --- pub --sec $SEC1 -k 20000 -c "ephemeral" sleep 0.5 From 0f1bda251db4dcc90596c08d75cb0c2364f7f450 Mon Sep 17 00:00:00 2001 From: "William K. Santiago" Date: Tue, 14 Jul 2026 13:50:38 -0400 Subject: [PATCH 2/3] Add kind 10051 replaceable test --- tests/integration.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/integration.sh b/tests/integration.sh index 373992d..9e5003a 100755 --- a/tests/integration.sh +++ b/tests/integration.sh @@ -81,6 +81,15 @@ chk "NIP-17/51 kind 10050 kept single" 1 "$(req -k 10050 -a "$PK2")" chk "NIP-17/51 kind 10050 keeps latest" "wss://relay.two" \ "$(timeout 10 noz req -k 10050 -a "$PK2" "$R" 2>/dev/null | grep -oE 'wss://relay\.(one|two)' | head -1)" +# --- Marmot/NIP-EE KeyPackage relays list (kind 10051) replaceable, latest wins --- +kpbase=$(($(date +%s) - 20)) +pub --sec $SEC2 -k 10051 --ts $kpbase -t relay=wss://kp.one -c "" +pub --sec $SEC2 -k 10051 --ts $((kpbase + 1)) -t relay=wss://kp.two -c "" +sleep 0.5 +chk "Marmot kind 10051 kept single" 1 "$(req -k 10051 -a "$PK2")" +chk "Marmot kind 10051 keeps latest" "wss://kp.two" \ + "$(timeout 10 noz req -k 10051 -a "$PK2" "$R" 2>/dev/null | grep -oE 'wss://kp\.(one|two)' | head -1)" + # --- NIP-16 ephemeral (kind 20000) not stored --- pub --sec $SEC1 -k 20000 -c "ephemeral" sleep 0.5 From c028a00fdb49eadc4e5b78210e9aed10737bb158 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kyle=20=F0=9F=90=86?= Date: Tue, 14 Jul 2026 17:22:17 -0400 Subject: [PATCH 3/3] Drop NIP-17 claim (no 1059 recipient gating), keep NIP-51, add 30443 addressable test --- README.md | 5 ++++- src/nip11.zig | 2 +- tests/integration.sh | 17 ++++++++++++++--- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f7f58ae..a955021 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ For more options, see `wisp.toml.example`. ## Features -* NIPs: 1, 2, 9, 11, 13, 16, 17, 33, 40, 42, 45, 50, 51, 65, 70, 77, 86 +* NIPs: 1, 2, 9, 11, 13, 16, 33, 40, 42, 45, 50, 51, 65, 70, 77, 86 * LMDB storage (no external database) * Spider mode for syncing events from external relays * Import/export to JSONL @@ -51,6 +51,9 @@ Marmot/MLS compatible: Wisp's generic NIP-16/NIP-33 handling stores and serves kind 10050 (DM/inbox relays, replaceable), 10051 (KeyPackage relays, replaceable), 30443 (KeyPackage, addressable) / legacy 443, and 1059 gift wraps, so Haven, WhiteNoise, and other Marmot clients work without extra setup. +Gift wraps are stored and served like any other event; Wisp does not implement +the NIP-17 recipient-only serving rule, so operators wanting to restrict who can +read kind 1059 should enable AUTH (`auth_required`). ## Monitoring diff --git a/src/nip11.zig b/src/nip11.zig index 46d27b5..3e1f28c 100644 --- a/src/nip11.zig +++ b/src/nip11.zig @@ -41,7 +41,7 @@ pub fn write(config: *const Config, nip86: *const Nip86Handler, w: anytype) !voi try writeJsonString(w, contact); } - try w.writeAll(",\"supported_nips\":[1,2,9,11,13,16,17,33,40,42,45,50,51,65,70,77,86]"); + try w.writeAll(",\"supported_nips\":[1,2,9,11,13,16,33,40,42,45,50,51,65,70,77,86]"); try w.writeAll(",\"software\":\"https://github.com/privkeyio/wisp\""); try w.writeAll(",\"version\":\"0.5.12\""); diff --git a/tests/integration.sh b/tests/integration.sh index 9e5003a..cae4c21 100755 --- a/tests/integration.sh +++ b/tests/integration.sh @@ -72,13 +72,13 @@ chk "NIP-16 replaceable kept single" 1 "$(req -k 0 -a "$PK2")" chk "NIP-16 replaceable keeps latest" "v2" \ "$(timeout 10 noz req -k 0 -a "$PK2" "$R" 2>/dev/null | grep -o 'v[12]' | head -1)" -# --- NIP-17/NIP-51 DM relays list (kind 10050) replaceable, latest wins --- +# --- NIP-51 DM relays list (kind 10050, NIP-17 inbox) replaceable, latest wins --- dmbase=$(($(date +%s) - 20)) pub --sec $SEC2 -k 10050 --ts $dmbase -t relay=wss://relay.one -c "" pub --sec $SEC2 -k 10050 --ts $((dmbase + 1)) -t relay=wss://relay.two -c "" sleep 0.5 -chk "NIP-17/51 kind 10050 kept single" 1 "$(req -k 10050 -a "$PK2")" -chk "NIP-17/51 kind 10050 keeps latest" "wss://relay.two" \ +chk "NIP-51 kind 10050 kept single" 1 "$(req -k 10050 -a "$PK2")" +chk "NIP-51 kind 10050 keeps latest" "wss://relay.two" \ "$(timeout 10 noz req -k 10050 -a "$PK2" "$R" 2>/dev/null | grep -oE 'wss://relay\.(one|two)' | head -1)" # --- Marmot/NIP-EE KeyPackage relays list (kind 10051) replaceable, latest wins --- @@ -90,6 +90,17 @@ chk "Marmot kind 10051 kept single" 1 "$(req -k 10051 -a "$PK2")" chk "Marmot kind 10051 keeps latest" "wss://kp.two" \ "$(timeout 10 noz req -k 10051 -a "$PK2" "$R" 2>/dev/null | grep -oE 'wss://kp\.(one|two)' | head -1)" +# --- Marmot KeyPackage (kind 30443) addressable, keyed by d tag, latest wins --- +kabase=$(($(date +%s) - 20)) +pub --sec $SEC2 -k 30443 -d device1 --ts $kabase -c "kp-v1" +pub --sec $SEC2 -k 30443 -d device1 --ts $((kabase + 1)) -c "kp-v2" +pub --sec $SEC2 -k 30443 -d device2 --ts $((kabase + 1)) -c "kp-other" +sleep 0.5 +chk "Marmot kind 30443 same d-tag replaced" 1 "$(req -k 30443 -d device1)" +chk "Marmot kind 30443 different d-tags kept" 2 "$(req -k 30443 -a "$PK2")" +chk "Marmot kind 30443 keeps latest per d" "kp-v2" \ + "$(timeout 10 noz req -k 30443 -d device1 -a "$PK2" "$R" 2>/dev/null | grep -oE 'kp-v[12]' | head -1)" + # --- NIP-16 ephemeral (kind 20000) not stored --- pub --sec $SEC1 -k 20000 -c "ephemeral" sleep 0.5