From 50f87c9970e1a6f5208f289bec720a969f7c58b7 Mon Sep 17 00:00:00 2001 From: Padreug Date: Sun, 3 May 2026 17:41:30 +0200 Subject: [PATCH] fix(nip17): drop `since` filter on kind 1059 subscription MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NIP-59 randomizes gift wrap created_at up to 2 days into the past so metadata observers can't correlate publish moments. The lenient `since = last_dm_time - 5min` window from commit e0fdada was designed for NIP-04 messages where created_at is the real send time; with gift wraps it locks out any wrap whose randomized timestamp falls before the latest stored DM. aio-demo symptom: established merchant (last_dm_time = today 14:40) subscribes with `since = today 14:35`. Customer publishes a new gift wrap whose randomized created_at is May 1 23:11. NostrFilter.matches sees `event.created_at < self.since` and returns False — relay logs "❌ Filter didn't match" and the order never reaches the merchant. Fix: don't apply `since` at all on the kind 1059 filter. Replay risk is bounded by server-side dedup and our existing NostrClient.is_duplicate_event() guard. Other filters (stalls, products, profiles) keep their `since` because those events use real timestamps. Co-Authored-By: Claude Opus 4.6 (1M context) --- nostr/nostr_client.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/nostr/nostr_client.py b/nostr/nostr_client.py index c51d19d..dbc410e 100644 --- a/nostr/nostr_client.py +++ b/nostr/nostr_client.py @@ -152,10 +152,13 @@ class NostrClient: def _filters_for_direct_messages(self, public_keys: List[str], since: int) -> List: # NIP-17/NIP-59: subscribe to kind 1059 gift wraps addressed to our merchants. # With gift wrapping, outgoing messages are self-wrapped (same p-tag filter). + # + # Do NOT apply `since` here. Per NIP-59, gift wraps use randomized past + # timestamps (up to 2 days back) to defeat metadata correlation, so a + # `since` derived from the latest DM in our DB will reject fresh wraps + # whose randomized created_at is older than that window. Server-side + # dedup + the client's is_duplicate_event() guard handle replays. gift_wrap_filter: dict = {"kinds": [1059], "#p": public_keys} - if since and since != 0: - gift_wrap_filter["since"] = since - return [gift_wrap_filter] def _filters_for_stall_events(self, public_keys: List[str], since: int) -> List: -- 2.53.0