zaps: foundation for the bitvid-native zap tally (#47) — schema + verify

First slice of docs/zap-tally-plan.md (decisions D1-D5 resolved in the doc):

- ZAP_TALLY_KIND = 30081 (addressable, d=payment_hash → one canonical event
  per real payment) + NOTE_TYPES.ZAP_TALLY schema + buildZapTallyEvent
  (nostrEventSchemas.js). Video + profile pointers.
- FEATURE_ZAP_TALLY flag (constants.js), default ON per D4.
- zapReceiptValidator.js: extractBolt11Fields (payment_hash + description_hash
  from the existing bech32 walker), verifyPaymentPreimage
  (sha256(preimage)==payment_hash), verifyBitvidZapTally — the security core:
  proves the invoice was paid AND bound to this zap request (description-hash
  binding blocks reusing a leaked preimage for another video). Amount is
  bolt11-derived, never the tag; pointers come from the embedded zap request.
- Schema-doc row for kind 30081.

Tests: tests/zap-tally-verify.test.mjs (8) — preimage check, bech32 field
round-trip, valid/bad-preimage/replay/zero-sats decisions, builder tag shape
(video + profile). Lint + build green.

No publishing or counting wired yet — next slices per the plan checklist.

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
thePR0M3TH3ANandClaude Fable 5 committed 2026-07-04 23:32:12 -04:00
1 parent ce4904f1a4
commit a6b2996f4e
6 files changed
+542 -16

No files matched your search

+7
View File
@@ -200,6 +200,7 @@ const DEFAULT_FLAGS = Object.freeze({
FEATURE_IMPROVED_COMMENT_FETCHING: true, // Default true for comment persistence fixes
FEATURE_TRENDING_FEED: true, // "Trending" tab: recently-added ranked by view count. Disable to hide the tab.
FEATURE_MOST_ZAPPED_FEED: true, // "Most Zapped" tab: recently-added ranked by zap total. Disable to hide the tab.
FEATURE_ZAP_TALLY: true, // bitvid-native preimage-verified zap tally (publish + count). Rollback: set false.
TRUSTED_MUTE_HIDE_THRESHOLD: DEFAULT_TRUSTED_MUTE_HIDE_THRESHOLD,
TRUSTED_SPAM_HIDE_THRESHOLD: DEFAULT_TRUSTED_SPAM_HIDE_THRESHOLD,
WSS_TRACKERS: DEFAULT_WSS_TRACKERS,
@@ -224,6 +225,7 @@ const runtimeFlags = (() => {
DEFAULT_FLAGS.FEATURE_IMPROVED_COMMENT_FETCHING,
FEATURE_TRENDING_FEED: DEFAULT_FLAGS.FEATURE_TRENDING_FEED,
FEATURE_MOST_ZAPPED_FEED: DEFAULT_FLAGS.FEATURE_MOST_ZAPPED_FEED,
FEATURE_ZAP_TALLY: DEFAULT_FLAGS.FEATURE_ZAP_TALLY,
TRUSTED_MUTE_HIDE_THRESHOLD: DEFAULT_FLAGS.TRUSTED_MUTE_HIDE_THRESHOLD,
TRUSTED_SPAM_HIDE_THRESHOLD: DEFAULT_FLAGS.TRUSTED_SPAM_HIDE_THRESHOLD,
WSS_TRACKERS: [...DEFAULT_FLAGS.WSS_TRACKERS],
@@ -274,6 +276,11 @@ export let FEATURE_MOST_ZAPPED_FEED = coerceBoolean(
DEFAULT_FLAGS.FEATURE_MOST_ZAPPED_FEED
);
export let FEATURE_ZAP_TALLY = coerceBoolean(
runtimeFlags.FEATURE_ZAP_TALLY,
DEFAULT_FLAGS.FEATURE_ZAP_TALLY
);
export let FEATURE_TRUST_SEEDS = coerceBoolean(
runtimeFlags.FEATURE_TRUST_SEEDS,
DEFAULT_FLAGS.FEATURE_TRUST_SEEDS