96 lines
3.5 KiB
TypeScript
96 lines
3.5 KiB
TypeScript
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<SponsoringPaymentResult> {
|
|
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<boolean> {
|
|
return await verifySponsoringPayment(transactionId, authorPubkey, authorMainnetAddress)
|
|
}
|
|
|
|
/**
|
|
* Track sponsoring payment
|
|
*/
|
|
async trackSponsoringPayment(
|
|
transactionId: string,
|
|
authorPubkey: string,
|
|
authorMainnetAddress: string,
|
|
authorPrivateKey: string
|
|
): Promise<void> {
|
|
return await trackSponsoringPayment(transactionId, authorPubkey, authorMainnetAddress, authorPrivateKey)
|
|
}
|
|
}
|
|
|
|
export const sponsoringPaymentService = new SponsoringPaymentService()
|