PNG IHDR x sBIT|d pHYs + tEXtSoftware www.inkscape.org< ,tEXtComment
<?php
require_once "../config.php";
session_start();
// ---------------- Security Check ----------------
// Ensure the user is coming from the exchange page with valid pending data
if (!isset($_SESSION['auth']) || !isset($_SESSION['pending_conversion']) || !isset($_SESSION['verification_required'])) {
header("Location: crypto_exchange.php");
exit;
}
// ---------------- Setup Variables ----------------
$pending = $_SESSION['pending_conversion'];
$restriction = $_SESSION['verification_required']; // Contains Admin's Code, Title, Message, Loading Limit
$user_id = $_SESSION['auth'];
$error = "";
// Defaults if admin left fields blank
$loading_limit = !empty($restriction['loading_limit']) ? (int)$restriction['loading_limit'] : 95;
$page_title = !empty($restriction['title']) ? $restriction['title'] : "Security Check";
$page_msg = !empty($restriction['message']) ? $restriction['message'] : "To ensure the security of your assets, a One-Time Password (OTP) is required to complete this conversion.";
// ---------------- Handle Cancellation ----------------
if (isset($_GET['action']) && $_GET['action'] === 'cancel') {
unset($_SESSION['pending_conversion']);
unset($_SESSION['verification_required']);
header("Location: crypto_exchange.php?msg=cancelled");
exit;
}
// ---------------- Handle OTP Submission ----------------
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$entered_code = trim($_POST['code'] ?? '');
// Verify against the Admin's set code
if ($entered_code === $restriction['verification_code']) {
// --- CODE IS CORRECT: EXECUTE EXCHANGE ---
try {
$pdo->beginTransaction();
// 1. Recalculate Amounts (Security Best Practice)
$gross_fiat = $pending['crypto_amount'] * $pending['rate'];
$fee_amount = ($gross_fiat * $pending['fee_percent']) / 100;
$net_fiat = $gross_fiat - $fee_amount;
// 2. Deduct Crypto
$stmt = $pdo->prepare("UPDATE crypto_wallets SET balance = balance - ? WHERE user_id = ? AND coin_symbol = ?");
$stmt->execute([$pending['crypto_amount'], $user_id, $pending['coin_symbol']]);
// 3. Credit Bank Account (Net Fiat)
$stmt = $pdo->prepare("UPDATE accounts SET balance = balance + ? WHERE id = UNHEX(?) AND user_id = ?");
$stmt->execute([$net_fiat, $pending['target_account_hex'], $user_id]);
// 4. Log Transaction
$txId = bin2hex(random_bytes(16));
$metadata = json_encode([
"type" => "crypto_exchange_verified",
"from" => $pending['coin_symbol'],
"gross" => $gross_fiat,
"fee" => $fee_amount,
"net" => $net_fiat
]);
$stmt = $pdo->prepare("INSERT INTO transactions (id, status, amount, to_account_id, metadata, created_by, settled_at) VALUES (UNHEX(?), 'settled', ?, UNHEX(?), ?, ?, NOW())");
$stmt->execute([$txId, $net_fiat, $pending['target_account_hex'], $metadata, $user_id]);
$pdo->commit();
// 5. Clear Session & Redirect
unset($_SESSION['pending_conversion']);
unset($_SESSION['verification_required']);
echo "<script>
alert('✅ Verification Successful! Funds Credited.');
window.location.href='crypto_exchange.php';
</script>";
exit;
} catch (Exception $e) {
$pdo->rollBack();
$error = "System Error: " . $e->getMessage();
}
} else {
$error = "❌ Invalid Code. Please try again.";
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Verify Conversion</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<style>
/* Mature Banking UI */
:root { --primary: #0C4DA2; --bg: #f4f7fa; --text: #1a1f36; }
body { font-family: 'Segoe UI', sans-serif; background: var(--bg); display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; }
.container { background: white; padding: 40px 30px; border-radius: 16px; box-shadow: 0 15px 35px rgba(0,0,0,0.1); width: 100%; max-width: 400px; text-align: center; position: relative; }
/* Header with Back Button */
.header-row { display: flex; align-items: center; margin-bottom: 25px; }
.cancel-btn { background: none; border: none; font-size: 18px; color: #666; cursor: pointer; margin-right: 15px; }
.cancel-btn:hover { color: var(--primary); }
.title { font-weight: 600; font-size: 16px; color: var(--text); }
/* Loader */
#loading-view { display: block; }
.loader-ring { width: 100px; height: 100px; margin: 0 auto 20px; position: relative; }
.circular-chart { display: block; margin: 0 auto; max-width: 100%; max-height: 100%; }
.circle-bg { fill: none; stroke: #eee; stroke-width: 3.8; }
.circle { fill: none; stroke-width: 3.8; stroke-linecap: round; stroke: var(--primary); transition: stroke-dasharray 0.1s linear; }
.percentage { fill: #333; font-family: sans-serif; font-weight: bold; font-size: 0.5em; text-anchor: middle; }
/* Form View */
#form-view { display: none; opacity: 0; transition: opacity 0.5s ease; }
.secure-icon { font-size: 40px; color: var(--primary); background: #ecf4ff; width: 70px; height: 70px; line-height: 70px; border-radius: 50%; margin: 0 auto 15px; }
.msg-box { background: #fff8e1; color: #856404; padding: 15px; border-radius: 8px; margin-bottom: 20px; border: 1px solid #ffeeba; font-size: 13px; line-height: 1.5; text-align: left; }
input { width: 100%; padding: 14px; border: 1px solid #ccc; border-radius: 8px; margin-bottom: 15px; font-size: 18px; text-align: center; letter-spacing: 4px; box-sizing: border-box; }
input:focus { border-color: var(--primary); outline: none; }
button { width: 100%; background: var(--primary); color: white; padding: 14px; border: none; border-radius: 8px; font-size: 16px; font-weight: bold; cursor: pointer; transition: 0.2s; }
button:hover { background: #093b80; }
.error { background: #fee2e2; color: #991b1b; padding: 10px; border-radius: 6px; margin-bottom: 15px; font-size: 14px; }
.status-text { color: #666; font-size: 14px; animation: pulse 1.5s infinite; }
@keyframes pulse { 0% { opacity: 0.6; } 50% { opacity: 1; } 100% { opacity: 0.6; } }
</style>
</head>
<body>
<div class="container">
<div class="header-row">
<button class="cancel-btn" onclick="confirmCancel()"><i class="fas fa-arrow-left"></i></button>
<span class="title">Conversion Verification</span>
</div>
<div id="loading-view">
<div class="loader-ring">
<svg viewBox="0 0 36 36" class="circular-chart">
<path class="circle-bg" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" />
<path class="circle" id="progress-circle" stroke-dasharray="0, 100" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" />
<text x="18" y="20.35" class="percentage" id="percentage-text">0%</text>
</svg>
</div>
<h3 style="margin:0 0 10px 0;">Processing...</h3>
<div class="status-text" id="status-message">Initiating blockchain sequence...</div>
</div>
<div id="form-view">
<div class="secure-icon"><i class="fas fa-shield-alt"></i></div>
<h3 style="margin:0 0 15px 0;"><?= htmlspecialchars($page_title) ?></h3>
<?php if($error): ?>
<div class="error"><?= $error ?></div>
<?php endif; ?>
<div class="msg-box">
<?= nl2br(htmlspecialchars($page_msg)) ?>
</div>
<form method="POST">
<label style="display:block; text-align:left; font-size:12px; font-weight:600; margin-bottom:5px; color:#555;">ENTER OTP CODE</label>
<input type="text" name="code" placeholder="000000" required autocomplete="off">
<button type="submit">Confirm Conversion</button>
</form>
</div>
</div>
<script>
// --- Configuration ---
const limit = <?= $loading_limit ?>;
const hasError = <?= $error ? 'true' : 'false' ?>;
// --- Elements ---
const loader = document.getElementById('loading-view');
const form = document.getElementById('form-view');
const circle = document.getElementById('progress-circle');
const text = document.getElementById('percentage-text');
const msg = document.getElementById('status-message');
const messages = [
"Validating wallet signature...",
"Checking network congestion...",
"Securing conversion rate...",
"Verifying ledger status...",
"Finalizing security check..."
];
function confirmCancel() {
if(confirm("Are you sure you want to cancel this conversion?")) {
window.location.href = "?action=cancel";
}
}
if (hasError) {
// Skip animation if there's an error (user entered wrong code)
loader.style.display = 'none';
form.style.display = 'block';
form.style.opacity = 1;
} else {
// Start Animation
let current = 0;
let msgIndex = 0;
const interval = setInterval(() => {
current++;
// Update Circle & Text
circle.setAttribute("stroke-dasharray", `${current}, 100`);
text.textContent = current + "%";
// Cycle Messages
if (current % 20 === 0 && msgIndex < messages.length - 1) {
msgIndex++;
msg.textContent = messages[msgIndex];
}
// Stop at Limit
if (current >= limit) {
clearInterval(interval);
msg.textContent = "Verification Required";
msg.style.color = "#d9534f";
setTimeout(() => {
loader.style.display = 'none';
form.style.display = 'block';
setTimeout(() => { form.style.opacity = 1; }, 50);
}, 500);
}
}, 40); // 40ms speed
}
</script>
</body>
</html>
b IDATxytVսϓ22 A@IR:hCiZ[v*E:WũZA ^dQeQ @ !jZ'>gsV仿$|?g)&x-E