story-research-zapwall/lib/paymentSplit.ts
Nicolas Cantu 90ff8282f1 feat: Implémentation système de commissions systématique et incontournable
- 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.
2025-12-27 21:11:09 +01:00

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()