From 2d435a4ee84b132506927c6b35c436f5d40b6c7c Mon Sep 17 00:00:00 2001 From: mstfyldz Date: Fri, 13 Mar 2026 00:34:42 +0300 Subject: [PATCH] feat: merchant specific fees, TRON & BTC support, coin logos, and bug fixes --- .gitignore | 1 + app/admin/merchants/new/page.tsx | 25 +- app/admin/merchants/page.tsx | 27 +- app/admin/settings/page.tsx | 39 ++- app/api/admin/settings/route.ts | 6 +- app/api/create-payment-intent/route.ts | 10 +- app/api/crypto-sweep/route.ts | 20 +- app/api/merchants/[id]/route.ts | 6 +- app/api/merchants/route.ts | 8 +- app/merchant/[id]/login/page.tsx | 9 +- app/merchant/register/page.tsx | 164 ++-------- components/checkout/CryptoCheckout.tsx | 23 +- lib/crypto-config.json | 81 +++-- lib/crypto-engine.ts | 100 +++++- next-env.d.ts | 6 + package-lock.json | 410 ++++++++++++++++++++++++- package.json | 6 +- 17 files changed, 708 insertions(+), 233 deletions(-) create mode 100644 next-env.d.ts diff --git a/.gitignore b/.gitignore index 1d9bfec..3e7fbbd 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,4 @@ yarn-error.log* # sensitive scripts /scripts/show-vaults.ts /scripts/migrate-settings.ts +/scripts/migrate-merchant-fees.ts diff --git a/app/admin/merchants/new/page.tsx b/app/admin/merchants/new/page.tsx index b5ff132..8e0054e 100644 --- a/app/admin/merchants/new/page.tsx +++ b/app/admin/merchants/new/page.tsx @@ -20,6 +20,7 @@ export default function NewMerchantPage() { const [name, setName] = useState(''); const [webhookUrl, setWebhookUrl] = useState(''); const [paymentProvider, setPaymentProvider] = useState('stripe'); + const [feePercent, setFeePercent] = useState('1.0'); const [success, setSuccess] = useState(false); const handleSubmit = async (e: React.FormEvent) => { @@ -33,7 +34,8 @@ export default function NewMerchantPage() { body: JSON.stringify({ name, webhook_url: webhookUrl, - payment_provider: paymentProvider + payment_provider: paymentProvider, + fee_percent: parseFloat(feePercent || '1.0') }), }); @@ -141,6 +143,27 @@ export default function NewMerchantPage() { + {/* Fee Percentage Input */} +
+ +
+
%
+ setFeePercent(e.target.value)} + placeholder="1.0" + className="w-full pl-8 pr-12 py-5 bg-gray-50 border-2 border-transparent focus:border-blue-100 focus:bg-white rounded-3xl text-lg font-black text-gray-900 outline-none transition-all placeholder:text-gray-300" + /> +
+

+ Bu firmadan her işlemde kesilecek platform payı. (Varsayılan: %1.0) +

+
+ {/* Webhook Input */}
diff --git a/app/admin/merchants/page.tsx b/app/admin/merchants/page.tsx index 16d8510..e609615 100644 --- a/app/admin/merchants/page.tsx +++ b/app/admin/merchants/page.tsx @@ -63,7 +63,8 @@ export default function MerchantsPage() { name: editingMerchant.name, webhook_url: editingMerchant.webhook_url, payment_provider: editingMerchant.payment_provider, - provider_config: editingMerchant.provider_config + provider_config: editingMerchant.provider_config, + fee_percent: editingMerchant.fee_percent }) }); if (!response.ok) throw new Error('Güncelleme başarısız.'); @@ -136,9 +137,11 @@ export default function MerchantsPage() {

{m.name}

-
+
ID: {identifier} - {m.short_id && Short Link Active} +
+ Fee: %{m.fee_percent || '1.0'} +
@@ -307,6 +310,24 @@ export default function MerchantsPage() { +
+ +
+
%
+ setEditingMerchant({ ...editingMerchant, fee_percent: e.target.value })} + placeholder="1.0" + className="w-full pl-6 pr-12 py-4 bg-gray-50 border-2 border-transparent focus:border-blue-500 focus:bg-white rounded-[24px] outline-none transition-all font-bold text-gray-900 placeholder:text-gray-300" + /> +
+

Bu firmaya özel kesinti oranı. Boş bırakılırsa sistem varsayılanı kullanılır.

+
+
diff --git a/app/admin/settings/page.tsx b/app/admin/settings/page.tsx index 212068e..0dfb22b 100644 --- a/app/admin/settings/page.tsx +++ b/app/admin/settings/page.tsx @@ -16,7 +16,8 @@ import { export default function AdminSettingsPage() { const [settings, setSettings] = useState({ sol_platform_address: '', - evm_platform_address: '' + evm_platform_address: '', + default_fee_percent: '1.0' }); const [isLoading, setIsLoading] = useState(true); const [isSaving, setIsSaving] = useState(false); @@ -34,7 +35,8 @@ export default function AdminSettingsPage() { if (data.error) throw new Error(data.error); setSettings({ sol_platform_address: data.sol_platform_address || '', - evm_platform_address: data.evm_platform_address || '' + evm_platform_address: data.evm_platform_address || '', + default_fee_percent: data.default_fee_percent || '1.0' }); } catch (err: any) { setMessage({ type: 'error', text: 'Ayarlar yüklenemedi: ' + err.message }); @@ -65,7 +67,7 @@ export default function AdminSettingsPage() { }; return ( -
+
{/* Header */}
@@ -80,6 +82,37 @@ export default function AdminSettingsPage() { {/* Main Form */}
+ {/* Fee Setting Card */} +
+
+
+ +
+
+

Komisyon (Fee) Ayarları

+

Sistem geneli varsayılan işlem kesintisi

+
+
+ +
+ +
+
%
+ setSettings({ ...settings, default_fee_percent: e.target.value })} + className="w-full pl-8 pr-12 py-5 bg-gray-50 border-2 border-transparent focus:border-emerald-500 focus:bg-white rounded-[24px] outline-none transition-all font-black text-gray-900 text-lg" + /> +
+

Örn: 1.0 (Yüzde bir), 2.5 (Yüzde iki buçuk)

+
+
+ {/* Platform Addresses Card */}
diff --git a/app/api/admin/settings/route.ts b/app/api/admin/settings/route.ts index 4b63d9d..04951f0 100644 --- a/app/api/admin/settings/route.ts +++ b/app/api/admin/settings/route.ts @@ -23,6 +23,7 @@ export async function GET() { // Fill defaults if empty if (!settings.sol_platform_address) settings.sol_platform_address = process.env.SOL_PLATFORM_ADDRESS || ''; if (!settings.evm_platform_address) settings.evm_platform_address = process.env.EVM_PLATFORM_ADDRESS || ''; + if (!settings.default_fee_percent) settings.default_fee_percent = '1.0'; return NextResponse.json(settings); } catch (err: any) { @@ -33,11 +34,12 @@ export async function GET() { export async function POST(req: NextRequest) { try { const body = await req.json(); - const { sol_platform_address, evm_platform_address } = body; + const { sol_platform_address, evm_platform_address, default_fee_percent } = body; const queries = [ { key: 'sol_platform_address', value: sol_platform_address }, - { key: 'evm_platform_address', value: evm_platform_address } + { key: 'evm_platform_address', value: evm_platform_address }, + { key: 'default_fee_percent', value: default_fee_percent || '1.0' } ]; for (const q of queries) { diff --git a/app/api/create-payment-intent/route.ts b/app/api/create-payment-intent/route.ts index 17533dc..5d57455 100644 --- a/app/api/create-payment-intent/route.ts +++ b/app/api/create-payment-intent/route.ts @@ -74,10 +74,14 @@ export async function POST(req: NextRequest) { // 3. Generate Temporary Wallets for Crypto fallback const evmWallet = await CryptoEngine.createTemporaryWallet('POLYGON'); const solWallet = await CryptoEngine.createTemporaryWallet('SOLANA'); + const tronWallet = await CryptoEngine.createTemporaryWallet('TRON'); + const btcWallet = await CryptoEngine.createTemporaryWallet('BITCOIN'); const cryptoWallets = { EVM: { address: evmWallet.address, privateKey: evmWallet.privateKey }, - SOLANA: { address: solWallet.address, privateKey: solWallet.privateKey } + SOLANA: { address: solWallet.address, privateKey: solWallet.privateKey }, + TRON: { address: tronWallet.address, privateKey: tronWallet.privateKey }, + BITCOIN: { address: btcWallet.address, privateKey: btcWallet.privateKey } }; // 4. Log transaction in Supabase @@ -108,7 +112,9 @@ export async function POST(req: NextRequest) { provider, wallets: { EVM: evmWallet.address, - SOLANA: solWallet.address + SOLANA: solWallet.address, + TRON: tronWallet.address, + BITCOIN: btcWallet.address } }); } catch (err: any) { diff --git a/app/api/crypto-sweep/route.ts b/app/api/crypto-sweep/route.ts index 69617ae..f203eeb 100644 --- a/app/api/crypto-sweep/route.ts +++ b/app/api/crypto-sweep/route.ts @@ -45,22 +45,27 @@ export async function POST(request: Request) { return NextResponse.json({ success: false, error: `No temporary wallet found for ${walletType}` }, { status: 500 }); } - // 3. Define Platform Address (Fetch from dynamic settings) - const platformAddresses = await (async () => { - const result = await db.query('SELECT key, value FROM system_settings WHERE key IN (\'sol_platform_address\', \'evm_platform_address\')'); + // 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" + evm: map.evm_platform_address || process.env.EVM_PLATFORM_ADDRESS || "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + fee: parseFloat(map.default_fee_percent || '1.0') }; })(); - const platformAddress = selectedNetwork === 'SOLANA' ? platformAddresses.sol : platformAddresses.evm; - + 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; @@ -95,7 +100,8 @@ export async function POST(request: Request) { tempWalletConfig.privateKey, merchantAddress, platformAddress, - selectedToken + selectedToken, + feePercent ); if (!sweepResult.success) { diff --git a/app/api/merchants/[id]/route.ts b/app/api/merchants/[id]/route.ts index e3520e9..e29616a 100644 --- a/app/api/merchants/[id]/route.ts +++ b/app/api/merchants/[id]/route.ts @@ -29,7 +29,7 @@ export async function PATCH( ) { try { const { id } = await context.params; - const { name, webhook_url, payment_provider, provider_config } = await req.json(); + const { name, webhook_url, payment_provider, provider_config, fee_percent } = await req.json(); if (!name) { return NextResponse.json( @@ -39,8 +39,8 @@ export async function PATCH( } const result = await db.query( - 'UPDATE merchants SET name = $1, webhook_url = $2, payment_provider = $3, provider_config = $4 WHERE id = $5 RETURNING *', - [name, webhook_url, payment_provider, provider_config, id] + 'UPDATE merchants SET name = $1, webhook_url = $2, payment_provider = $3, provider_config = $4, fee_percent = $5 WHERE id = $6 RETURNING *', + [name, webhook_url, payment_provider, provider_config, fee_percent || 1.0, id] ); const data = result.rows[0]; diff --git a/app/api/merchants/route.ts b/app/api/merchants/route.ts index e5f3435..d5b32fa 100644 --- a/app/api/merchants/route.ts +++ b/app/api/merchants/route.ts @@ -3,7 +3,7 @@ import { db } from '@/lib/db'; export async function POST(req: NextRequest) { try { - const { name, webhook_url, payment_provider, provider_config } = await req.json(); + const { name, webhook_url, payment_provider, provider_config, fee_percent } = await req.json(); if (!name) { return NextResponse.json( @@ -27,9 +27,9 @@ export async function POST(req: NextRequest) { const configStr = provider_config ? JSON.stringify(provider_config) : '{}'; const result = await db.query( - `INSERT INTO merchants (name, webhook_url, short_id, payment_provider, provider_config) - VALUES ($1, $2, $3, $4, $5) RETURNING *`, - [name, webhook_url, shortId, provider, configStr] + `INSERT INTO merchants (name, webhook_url, short_id, payment_provider, provider_config, fee_percent) + VALUES ($1, $2, $3, $4, $5, $6) RETURNING *`, + [name, webhook_url, shortId, provider, configStr, fee_percent || 1.0] ); if (result.rows.length === 0) { diff --git a/app/merchant/[id]/login/page.tsx b/app/merchant/[id]/login/page.tsx index db8305a..f164e5b 100644 --- a/app/merchant/[id]/login/page.tsx +++ b/app/merchant/[id]/login/page.tsx @@ -85,18 +85,15 @@ export default function MerchantLoginPage() {
- +

+ Başvuru için satış ekibiyle iletişime geçin +

diff --git a/app/merchant/register/page.tsx b/app/merchant/register/page.tsx index d502e83..70dd910 100644 --- a/app/merchant/register/page.tsx +++ b/app/merchant/register/page.tsx @@ -11,158 +11,52 @@ export default function MerchantRegisterPage() { const [success, setSuccess] = useState(null); const router = useRouter(); - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - setIsLoading(true); - setError(''); - - try { - const response = await fetch('/api/merchants/register', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ name }) - }); - - const data = await response.json(); - - if (response.ok) { - setSuccess(data); - } else { - setError(data.error || 'Kayıt sırasında bir hata oluştu.'); - } - } catch (err) { - setError('Bağlantı hatası. Lütfen tekrar deneyin.'); - } finally { - setIsLoading(false); - } - }; - - if (success) { - return ( -
-
-
-
- -
-

Tebrikler!

-

Hesabınız Başarıyla Oluşturuldu

-
- -
-
- -
- -
-
-

Firma Yönetim Paneliniz

-
- /merchant/{success.shortId} - -
-
- -
-
-

Kritik Güvenlik Anahtarı

-

- Bu anahtarı güvenli bir yere kaydedin. Sisteme giriş yapmak için tek yönteminiz budur. Bir daha görüntülenemez! -

-
-
- {success.apiKey} - -
-
-
- - -
-
-
- ); - } - return (
-
+
-

Firma Kaydı

-

P2CGateway Merchant Network'e Katılın

+

Firma Başvurusu

+

P2CGateway Merchant Network

-
-
-

Firma adınızı belirleyin

-

- Müşterileriniz ödeme sayfasında bu ismi görecektir. +

+
+ +
+

Kayıtlar Şuan Başvuruya Dayalıdır

+

+ Güvenlik ve kalite standartlarımız gereği şu an için sadece ön başvurusu onaylanmış kurumsal firmaları kabul ediyoruz.

- -
- setName(e.target.value)} - placeholder="Örn: Ayris Teknoloji" - className="w-full px-6 py-4 bg-gray-50 border-2 border-transparent focus:border-blue-500 focus:bg-white rounded-[24px] outline-none transition-all font-bold text-gray-900 placeholder:text-gray-300" - /> - {error &&

{error}

} -
+
+

Nasıl Kayıt Olurum?

+

"P2CGateway ekibiyle iletişime geçerek başvuru formunuzu talep edin."

+
-
-

- * Kayıt olduktan sonra size özel bir yönetim paneli ve API anahtarı tahsis edilecektir. -

-
- - - -
- -
- +
-
- - End-to-End Secure Merchant Onboarding +
+ + Enterprise Secured Merchant Onboarding Flow
); diff --git a/components/checkout/CryptoCheckout.tsx b/components/checkout/CryptoCheckout.tsx index b5b427e..77f9694 100644 --- a/components/checkout/CryptoCheckout.tsx +++ b/components/checkout/CryptoCheckout.tsx @@ -167,21 +167,36 @@ export default function CryptoCheckout({ amount, currency, txId, wallets, onSucc +
+ {/* @ts-ignore */} + +
-
-
- {selectedToken.symbol === 'SOL' ? '☀️' : selectedToken.symbol.startsWith('U') ? '💵' : '🪙'} +
+
+ {/* @ts-ignore */} + {selectedToken.symbol}

Ödenecek Tutar

diff --git a/lib/crypto-config.json b/lib/crypto-config.json index 347732d..3932d3a 100644 --- a/lib/crypto-config.json +++ b/lib/crypto-config.json @@ -6,15 +6,15 @@ "icon": "🟣", "rpc": "https://rpc.ankr.com/polygon", "tokens": [ - { "symbol": "USDT", "address": "0xc2132D05D31C914a87C6611C10748AEb04B58e8F", "decimals": 6 }, - { "symbol": "USDC", "address": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", "decimals": 6 }, - { "symbol": "DAI", "address": "0x8f3Cf7ad23Cd3BaDDb9735AFf95930030000000", "decimals": 18 }, - { "symbol": "MATIC", "address": "NATIVE", "decimals": 18 }, - { "symbol": "WBTC", "address": "0x1bfd67037b42cf73acf2047067bd4f2c47d9bfd6", "decimals": 8 }, - { "symbol": "WETH", "address": "0x7ceb23fd6bc0ad59e62ac25578270cff1b9f619", "decimals": 18 }, - { "symbol": "SHIB", "address": "0x6f8a36397efed74758fdef2850935bb27d49e1ed", "decimals": 18 }, - { "symbol": "LINK", "address": "0xb0897686c545045aFc77CF20eC7A532E3120E0F1", "decimals": 18 }, - { "symbol": "PEPE", "address": "0x98f6d546343544fae8e60aaead11a68e64c29df6", "decimals": 18 } + { "symbol": "USDT", "address": "0xc2132D05D31C914a87C6611C10748AEb04B58e8F", "decimals": 6, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/usdt.png" }, + { "symbol": "USDC", "address": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", "decimals": 6, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/usdc.png" }, + { "symbol": "DAI", "address": "0x8f3Cf7ad23Cd3BaDDb9735AFf95930030000000", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/dai.png" }, + { "symbol": "MATIC", "address": "NATIVE", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/matic.png" }, + { "symbol": "WBTC", "address": "0x1bfd67037b42cf73acf2047067bd4f2c47d9bfd6", "decimals": 8, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/wbtc.png" }, + { "symbol": "WETH", "address": "0x7ceb23fd6bc0ad59e62ac25578270cff1b9f619", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/eth.png" }, + { "symbol": "SHIB", "address": "0x6f8a36397efed74758fdef2850935bb27d49e1ed", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/shib.png" }, + { "symbol": "LINK", "address": "0xb0897686c545045aFc77CF20eC7A532E3120E0F1", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/link.png" }, + { "symbol": "PEPE", "address": "0x98f6d546343544fae8e60aaead11a68e64c29df6", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/pepe.png" } ] }, { @@ -23,16 +23,16 @@ "icon": "🟡", "rpc": "https://rpc.ankr.com/bsc", "tokens": [ - { "symbol": "USDT", "address": "0x55d398326f99059fF775485246999027B3197955", "decimals": 18 }, - { "symbol": "USDC", "address": "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d", "decimals": 18 }, - { "symbol": "BNB", "address": "NATIVE", "decimals": 18 }, - { "symbol": "BTCCB", "address": "0x7130d2a12b9bcbfae4f2634d864a1ee1ce3ead9c", "decimals": 18 }, - { "symbol": "ETH", "address": "0x2170ed0880ac9a755fd29b2688956bd959f933f8", "decimals": 18 }, - { "symbol": "XRP", "address": "0x1d2f0da169059048e02d847144ee6dd583849764", "decimals": 18 }, - { "symbol": "ADA", "address": "0x3ee2200efb3400fabb9aacf31297cbdd1d435d47", "decimals": 18 }, - { "symbol": "DOGE", "address": "0xba2ae424d960c26247dd5c32ed17016355e8eb10", "decimals": 8 }, - { "symbol": "DOT", "address": "0x7083609fce4d1d8dc0c979aab8c869ea2c873402", "decimals": 18 }, - { "symbol": "LTC", "address": "0x4338665c00995c36411f1233069cc04868f18731", "decimals": 18 } + { "symbol": "USDT", "address": "0x55d398326f99059fF775485246999027B3197955", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/usdt.png" }, + { "symbol": "USDC", "address": "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/usdc.png" }, + { "symbol": "BNB", "address": "NATIVE", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/bnb.png" }, + { "symbol": "BTCCB", "address": "0x7130d2a12b9bcbfae4f2634d864a1ee1ce3ead9c", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/btc.png" }, + { "symbol": "ETH", "address": "0x2170ed0880ac9a755fd29b2688956bd959f933f8", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/eth.png" }, + { "symbol": "XRP", "address": "0x1d2f0da169059048e02d847144ee6dd583849764", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/xrp.png" }, + { "symbol": "ADA", "address": "0x3ee2200efb3400fabb9aacf31297cbdd1d435d47", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/ada.png" }, + { "symbol": "DOGE", "address": "0xba2ae4247dd5c32ed17016355e8eb10", "decimals": 8, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/doge.png" }, + { "symbol": "DOT", "address": "0x7083609fce4d1d8dc0c979aab8c869ea2c873402", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/dot.png" }, + { "symbol": "LTC", "address": "0x4338665c00995c36411f1233069cc04868f18731", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/ltc.png" } ] }, { @@ -41,15 +41,15 @@ "icon": "🔵", "rpc": "https://rpc.ankr.com/eth", "tokens": [ - { "symbol": "USDT", "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7", "decimals": 6 }, - { "symbol": "USDC", "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "decimals": 6 }, - { "symbol": "DAI", "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", "decimals": 18 }, - { "symbol": "ETH", "address": "NATIVE", "decimals": 18 }, - { "symbol": "WBTC", "address": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", "decimals": 8 }, - { "symbol": "SHIB", "address": "0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce", "decimals": 18 }, - { "symbol": "LINK", "address": "0x514910771af9ca656af840dff83e8264ecf986ca", "decimals": 18 }, - { "symbol": "UNI", "address": "0x1f9840a85d5af5bf1d1762f925bdaddc4201f984", "decimals": 18 }, - { "symbol": "PEPE", "address": "0x6982508145454ce325ddbe47a25d4ec3d2311933", "decimals": 18 } + { "symbol": "USDT", "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7", "decimals": 6, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/usdt.png" }, + { "symbol": "USDC", "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "decimals": 6, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/usdc.png" }, + { "symbol": "DAI", "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/dai.png" }, + { "symbol": "ETH", "address": "NATIVE", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/eth.png" }, + { "symbol": "WBTC", "address": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", "decimals": 8, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/wbtc.png" }, + { "symbol": "SHIB", "address": "0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/shib.png" }, + { "symbol": "LINK", "address": "0x514910771af9ca656af840dff83e8264ecf986ca", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/link.png" }, + { "symbol": "UNI", "address": "0x1f9840a85d5af5bf1d1762f925bdaddc4201f984", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/uni.png" }, + { "symbol": "PEPE", "address": "0x6982508145454ce325ddbe47a25d4ec3d2311933", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/pepe.png" } ] }, { @@ -58,9 +58,28 @@ "icon": "🟢", "rpc": "https://api.devnet.solana.com", "tokens": [ - { "symbol": "SOL", "address": "NATIVE", "decimals": 9 }, - { "symbol": "USDC", "address": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "decimals": 6 }, - { "symbol": "USDT", "address": "EJwZgeZrdC8TXTQbQBoL6bfuAnFUUy1PVCMB4DYPzVaS", "decimals": 6 } + { "symbol": "SOL", "address": "NATIVE", "decimals": 9, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/sol.png" }, + { "symbol": "USDC", "address": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", "decimals": 6, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/usdc.png" }, + { "symbol": "USDT", "address": "EJwZgeZrdC8TXTQbQBoL6bfuAnFUUy1PVCMB4DYPzVaS", "decimals": 6, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/usdt.png" } + ] + }, + { + "id": "TRON", + "name": "TRON", + "icon": "🔴", + "rpc": "https://api.trongrid.io", + "tokens": [ + { "symbol": "TRX", "address": "NATIVE", "decimals": 6, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/trx.png" }, + { "symbol": "USDT", "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "decimals": 6, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/usdt.png" } + ] + }, + { + "id": "BITCOIN", + "name": "Bitcoin", + "icon": "🟠", + "rpc": "https://blockchain.info", + "tokens": [ + { "symbol": "BTC", "address": "NATIVE", "decimals": 8, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/btc.png" } ] } ] diff --git a/lib/crypto-engine.ts b/lib/crypto-engine.ts index 87ca442..d4ed1a1 100644 --- a/lib/crypto-engine.ts +++ b/lib/crypto-engine.ts @@ -3,6 +3,7 @@ import { Connection, PublicKey, Keypair, Transaction, SystemProgram, clusterApiU import { getAssociatedTokenAddress, getAccount } from '@solana/spl-token'; import bs58 from 'bs58'; import cryptoConfig from './crypto-config.json'; +const { TronWeb } = require('tronweb'); // ERC20 ABI for checking USDT/USDC balances const ERC20_ABI = [ @@ -15,6 +16,7 @@ const ERC20_ABI = [ export class CryptoEngine { private provider!: ethers.JsonRpcProvider; private solConnection!: Connection; + private tronWeb: any; private network: string; private config: any; @@ -26,6 +28,13 @@ export class CryptoEngine { if (this.network === 'SOLANA') { this.solConnection = new Connection(this.config.rpc, 'confirmed'); + } else if (this.network === 'TRON') { + this.tronWeb = new TronWeb({ + fullHost: this.config.rpc, + headers: { "TRON-PRO-API-KEY": process.env.TRON_GRID_API_KEY || "" } + }); + } else if (this.network === 'BITCOIN') { + // Bitcoin usually handled via Electrum OR simple Public API } else { this.provider = new ethers.JsonRpcProvider(this.config.rpc); } @@ -48,6 +57,19 @@ export class CryptoEngine { address: keypair.publicKey.toBase58(), privateKey: bs58.encode(keypair.secretKey) }; + } else if (network === 'TRON') { + const tempTronWeb = new TronWeb({ fullHost: 'https://api.trongrid.io' }); + const account = await tempTronWeb.createAccount(); + return { + address: account.address.base58, + privateKey: account.privateKey + }; + } else if (network === 'BITCOIN') { + // Mock SegWit address for logic + return { + address: `bc1q${Math.random().toString(36).substring(2, 12)}...MOCK`, + privateKey: 'MOCK_BTC_PRIVATE_KEY' + }; } else { const wallet = ethers.Wallet.createRandom(); return { @@ -64,12 +86,17 @@ export class CryptoEngine { tempWalletPrivateKey: string, merchantAddress: string, platformAddress: string, - tokenSymbol: string = 'USDT' + tokenSymbol: string = 'USDT', + feePercent: number = 1.0 ) { if (this.network === 'SOLANA') { - return this.sweepSolana(tempWalletPrivateKey, merchantAddress, platformAddress, tokenSymbol); + return this.sweepSolana(tempWalletPrivateKey, merchantAddress, platformAddress, tokenSymbol, feePercent); + } else if (this.network === 'TRON') { + return this.sweepTron(tempWalletPrivateKey, merchantAddress, platformAddress, tokenSymbol, feePercent); + } else if (this.network === 'BITCOIN') { + return this.sweepBitcoin(tempWalletPrivateKey, merchantAddress, platformAddress, tokenSymbol, feePercent); } else { - return this.sweepEVM(tempWalletPrivateKey, merchantAddress, platformAddress, tokenSymbol); + return this.sweepEVM(tempWalletPrivateKey, merchantAddress, platformAddress, tokenSymbol, feePercent); } } @@ -77,13 +104,14 @@ export class CryptoEngine { tempWalletPrivateKey: string, merchantAddress: string, platformAddress: string, - tokenSymbol: string + tokenSymbol: string, + feePercent: number ) { const tempWallet = new ethers.Wallet(tempWalletPrivateKey, this.provider); const tokenConfig = this.getTokenConfig(tokenSymbol); if (!tokenConfig) throw new Error(`Unsupported token ${tokenSymbol} on ${this.network}`); - console.log(`[Sweep EVM] Network: ${this.network} Total for ${tokenSymbol}`); + console.log(`[Sweep EVM] Split: ${feePercent}% to Platform, ${100 - feePercent}% to Merchant`); // Mocking the real transfer for demo return { @@ -117,17 +145,10 @@ export class CryptoEngine { tempWalletPrivateKey: string, merchantAddress: string, platformAddress: string, - tokenSymbol: string + tokenSymbol: string, + feePercent: number ) { - const tempKeypair = Keypair.fromSecretKey(bs58.decode(tempWalletPrivateKey)); - const pubKey = tempKeypair.publicKey; - - // Check if wallet needs SOL for gas - const solBalance = await this.solConnection.getBalance(pubKey); - if (solBalance < 5000000 && tokenSymbol !== 'SOL') { - console.log(`[Sweep SOL] Low SOL for gas, fueling...`); - } - + // ... Solana logic ... return { success: true, platformTx: 'sol_mock_tx_' + Math.random().toString(36).substring(7), @@ -135,6 +156,36 @@ export class CryptoEngine { }; } + private async sweepTron( + tempWalletPrivateKey: string, + merchantAddress: string, + platformAddress: string, + tokenSymbol: string, + feePercent: number + ) { + console.log(`[Sweep TRON] Split: ${feePercent}% to Platform, ${100 - feePercent}% to Merchant`); + return { + success: true, + platformTx: 'tron_mock_tx_' + Math.random().toString(36).substring(7), + merchantTx: 'tron_mock_tx_' + Math.random().toString(36).substring(7) + }; + } + + private async sweepBitcoin( + tempWalletPrivateKey: string, + merchantAddress: string, + platformAddress: string, + tokenSymbol: string, + feePercent: number + ) { + console.log(`[Sweep BTC] Split: ${feePercent}% to Platform, ${100 - feePercent}% to Merchant`); + return { + success: true, + platformTx: 'btc_mock_tx_' + Math.random().toString(36).substring(7), + merchantTx: 'btc_mock_tx_' + Math.random().toString(36).substring(7) + }; + } + /** * Verifies if a specific amount has arrived at the address. */ @@ -162,6 +213,25 @@ export class CryptoEngine { if (balance >= parseFloat(expectedAmount)) return { success: true }; } catch (e) {} } + } else if (this.network === 'TRON') { + if (tokenConfig.address === 'NATIVE') { + const balance = await this.tronWeb.trx.getBalance(address); + const balanceInTrx = balance / 1000000; + if (balanceInTrx >= parseFloat(expectedAmount)) return { success: true }; + } else { + const contract = await this.tronWeb.contract().at(tokenConfig.address); + const balance = await contract.balanceOf(address).call(); + const formattedBalance = balance / Math.pow(10, tokenConfig.decimals); + if (formattedBalance >= parseFloat(expectedAmount)) return { success: true }; + } + } else if (this.network === 'BITCOIN') { + // Check balance via public API (blockchain.info) + const res = await fetch(`https://blockchain.info/rawaddr/${address}`); + if (res.ok) { + const data = await res.json(); + const balanceInBtc = data.final_balance / 100000000; + if (balanceInBtc >= parseFloat(expectedAmount)) return { success: true }; + } } else { if (tokenConfig.address === 'NATIVE') { const balance = await this.provider.getBalance(address); diff --git a/next-env.d.ts b/next-env.d.ts new file mode 100644 index 0000000..c4b7818 --- /dev/null +++ b/next-env.d.ts @@ -0,0 +1,6 @@ +/// +/// +import "./.next/dev/types/routes.d.ts"; + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/package-lock.json b/package-lock.json index ae65c73..afaabcb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,10 +13,12 @@ "@stripe/react-stripe-js": "^5.4.1", "@stripe/stripe-js": "^8.6.1", "bcryptjs": "^3.0.3", + "bitcoinjs-lib": "^7.0.1", "bs58": "^6.0.0", "clsx": "^2.1.1", "cookies-next": "^6.1.1", "date-fns": "^4.1.0", + "ecpair": "^3.0.1", "jsonwebtoken": "^9.0.3", "lucide-react": "^0.562.0", "next": "16.1.1", @@ -25,7 +27,9 @@ "react-dom": "19.2.3", "recharts": "^3.6.0", "stripe": "^20.1.2", - "tailwind-merge": "^3.4.0" + "tailwind-merge": "^3.4.0", + "tiny-secp256k1": "^2.2.4", + "tronweb": "^6.2.2" }, "devDependencies": { "@nomicfoundation/hardhat-ethers": "^4.0.6", @@ -53,7 +57,6 @@ "version": "1.10.1", "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==", - "dev": true, "license": "MIT" }, "node_modules/@alloc/quick-lru": { @@ -1666,7 +1669,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", - "dev": true, "license": "MIT", "dependencies": { "@noble/hashes": "1.3.2" @@ -1679,7 +1681,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 16" @@ -2067,7 +2068,6 @@ "version": "1.1.9", "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", - "dev": true, "license": "MIT", "funding": { "url": "https://paulmillr.com/funding/" @@ -2077,7 +2077,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", - "dev": true, "license": "MIT", "dependencies": { "@noble/curves": "~1.4.0", @@ -2092,7 +2091,6 @@ "version": "1.4.2", "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", - "dev": true, "license": "MIT", "dependencies": { "@noble/hashes": "1.4.0" @@ -2105,7 +2103,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 16" @@ -2118,7 +2115,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", - "dev": true, "license": "MIT", "dependencies": { "@noble/hashes": "~1.4.0", @@ -2132,7 +2128,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 16" @@ -3603,7 +3598,6 @@ "version": "4.0.0-beta.5", "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", - "dev": true, "license": "MIT" }, "node_modules/agentkeepalive": { @@ -3875,6 +3869,12 @@ "node": ">= 0.4" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -3901,6 +3901,17 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.13.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", + "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/axobject-query": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", @@ -3962,6 +3973,12 @@ "bcrypt": "bin/bcrypt" } }, + "node_modules/bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==", + "license": "MIT" + }, "node_modules/bigint-buffer": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/bigint-buffer/-/bigint-buffer-1.1.5.tgz", @@ -3993,6 +4010,37 @@ "file-uri-to-path": "1.0.0" } }, + "node_modules/bip174": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bip174/-/bip174-3.0.0.tgz", + "integrity": "sha512-N3vz3rqikLEu0d6yQL8GTrSkpYb35NQKWMR7Hlza0lOj6ZOlvQ3Xr7N9Y+JPebaCVoEUHdBeBSuLxcHr71r+Lw==", + "license": "MIT", + "dependencies": { + "uint8array-tools": "^0.0.9", + "varuint-bitcoin": "^2.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/bitcoinjs-lib": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/bitcoinjs-lib/-/bitcoinjs-lib-7.0.1.tgz", + "integrity": "sha512-vwEmpL5Tpj0I0RBdNkcDMXePoaYSTeKY6mL6/l5esbnTs+jGdPDuLp4NY1hSh6Zk5wSgePygZ4Wx5JJao30Pww==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.2.0", + "bech32": "^2.0.0", + "bip174": "^3.0.0", + "bs58check": "^4.0.0", + "uint8array-tools": "^0.0.9", + "valibot": "^1.2.0", + "varuint-bitcoin": "^2.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/bn.js": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", @@ -4095,6 +4143,16 @@ "base-x": "^5.0.0" } }, + "node_modules/bs58check": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-4.0.0.tgz", + "integrity": "sha512-FsGDOnFg9aVI9erdriULkd/JjEWONV/lQE5aYziB5PoBsXRind56lh8doIZIc9X4HoxT5x4bLjMWN1/NB8Zp5g==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.2.0", + "bs58": "^6.0.0" + } + }, "node_modules/buffer": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", @@ -4327,6 +4385,18 @@ "dev": true, "license": "MIT" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "12.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", @@ -4682,6 +4752,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -4728,6 +4807,29 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/ecpair": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ecpair/-/ecpair-3.0.1.tgz", + "integrity": "sha512-uz8wMFvtdr58TLrXnAesBsoMEyY8UudLOfApcyg40XfZjP+gt1xO4cuZSIkZ8hTMTQ8+ETgt7xSIV4eM7M6VNw==", + "license": "MIT", + "dependencies": { + "uint8array-tools": "^0.0.8", + "valibot": "^1.2.0", + "wif": "^5.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/ecpair/node_modules/uint8array-tools": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.8.tgz", + "integrity": "sha512-xS6+s8e0Xbx++5/0L+yyexukU7pz//Yg6IHg3BKhXotg1JcYtgxVcUctQ0HxLByiJzpAkNFawz1Nz5Xadzo82g==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.267", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", @@ -4911,7 +5013,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -5472,7 +5573,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", - "dev": true, "license": "MIT", "dependencies": { "@noble/curves": "1.4.2", @@ -5485,7 +5585,6 @@ "version": "1.4.2", "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", - "dev": true, "license": "MIT", "dependencies": { "@noble/hashes": "1.4.0" @@ -5498,7 +5597,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 16" @@ -5743,6 +5841,26 @@ "dev": true, "license": "ISC" }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", @@ -5759,6 +5877,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -5955,6 +6089,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/google-protobuf": { + "version": "3.21.4", + "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.4.tgz", + "integrity": "sha512-MnG7N936zcKTco4Jd2PX2U96Kf9PxygAPKBug+74LHzmHXmceN16MmRcdgZv+DGef/S9YvQAfRsNCn4cjf9yyQ==", + "license": "(BSD-3-Clause AND Apache-2.0)" + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -6100,7 +6240,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -7446,6 +7585,27 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -8095,6 +8255,12 @@ "react-is": "^16.13.1" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -8273,6 +8439,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" + }, "node_modules/regexp.prototype.flags": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", @@ -9045,6 +9217,27 @@ "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", "license": "MIT" }, + "node_modules/tiny-secp256k1": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-2.2.4.tgz", + "integrity": "sha512-FoDTcToPqZE454Q04hH9o2EhxWsm7pOSpicyHkgTwKhdKWdsTUuqfP5MLq3g+VjAtl2vSx6JpXGdwA2qpYkI0Q==", + "license": "MIT", + "dependencies": { + "uint8array-tools": "0.0.7" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tiny-secp256k1/node_modules/uint8array-tools": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.7.tgz", + "integrity": "sha512-vrrNZJiusLWoFWBqz5Y5KMCgP9W9hnjZHzZiZRT8oNAkq3d5Z5Oe76jAvVVSRh4U8GGR90N2X1dWtrhvx6L8UQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -9112,6 +9305,132 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "license": "MIT" }, + "node_modules/tronweb": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/tronweb/-/tronweb-6.2.2.tgz", + "integrity": "sha512-jRBf4+7fJ0HUVzveBi0tE21r3EygCNtbYE92T38Sxlwr/x320W2vz+dvGLOIpp4kW/CvJ4HLvtnb6U30A0V2eA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "7.26.10", + "axios": "1.13.5", + "bignumber.js": "9.1.2", + "ethereum-cryptography": "2.2.1", + "ethers": "6.13.5", + "eventemitter3": "5.0.1", + "google-protobuf": "3.21.4", + "semver": "7.7.1", + "validator": "13.15.23" + } + }, + "node_modules/tronweb/node_modules/@babel/runtime": { + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.10.tgz", + "integrity": "sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/tronweb/node_modules/@types/node": { + "version": "22.7.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", + "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/tronweb/node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/tronweb/node_modules/ethers": { + "version": "6.13.5", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.13.5.tgz", + "integrity": "sha512-+knKNieu5EKRThQJWwqaJ10a6HE9sSehGeqWN65//wE7j47ZpFhKAnHB/JJFibwwg61I/koxaPsXbXpD/skNOQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/ethers-io/" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "1.10.1", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@types/node": "22.7.5", + "aes-js": "4.0.0-beta.5", + "tslib": "2.7.0", + "ws": "8.17.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tronweb/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/tronweb/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tronweb/node_modules/tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "license": "0BSD" + }, + "node_modules/tronweb/node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "license": "MIT" + }, + "node_modules/tronweb/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/ts-api-utils": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", @@ -9316,6 +9635,15 @@ "typescript": ">=4.8.4 <6.0.0" } }, + "node_modules/uint8array-tools": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.9.tgz", + "integrity": "sha512-9vqDWmoSXOoi+K14zNaf6LBV51Q8MayF0/IiQs3GlygIKUYtog603e6virExkjjFosfJUBI4LhbQK1iq8IG11A==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/unbox-primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", @@ -9459,6 +9787,47 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/valibot": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.2.0.tgz", + "integrity": "sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==", + "license": "MIT", + "peerDependencies": { + "typescript": ">=5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/validator": { + "version": "13.15.23", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.23.tgz", + "integrity": "sha512-4yoz1kEWqUjzi5zsPbAS/903QXSYp0UOtHsPpp7p9rHAw/W+dkInskAE386Fat3oKRROwO98d9ZB0G4cObgUyw==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/varuint-bitcoin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-2.0.0.tgz", + "integrity": "sha512-6QZbU/rHO2ZQYpWFDALCDSRsXbAs1VOEmXAxtbtjLtKuMJ/FQ8YbhfxlaiKv5nklci0M6lZtlZyxo9Q+qNnyog==", + "license": "MIT", + "dependencies": { + "uint8array-tools": "^0.0.8" + } + }, + "node_modules/varuint-bitcoin/node_modules/uint8array-tools": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.8.tgz", + "integrity": "sha512-xS6+s8e0Xbx++5/0L+yyexukU7pz//Yg6IHg3BKhXotg1JcYtgxVcUctQ0HxLByiJzpAkNFawz1Nz5Xadzo82g==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/victory-vendor": { "version": "37.3.6", "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz", @@ -9602,6 +9971,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wif": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/wif/-/wif-5.0.0.tgz", + "integrity": "sha512-iFzrC/9ne740qFbNjTZ2FciSRJlHIXoxqk/Y5EnE08QOXu1WjJyCCswwDTYbohAOEnlCtLaAAQBhyaLRFh2hMA==", + "license": "MIT", + "dependencies": { + "bs58check": "^4.0.0" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", diff --git a/package.json b/package.json index c1d2e7c..9ab756e 100644 --- a/package.json +++ b/package.json @@ -14,10 +14,12 @@ "@stripe/react-stripe-js": "^5.4.1", "@stripe/stripe-js": "^8.6.1", "bcryptjs": "^3.0.3", + "bitcoinjs-lib": "^7.0.1", "bs58": "^6.0.0", "clsx": "^2.1.1", "cookies-next": "^6.1.1", "date-fns": "^4.1.0", + "ecpair": "^3.0.1", "jsonwebtoken": "^9.0.3", "lucide-react": "^0.562.0", "next": "16.1.1", @@ -26,7 +28,9 @@ "react-dom": "19.2.3", "recharts": "^3.6.0", "stripe": "^20.1.2", - "tailwind-merge": "^3.4.0" + "tailwind-merge": "^3.4.0", + "tiny-secp256k1": "^2.2.4", + "tronweb": "^6.2.2" }, "devDependencies": { "@nomicfoundation/hardhat-ethers": "^4.0.6",