From 63030f2e3404abcd0c9635b44258941e5c18662b Mon Sep 17 00:00:00 2001 From: anshumancanrock Date: Mon, 8 Jun 2026 18:58:07 +0530 Subject: [PATCH] feat: add NIP-70 protected event detection util --- .changeset/nip70-protected-event-util.md | 5 +++ src/constants/base.ts | 2 + src/utils/event.ts | 6 +++ test/unit/utils/event.spec.ts | 54 ++++++++++++++++++++++++ 4 files changed, 67 insertions(+) create mode 100644 .changeset/nip70-protected-event-util.md diff --git a/.changeset/nip70-protected-event-util.md b/.changeset/nip70-protected-event-util.md new file mode 100644 index 00000000..7d82848d --- /dev/null +++ b/.changeset/nip70-protected-event-util.md @@ -0,0 +1,5 @@ +--- +"nostream": patch +--- + +feat: add NIP-70 protected event detection utility diff --git a/src/constants/base.ts b/src/constants/base.ts index f37a41d8..d5b5f526 100644 --- a/src/constants/base.ts +++ b/src/constants/base.ts @@ -79,6 +79,8 @@ export enum EventTags { AuthRelay = 'relay', // Marmot Protocol MIP-03: group ID for filtering kind:445 Group Events Group = 'h', + // NIP-70: Protected Events + Protected = '-', } export const ALL_RELAYS = 'ALL_RELAYS' diff --git a/src/utils/event.ts b/src/utils/event.ts index 68f34b2e..b49f4bcb 100644 --- a/src/utils/event.ts +++ b/src/utils/event.ts @@ -289,3 +289,9 @@ export const isWelcomeRumorEvent = (event: Event): boolean => { export const isMarmotGroupEvent = (event: Event): boolean => { return event.kind === EventKinds.MARMOT_GROUP_EVENT } + +// NIP-70: Protected Events + +export const isProtectedEvent = (event: Event): boolean => { + return event.tags.some((tag) => tag[0] === EventTags.Protected) +} diff --git a/test/unit/utils/event.spec.ts b/test/unit/utils/event.spec.ts index 721d767b..e91fe09b 100644 --- a/test/unit/utils/event.spec.ts +++ b/test/unit/utils/event.spec.ts @@ -13,6 +13,7 @@ import { isGiftWrapEvent, isMarmotGroupEvent, isParameterizedReplaceableEvent, + isProtectedEvent, isReplaceableEvent, isRequestToVanishEvent, isSealEvent, @@ -655,3 +656,56 @@ describe('NIP-40', () => { }) }) }) + +describe('NIP-70', () => { + describe('isProtectedEvent', () => { + it('returns true if event has a ["-"] tag', () => { + const event: Event = { + tags: [['-']], + } as any + expect(isProtectedEvent(event)).to.be.true + }) + + it('returns true if protected tag has extra values', () => { + const event: Event = { + tags: [['-', 'some-reason']], + } as any + expect(isProtectedEvent(event)).to.be.true + }) + + it('returns false if event has no tags', () => { + const event: Event = { + tags: [], + } as any + expect(isProtectedEvent(event)).to.be.false + }) + + it('returns false if event has unrelated tags', () => { + const event: Event = { + tags: [ + ['e', '7377fa81fc6c7ae7f7f4ef8938d4a603f7bf98183b35ab128235cc92d4bebf96'], + ['p', '22e804d26ed16b68db5259e78449e96dab5d464c8f470bda3eb1a70467f2c793'], + ], + } as any + expect(isProtectedEvent(event)).to.be.false + }) + + it('returns false if "-" appears as a tag value, not a tag name', () => { + const event: Event = { + tags: [['e', '-']], + } as any + expect(isProtectedEvent(event)).to.be.false + }) + + it('returns true when protected tag is among other tags', () => { + const event: Event = { + tags: [ + ['e', '7377fa81fc6c7ae7f7f4ef8938d4a603f7bf98183b35ab128235cc92d4bebf96'], + ['-'], + ['p', '22e804d26ed16b68db5259e78449e96dab5d464c8f470bda3eb1a70467f2c793'], + ], + } as any + expect(isProtectedEvent(event)).to.be.true + }) + }) +})