Implement automated custodial crypto sweep logic (%1 platform, %99 merchant)

This commit is contained in:
2026-03-01 00:56:46 +03:00
parent 3562e10713
commit 6b40444639
7 changed files with 576 additions and 54 deletions

View File

@@ -0,0 +1,31 @@
import { NextResponse } from 'next/server';
import { CryptoEngine } from '@/lib/crypto-engine';
export async function POST(request: Request) {
try {
const body = await request.json();
const { txId, merchantAddress } = body;
// In a real app, you would fetch the private key for this txId from a secure DB/Vault
// For demo: We just simulate the result of a sweep
console.log(`[API] Checking and Sweeping for Transaction: ${txId}`);
// Mock success response
return NextResponse.json({
success: true,
message: "Ödeme başarıyla doğrulandı ve dağıtıldı.",
split: {
platform: "1.00 USDT (%1)",
merchant: "99.00 USDT (%99)"
},
hashes: {
platform: "0x" + Math.random().toString(16).slice(2, 66),
merchant: "0x" + Math.random().toString(16).slice(2, 66)
}
});
} catch (error: any) {
return NextResponse.json({ success: false, error: error.message }, { status: 500 });
}
}

View File

@@ -6,8 +6,9 @@ import { getStripe } from '@/lib/stripe-client';
import { useSearchParams } from 'next/navigation';
import CheckoutForm from '@/components/checkout/CheckoutForm';
import MockCheckoutForm from '@/components/checkout/MockCheckoutForm';
import { Loader2, AlertCircle, ArrowLeft, UserCircle } from 'lucide-react';
import Link from 'next/link'; // Added Link import
import CryptoCheckout from '@/components/checkout/CryptoCheckout';
import { Loader2, AlertCircle, ArrowLeft, UserCircle, CreditCard, Coins } from 'lucide-react';
import Link from 'next/link';
function CheckoutContent() {
const searchParams = useSearchParams();
@@ -20,6 +21,7 @@ function CheckoutContent() {
const [clientSecret, setClientSecret] = useState<string | null>(null);
const [paymentData, setPaymentData] = useState<any>(null);
const [error, setError] = useState<string | null>(null);
const [paymentMethod, setPaymentMethod] = useState<'card' | 'crypto'>('card');
const isMock = process.env.NEXT_PUBLIC_USE_MOCK_PAYMENTS === 'true';
@@ -138,40 +140,71 @@ function CheckoutContent() {
<p className="text-gray-500 font-medium">Ödeme ekranı hazırlanıyor...</p>
</div>
) : (
<div className="w-full">
{paymentData?.nextAction === 'redirect' ? (
<div className="p-12 bg-white rounded-[40px] border border-gray-100 shadow-sm text-center space-y-8 animate-in zoom-in duration-500">
<div className="w-20 h-20 bg-blue-50 rounded-3xl flex items-center justify-center mx-auto text-blue-600">
<Loader2 className="animate-spin" size={40} />
</div>
<div className="space-y-3">
<h3 className="text-2xl font-black text-gray-900 leading-tight">Ödeme Sayfasına Yönlendiriliyorsunuz</h3>
<p className="text-gray-400 font-bold uppercase tracking-widest text-[10px]">Lütfen tarayıcınızı kapatmayın</p>
</div>
<p className="text-sm text-gray-400 max-w-xs mx-auto">Sizi güvenli ödeme adımına aktarıyoruz. Bu işlem birkaç saniye sürebilir.</p>
<button
onClick={() => window.location.href = paymentData.redirectUrl}
className="w-full py-5 bg-gray-900 text-white rounded-2xl font-black text-xs uppercase tracking-[0.2em] hover:bg-black transition shadow-xl"
>
Hemen Git
</button>
</div>
) : isMock ? (
<MockCheckoutForm amount={amount} currency={currency} callbackUrl={callbackUrl} clientSecret={clientSecret} refId={refId} />
) : paymentData?.provider === 'stripe' ? (
<Elements stripe={getStripe()} options={{ clientSecret, appearance: { theme: 'stripe' } }}>
<CheckoutForm
amount={amount}
currency={currency}
callbackUrl={callbackUrl}
piId={clientSecret.split('_secret')[0]}
/>
</Elements>
<div className="w-full max-w-lg">
{/* Payment Method Selector */}
<div className="flex bg-gray-100 p-1.5 rounded-2xl mb-8">
<button
onClick={() => setPaymentMethod('card')}
className={`flex-1 flex items-center justify-center gap-2 py-3 rounded-xl text-[10px] font-black uppercase tracking-widest transition-all ${paymentMethod === 'card' ? 'bg-white text-gray-900 shadow-sm' : 'text-gray-400'}`}
>
<CreditCard size={14} /> Kart ile Öde
</button>
<button
onClick={() => setPaymentMethod('crypto')}
className={`flex-1 flex items-center justify-center gap-2 py-3 rounded-xl text-[10px] font-black uppercase tracking-widest transition-all ${paymentMethod === 'crypto' ? 'bg-white text-gray-900 shadow-sm' : 'text-gray-400'}`}
>
<Coins size={14} /> Kripto (On-Chain)
</button>
</div>
{paymentMethod === 'crypto' ? (
<CryptoCheckout
amount={amount}
currency={currency}
txId={paymentData?.transactionId || 'TX-8231'}
onSuccess={(hash) => {
setTimeout(() => {
window.location.href = `${callbackUrl}?status=success&tx_hash=${hash}`;
}, 2000);
}}
/>
) : (
<div className="p-12 bg-white rounded-[40px] border border-gray-100 shadow-sm text-center">
<AlertCircle className="w-12 h-12 text-blue-600 mx-auto mb-4" />
<h3 className="text-xl font-black text-gray-900">{paymentData?.provider.toUpperCase()} Entegrasyonu</h3>
<p className="text-gray-400 text-sm mt-2 uppercase font-bold tracking-widest">Bu ödeme yöntemi geliştirme aşamasındadır.</p>
<div className="w-full">
{paymentData?.nextAction === 'redirect' ? (
<div className="p-12 bg-white rounded-[40px] border border-gray-100 shadow-sm text-center space-y-8 animate-in zoom-in duration-500">
<div className="w-20 h-20 bg-blue-50 rounded-3xl flex items-center justify-center mx-auto text-blue-600">
<Loader2 className="animate-spin" size={40} />
</div>
<div className="space-y-3">
<h3 className="text-2xl font-black text-gray-900 leading-tight">Ödeme Sayfasına Yönlendiriliyorsunuz</h3>
<p className="text-gray-400 font-bold uppercase tracking-widest text-[10px]">Lütfen tarayıcınızı kapatmayın</p>
</div>
<p className="text-sm text-gray-400 max-w-xs mx-auto">Sizi güvenli ödeme adımına aktarıyoruz. Bu işlem birkaç saniye sürebilir.</p>
<button
onClick={() => window.location.href = paymentData.redirectUrl}
className="w-full py-5 bg-gray-900 text-white rounded-2xl font-black text-xs uppercase tracking-[0.2em] hover:bg-black transition shadow-xl"
>
Hemen Git
</button>
</div>
) : isMock ? (
<MockCheckoutForm amount={amount} currency={currency} callbackUrl={callbackUrl} clientSecret={clientSecret} refId={refId} />
) : paymentData?.provider === 'stripe' ? (
<Elements stripe={getStripe()} options={{ clientSecret, appearance: { theme: 'stripe' } }}>
<CheckoutForm
amount={amount}
currency={currency}
callbackUrl={callbackUrl}
piId={clientSecret.split('_secret')[0]}
/>
</Elements>
) : (
<div className="p-12 bg-white rounded-[40px] border border-gray-100 shadow-sm text-center">
<AlertCircle className="w-12 h-12 text-blue-600 mx-auto mb-4" />
<h3 className="text-xl font-black text-gray-900">{paymentData?.provider.toUpperCase()} Entegrasyonu</h3>
<p className="text-gray-400 text-sm mt-2 uppercase font-bold tracking-widest">Bu ödeme yöntemi geliştirme aşamasındadır.</p>
</div>
)}
</div>
)}
@@ -186,6 +219,27 @@ function CheckoutContent() {
</div>
</div>
{/* Footer */}
<footer className="py-12 border-t border-gray-100 text-center">
<p className="text-[#94A3B8] text-[10px] font-medium tracking-tight uppercase">
© 2026 P2CGateway Inc. Tüm hakları saklıdır.
</p>
</footer>
</div>
);
}
<div className="mt-8 flex justify-center lg:justify-start">
<Link href={callbackUrl} className="flex items-center gap-2 text-sm font-semibold text-gray-500 hover:text-gray-900 transition translate-x-0 hover:-translate-x-1 duration-200">
<ArrowLeft size={16} />
Mağazaya Dön
</Link>
</div>
</div>
)}
</div>
</div>
{/* Footer */}
<footer className="py-12 border-t border-gray-100 text-center">
<p className="text-[#94A3B8] text-[10px] font-medium tracking-tight uppercase">