- Split pour sponsoring (Bitcoin mainnet) : - Service SponsoringPaymentService avec calcul split (0.042/0.004 BTC) - Validation montants et adresses Bitcoin - Structure pour vérification transactions - Split pour avis (Lightning) : - Service ReviewRewardService avec commission (49/21 sats) - Création invoice avec split - Transfert automatique reviewer portion - Mise à jour avis avec tag rewarded - Système transfert automatique : - Service AutomaticTransferService - Transfert auteur portion après paiement article - Transfert reviewer portion après rémunération avis - Tracking et logs structurés - Intégration dans paymentPolling pour articles - Documentation complète du système Les services sont prêts pour intégration avec nœud Lightning et services blockchain.
169 lines
4.8 KiB
TypeScript
169 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()
|
|
|