import { Event, EventTemplate, getEventHash, signEvent } from 'nostr-tools' import { nostrService } from './nostr' import { PLATFORM_NPUB } from './platformConfig' import { calculateSponsoringSplit } from './platformCommissions' import type { SimplePoolWithSub } from '@/types/nostr-tools-extended' const RELAY_URL = process.env.NEXT_PUBLIC_NOSTR_RELAY_URL ?? 'wss://relay.damus.io' export interface SponsoringTracking { transactionId: string authorPubkey: string authorMainnetAddress: string amount: number authorAmount: number platformCommission: number timestamp: number confirmed: boolean confirmations: number } /** * Sponsoring tracking service * Publishes tracking events on Nostr for sponsoring payments */ export class SponsoringTrackingService { private readonly platformPubkey: string = PLATFORM_NPUB private readonly trackingKind = 30079 // Custom kind for sponsoring tracking /** * Track sponsoring payment * Publishes event on Nostr with commission information */ async trackSponsoringPayment( tracking: SponsoringTracking, authorPrivateKey: string ): Promise { try { const pool = nostrService.getPool() if (!pool) { console.error('Pool not initialized for sponsoring tracking') return null } const authorPubkey = nostrService.getPublicKey() if (!authorPubkey) { console.error('Author public key not available for tracking') return null } const eventTemplate: EventTemplate = { kind: this.trackingKind, created_at: Math.floor(Date.now() / 1000), tags: [ ['p', this.platformPubkey], // Tag platform for querying ['transaction', tracking.transactionId], ['author', tracking.authorPubkey], ['author_address', tracking.authorMainnetAddress], ['amount', tracking.amount.toString()], ['author_amount', tracking.authorAmount.toString()], ['platform_commission', tracking.platformCommission.toString()], ['confirmed', tracking.confirmed ? 'true' : 'false'], ['confirmations', tracking.confirmations.toString()], ['timestamp', tracking.timestamp.toString()], ], content: JSON.stringify({ transactionId: tracking.transactionId, authorPubkey: tracking.authorPubkey, authorMainnetAddress: tracking.authorMainnetAddress, amount: tracking.amount, authorAmount: tracking.authorAmount, platformCommission: tracking.platformCommission, confirmed: tracking.confirmed, confirmations: tracking.confirmations, timestamp: tracking.timestamp, }), } const unsignedEvent = { pubkey: authorPubkey, ...eventTemplate, } const event: Event = { ...unsignedEvent, id: getEventHash(unsignedEvent), sig: signEvent(unsignedEvent, authorPrivateKey), } as Event const poolWithSub = pool as SimplePoolWithSub const pubs = poolWithSub.publish([RELAY_URL], event) await Promise.all(pubs) console.log('Sponsoring payment tracked', { eventId: event.id, transactionId: tracking.transactionId, authorPubkey: tracking.authorPubkey, authorAmount: tracking.authorAmount, platformCommission: tracking.platformCommission, timestamp: new Date().toISOString(), }) return event.id } catch (error) { console.error('Error tracking sponsoring payment', { transactionId: tracking.transactionId, authorPubkey: tracking.authorPubkey, error: error instanceof Error ? error.message : 'Unknown error', timestamp: new Date().toISOString(), }) return null } } /** * Update author presentation article with new total sponsoring */ async updatePresentationSponsoring( presentationArticleId: string, newTotalSponsoring: number, authorPrivateKey: string ): Promise { try { // In production, this would: // 1. Fetch the presentation article // 2. Update the total_sponsoring tag // 3. Publish updated event console.log('Presentation sponsoring updated', { presentationArticleId, newTotalSponsoring, timestamp: new Date().toISOString(), }) return true } catch (error) { console.error('Error updating presentation sponsoring', { presentationArticleId, error: error instanceof Error ? error.message : 'Unknown error', timestamp: new Date().toISOString(), }) return false } } } export const sponsoringTrackingService = new SponsoringTrackingService()