- Création lib/platformCommissions.ts : configuration centralisée des commissions - Articles : 800 sats (700 auteur, 100 plateforme) - Avis : 70 sats (49 lecteur, 21 plateforme) - Sponsoring : 0.046 BTC (0.042 auteur, 0.004 plateforme) - Validation des montants à chaque étape : - Publication : vérification du montant avant publication - Paiement : vérification du montant avant acceptation - Erreurs explicites si montant incorrect - Tracking des commissions sur Nostr : - Tags author_amount et platform_commission dans événements - Interface ContentDeliveryTracking étendue - Traçabilité complète pour audit - Logs structurés avec informations de commission - Documentation complète du système Les commissions sont maintenant systématiques, validées et traçables.
104 lines
2.9 KiB
TypeScript
104 lines
2.9 KiB
TypeScript
import { getAlbyService } from './alby'
|
|
import { PLATFORM_LIGHTNING_ADDRESS, calculateArticleSplit, calculateReviewSplit } from './platformCommissions'
|
|
import type { AlbyInvoice } from '@/types/alby'
|
|
|
|
/**
|
|
* Payment split service
|
|
* Handles automatic commission splitting for platform payments
|
|
*
|
|
* Since WebLN doesn't support BOLT12, we use a two-step approach:
|
|
* 1. Platform creates invoice for full amount
|
|
* 2. Platform automatically forwards author/reviewer portion after payment
|
|
*
|
|
* This ensures commissions are always collected and tracked.
|
|
*/
|
|
export class PaymentSplitService {
|
|
/**
|
|
* Create invoice with commission split for article payment
|
|
* Returns invoice for full amount (800 sats) that will be split after payment
|
|
*/
|
|
async createArticleInvoiceWithSplit(
|
|
authorLightningAddress: string,
|
|
articleTitle: string
|
|
): Promise<{
|
|
invoice: AlbyInvoice
|
|
split: { author: number; platform: number; total: number }
|
|
}> {
|
|
const split = calculateArticleSplit()
|
|
const alby = getAlbyService()
|
|
await alby.enable()
|
|
|
|
const invoice = await alby.createInvoice({
|
|
amount: split.total,
|
|
description: `Article payment: ${articleTitle} (${split.author} sats to author, ${split.platform} sats commission)`,
|
|
expiry: 86400, // 24 hours
|
|
})
|
|
|
|
return {
|
|
invoice,
|
|
split,
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create invoice with commission split for review reward
|
|
* Returns invoice for full amount (70 sats) that will be split after payment
|
|
*/
|
|
async createReviewRewardInvoiceWithSplit(
|
|
reviewerLightningAddress: string,
|
|
reviewId: string
|
|
): Promise<{
|
|
invoice: AlbyInvoice
|
|
split: { reviewer: number; platform: number; total: number }
|
|
}> {
|
|
const split = calculateReviewSplit()
|
|
const alby = getAlbyService()
|
|
await alby.enable()
|
|
|
|
const invoice = await alby.createInvoice({
|
|
amount: split.total,
|
|
description: `Review reward: ${reviewId} (${split.reviewer} sats to reviewer, ${split.platform} sats commission)`,
|
|
expiry: 3600, // 1 hour
|
|
})
|
|
|
|
return {
|
|
invoice,
|
|
split,
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Verify that payment amount matches expected split
|
|
*/
|
|
verifyPaymentSplit(
|
|
type: 'article' | 'review',
|
|
paidAmount: number,
|
|
expectedSplit: { author?: number; reviewer?: number; platform: number; total: number }
|
|
): boolean {
|
|
if (paidAmount !== expectedSplit.total) {
|
|
return false
|
|
}
|
|
|
|
// Verify split amounts match expected commission structure
|
|
if (type === 'article') {
|
|
const articleSplit = calculateArticleSplit()
|
|
return (
|
|
expectedSplit.author === articleSplit.author &&
|
|
expectedSplit.platform === articleSplit.platform
|
|
)
|
|
}
|
|
|
|
if (type === 'review') {
|
|
const reviewSplit = calculateReviewSplit()
|
|
return (
|
|
expectedSplit.reviewer === reviewSplit.reviewer &&
|
|
expectedSplit.platform === reviewSplit.platform
|
|
)
|
|
}
|
|
|
|
return false
|
|
}
|
|
}
|
|
|
|
export const paymentSplitService = new PaymentSplitService()
|