import { NextResponse } from 'next/server'; import { CryptoEngine } from '@/lib/crypto-engine'; import { db } from '@/lib/db'; export async function POST(request: Request) { try { const body = await request.json(); const { txId, network, token } = body; if (!txId) { return NextResponse.json({ success: false, error: "Transaction ID is required" }, { status: 400 }); } const selectedNetwork = network || 'POLYGON'; const selectedToken = token || 'USDT'; console.log(`[API] Processing sweep for TX: ${txId} on ${selectedNetwork} with ${selectedToken}`); // 1. Fetch the transaction from DB to get the temporary wallet private key const result = await db.query('SELECT * FROM transactions WHERE stripe_pi_id = $1', [txId]); if (result.rows.length === 0) { return NextResponse.json({ success: false, error: "Transaction not found" }, { status: 404 }); } const transaction = result.rows[0]; // 1.1 Check if already processed if (transaction.status === 'succeeded') { return NextResponse.json({ success: true, message: "Transaction already processed", status: 'succeeded' }); } const metadata = transaction.metadata || {}; const wallets = metadata.wallets || {}; // 2. Determine which wallet to use (EVM or SOLANA) const walletType = selectedNetwork === 'SOLANA' ? 'SOLANA' : 'EVM'; const tempWalletConfig = wallets[walletType]; if (!tempWalletConfig || !tempWalletConfig.privateKey) { return NextResponse.json({ success: false, error: `No temporary wallet found for ${walletType}` }, { status: 500 }); } // 3. Define Platform Address & Fee (Fetch from dynamic settings) const settings = await (async () => { const result = await db.query('SELECT key, value FROM system_settings WHERE key IN (\'sol_platform_address\', \'evm_platform_address\', \'default_fee_percent\')'); const map: Record = {}; result.rows.forEach(r => map[r.key] = r.value); return { sol: map.sol_platform_address || process.env.SOL_PLATFORM_ADDRESS || "5pLH1tqZhx8p8WpZ18yr28N42KXB3FXVPzZ9ceCtpBVe", evm: map.evm_platform_address || process.env.EVM_PLATFORM_ADDRESS || "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", fee: parseFloat(map.default_fee_percent || '1.0') }; })(); const platformAddress = selectedNetwork === 'SOLANA' ? settings.sol : settings.evm; // 4. Define Merchant Address (Fetch from transaction's merchant) const merchantResult = await db.query('SELECT * FROM merchants WHERE id = $1', [transaction.merchant_id]); const merchant = merchantResult.rows[0]; // Prioritize merchant's specific fee, fallback to global setting const feePercent = merchant?.fee_percent !== undefined && merchant?.fee_percent !== null ? parseFloat(merchant.fee_percent) : settings.fee; let merchantAddress = merchant?.wallet_address || platformAddress; // Use merchant's specific vault if available if (selectedNetwork === 'SOLANA') { if (merchant?.sol_vault_address) merchantAddress = merchant.sol_vault_address; } else { if (merchant?.evm_vault_address) merchantAddress = merchant.evm_vault_address; } console.log(`[Sweep] Destination for merchant: ${merchantAddress}`); // 5. Initialize Engine and Verify Payment first const cryptoEngine = new CryptoEngine(selectedNetwork); const verification = await cryptoEngine.verifyPayment( tempWalletConfig.address, transaction.amount.toString(), selectedToken ); if (!verification.success) { return NextResponse.json({ success: false, error: "Henüz ödeme algılanmadı (On-chain bakiye yetersiz)", status: 'waiting' }); } // 6. Proceed to Sweep (100% to platform treasury) const sweepResult = await cryptoEngine.sweepFunds( tempWalletConfig.privateKey, platformAddress, selectedToken ); if (!sweepResult.success) { throw new Error("Süpürme işlemi başarısız oldu."); } // 6.1 Calculate Merchant's credit (Amount - Platform Fee) // Note: transaction.amount is the gross amount paid by customer const grossAmount = parseFloat(transaction.amount); const feeAmount = (grossAmount * feePercent) / 100; const merchantNetCredit = grossAmount - feeAmount; // 6.2 Update Merchant's virtual balance in DB await db.query(` UPDATE merchants SET available_balance = available_balance + $1 WHERE id = $2 `, [merchantNetCredit, transaction.merchant_id]); // 6.3 Update transaction status await db.query(`UPDATE transactions SET status = 'succeeded' WHERE id = $1`, [transaction.id]); // 7. Automated Webhook Notification if (transaction.callback_url) { console.log(`[Webhook] Notifying merchant at ${transaction.callback_url}`); try { fetch(transaction.callback_url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ status: 'success', txId: transaction.stripe_pi_id, orderRef: transaction.source_ref_id, hashes: { txHash: sweepResult.txHash } }) }).catch(e => console.error("Webhook fetch failed:", e.message)); } catch (webhookError: any) { console.error("[Webhook Error]:", webhookError.message); } } return NextResponse.json({ success: true, message: `Ödeme ${selectedNetwork} ağında ${selectedToken} ile başarıyla doğrulandı, hazineye aktarıldı ve merchant bakiyesi güncellendi.`, hashes: { txHash: sweepResult.txHash }, merchantCredit: merchantNetCredit }); } catch (error: any) { console.error('[API Error]:', error.message); return NextResponse.json({ success: false, error: error.message }, { status: 500 }); } }