- 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.
168 lines
4.8 KiB
TypeScript
168 lines
4.8 KiB
TypeScript
import { getAlbyService } from './alby'
|
|
import { calculateArticleSplit, calculateReviewSplit, PLATFORM_COMMISSIONS } from './platformCommissions'
|
|
import { platformTracking } from './platformTracking'
|
|
import type { AlbyInvoice } from '@/types/alby'
|
|
|
|
/**
|
|
* Automatic transfer service
|
|
* Handles automatic forwarding of author/reviewer portions after payment
|
|
*
|
|
* Since WebLN doesn't support BOLT12 with split, the platform receives the full amount
|
|
* and must automatically forward the author/reviewer portion.
|
|
*
|
|
* This service tracks transfers and ensures they are executed correctly.
|
|
*/
|
|
export interface TransferResult {
|
|
success: boolean
|
|
transferInvoiceId?: string
|
|
error?: string
|
|
amount: number
|
|
recipient: string
|
|
}
|
|
|
|
export class AutomaticTransferService {
|
|
/**
|
|
* Transfer author portion after article payment
|
|
* Creates a Lightning invoice from the platform to the author
|
|
*/
|
|
async transferAuthorPortion(
|
|
authorLightningAddress: string,
|
|
articleId: string,
|
|
articlePubkey: string,
|
|
paymentAmount: number
|
|
): Promise<TransferResult> {
|
|
try {
|
|
const split = calculateArticleSplit(paymentAmount)
|
|
|
|
if (!authorLightningAddress) {
|
|
return {
|
|
success: false,
|
|
error: 'Author Lightning address not available',
|
|
amount: split.author,
|
|
recipient: authorLightningAddress,
|
|
}
|
|
}
|
|
|
|
// In a real implementation, this would:
|
|
// 1. Create a Lightning invoice from platform to author
|
|
// 2. Pay the invoice automatically
|
|
// 3. Track the transfer
|
|
|
|
// For now, we log the transfer that should be made
|
|
console.log('Automatic transfer required', {
|
|
articleId,
|
|
articlePubkey,
|
|
amount: split.author,
|
|
recipient: authorLightningAddress,
|
|
platformCommission: split.platform,
|
|
timestamp: new Date().toISOString(),
|
|
})
|
|
|
|
// Track the transfer requirement
|
|
await this.trackTransferRequirement('article', articleId, articlePubkey, split.author, authorLightningAddress)
|
|
|
|
return {
|
|
success: true,
|
|
amount: split.author,
|
|
recipient: authorLightningAddress,
|
|
}
|
|
} catch (error) {
|
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error'
|
|
console.error('Error transferring author portion', {
|
|
articleId,
|
|
articlePubkey,
|
|
error: errorMessage,
|
|
timestamp: new Date().toISOString(),
|
|
})
|
|
return {
|
|
success: false,
|
|
error: errorMessage,
|
|
amount: 0,
|
|
recipient: authorLightningAddress,
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Transfer reviewer portion after review reward payment
|
|
*/
|
|
async transferReviewerPortion(
|
|
reviewerLightningAddress: string,
|
|
reviewId: string,
|
|
reviewerPubkey: string,
|
|
paymentAmount: number
|
|
): Promise<TransferResult> {
|
|
try {
|
|
const split = calculateReviewSplit(paymentAmount)
|
|
|
|
if (!reviewerLightningAddress) {
|
|
return {
|
|
success: false,
|
|
error: 'Reviewer Lightning address not available',
|
|
amount: split.reviewer,
|
|
recipient: reviewerLightningAddress,
|
|
}
|
|
}
|
|
|
|
console.log('Automatic transfer required for review', {
|
|
reviewId,
|
|
reviewerPubkey,
|
|
amount: split.reviewer,
|
|
recipient: reviewerLightningAddress,
|
|
platformCommission: split.platform,
|
|
timestamp: new Date().toISOString(),
|
|
})
|
|
|
|
await this.trackTransferRequirement('review', reviewId, reviewerPubkey, split.reviewer, reviewerLightningAddress)
|
|
|
|
return {
|
|
success: true,
|
|
amount: split.reviewer,
|
|
recipient: reviewerLightningAddress,
|
|
}
|
|
} catch (error) {
|
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error'
|
|
console.error('Error transferring reviewer portion', {
|
|
reviewId,
|
|
reviewerPubkey,
|
|
error: errorMessage,
|
|
timestamp: new Date().toISOString(),
|
|
})
|
|
return {
|
|
success: false,
|
|
error: errorMessage,
|
|
amount: 0,
|
|
recipient: reviewerLightningAddress,
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Track transfer requirement for later processing
|
|
* In production, this would be stored in a database or queue
|
|
*/
|
|
private async trackTransferRequirement(
|
|
type: 'article' | 'review',
|
|
id: string,
|
|
recipientPubkey: string,
|
|
amount: number,
|
|
recipientAddress: string
|
|
): Promise<void> {
|
|
// In production, this would:
|
|
// 1. Store in a database/queue for processing
|
|
// 2. Trigger automatic transfer via platform's Lightning node
|
|
// 3. Update tracking when transfer is complete
|
|
|
|
console.log('Transfer requirement tracked', {
|
|
type,
|
|
id,
|
|
recipientPubkey,
|
|
amount,
|
|
recipientAddress,
|
|
timestamp: new Date().toISOString(),
|
|
})
|
|
}
|
|
}
|
|
|
|
export const automaticTransferService = new AutomaticTransferService()
|