- Intégration mempool.space pour vérification transactions Bitcoin : - Service MempoolSpaceService avec API mempool.space - Vérification sorties et montants pour sponsoring - Vérification confirmations - Attente confirmation avec polling - Récupération adresses Lightning depuis profils Nostr : - Service LightningAddressService - Support lud16 et lud06 (NIP-19) - Cache avec TTL 1 heure - Intégré dans paymentPolling et reviewReward - Mise à jour événements Nostr pour avis rémunérés : - Publication événement avec tags rewarded et reward_amount - Parsing tags dans parseReviewFromEvent - Vérification doublons - Tracking sponsoring sur Nostr : - Service SponsoringTrackingService - Événements avec commissions et confirmations - Intégration vérification mempool.space Toutes les fonctionnalités de split sont maintenant opérationnelles. Seuls les transferts Lightning réels nécessitent un nœud Lightning.
148 lines
4.7 KiB
TypeScript
148 lines
4.7 KiB
TypeScript
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<string | null> {
|
|
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<boolean> {
|
|
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()
|
|
|