import type { Event } from 'nostr-tools' import { SimplePool } from 'nostr-tools' import { createSubscription } from '@/types/nostr-tools-extended' import { getPrimaryRelaySync } from './config' function createZapFilters(targetPubkey: string, targetEventId: string, userPubkey: string): Array<{ kinds: number[] '#p': string[] '#e': string[] authors: string[] }> { return [ { kinds: [9735], // Zap receipt '#p': [targetPubkey], '#e': [targetEventId], authors: [userPubkey], // Filter by the payer's pubkey }, ] } async function isValidZapReceipt( params: { event: Event targetEventId: string targetPubkey: string userPubkey: string amount: number } ): Promise { // Import verification service dynamically to avoid circular dependencies const { zapVerificationService } = await import('./zapVerification') return zapVerificationService.verifyZapReceiptForArticle({ zapReceipt: params.event, articleId: params.targetEventId, articlePubkey: params.targetPubkey, userPubkey: params.userPubkey, expectedAmount: params.amount, }) } /** * Check if user has paid for an article by looking for zap receipts */ function handleZapReceiptEvent( params: { event: Event targetEventId: string targetPubkey: string userPubkey: string amount: number finalize: (value: boolean) => void resolved: { current: boolean } } ): void { if (params.resolved.current) { return } void isValidZapReceipt({ event: params.event, targetEventId: params.targetEventId, targetPubkey: params.targetPubkey, userPubkey: params.userPubkey, amount: params.amount, }).then((isValid) => { if (isValid) { params.finalize(true) } }) } export function checkZapReceipt( params: { pool: SimplePool targetPubkey: string targetEventId: string amount: number userPubkey: string } ): Promise { if (!params.pool) { return Promise.resolve(false) } return new Promise((resolve) => { let resolved = false const relayUrl = getPrimaryRelaySync() const sub = createSubscription(params.pool, [relayUrl], createZapFilters(params.targetPubkey, params.targetEventId, params.userPubkey)) const finalize = (value: boolean): void => { if (resolved) { return } resolved = true sub.unsub() resolve(value) } const resolvedRef = { current: resolved } sub.on('event', (event: Event): void => { handleZapReceiptEvent({ event, targetEventId: params.targetEventId, targetPubkey: params.targetPubkey, userPubkey: params.userPubkey, amount: params.amount, finalize, resolved: resolvedRef, }) }) const end = (): void => { finalize(false) } sub.on('eose', end) setTimeout(end, 3000) }) }