import { calculateSponsoringSplit } from './platformCommissions' import { PLATFORM_BITCOIN_ADDRESS } from './platformConfig' import type { SponsoringPaymentRequest, SponsoringPaymentResult } from './sponsoringPaymentTypes' import { validateSponsoringAmount, buildErrorResult, isValidBitcoinAddress } from './sponsoringPaymentValidation' import { verifySponsoringPayment } from './sponsoringPaymentVerification' import { trackSponsoringPayment } from './sponsoringPaymentTracking' /** * Sponsoring payment service * Handles Bitcoin mainnet payments for sponsoring with automatic commission split * * Sponsoring: 0.046 BTC total * - Author: 0.042 BTC (4,200,000 sats) * - Platform: 0.004 BTC (400,000 sats) * * Since Bitcoin mainnet doesn't support automatic split like Lightning, * we use a two-output transaction approach: * 1. User creates transaction with two outputs (author + platform) * 2. Platform verifies both outputs are present * 3. Transaction is broadcast */ export type { SponsoringPaymentRequest, SponsoringPaymentResult } from './sponsoringPaymentTypes' export class SponsoringPaymentService { /** * Create sponsoring payment request with split information * Returns addresses and amounts for the user to create a Bitcoin transaction */ async createSponsoringPayment(request: SponsoringPaymentRequest): Promise { try { const amountValidation = validateSponsoringAmount(request.amount) if (!amountValidation.valid) { return buildErrorResult(amountValidation.error ?? 'Invalid amount', request) } const split = calculateSponsoringSplit(request.amount) if (!isValidBitcoinAddress(request.authorMainnetAddress)) { return buildErrorResult('Invalid author Bitcoin address', request) } console.log('Sponsoring payment request created', { authorPubkey: request.authorPubkey, authorAddress: request.authorMainnetAddress, platformAddress: PLATFORM_BITCOIN_ADDRESS, authorAmount: split.authorSats, platformAmount: split.platformSats, totalAmount: split.totalSats, timestamp: new Date().toISOString(), }) return { success: true, split, platformAddress: PLATFORM_BITCOIN_ADDRESS, authorAddress: request.authorMainnetAddress, } } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error' console.error('Error creating sponsoring payment', { authorPubkey: request.authorPubkey, error: errorMessage, timestamp: new Date().toISOString(), }) return buildErrorResult(errorMessage, request) } } /** * Verify sponsoring payment transaction * Checks that transaction has correct outputs for both author and platform * Uses mempool.space API to verify the transaction */ async verifySponsoringPayment( transactionId: string, authorPubkey: string, authorMainnetAddress: string ): Promise { return await verifySponsoringPayment(transactionId, authorPubkey, authorMainnetAddress) } /** * Track sponsoring payment */ async trackSponsoringPayment( transactionId: string, authorPubkey: string, authorMainnetAddress: string, authorPrivateKey: string ): Promise { return await trackSponsoringPayment(transactionId, authorPubkey, authorMainnetAddress, authorPrivateKey) } } export const sponsoringPaymentService = new SponsoringPaymentService()