false, 'error' => 'User not logged in']); exit; } $user_id = $_SESSION['user_id']; $data = json_decode(file_get_contents('php://input'), true); // --- Input Validation --- $pair = $data['pair'] ?? null; $amount = (float)($data['amount'] ?? 0); $direction = $data['direction'] ?? null; $duration = (int)($data['duration'] ?? 0); $rate = (float)($data['rate'] ?? 0); // Profit rate in percentage if (empty($pair) || empty($direction) || $amount <= 0 || $duration <= 0 || $rate <= 0) { echo json_encode(['success' => false, 'error' => 'Invalid order parameters.']); exit; } // --- Server-Side Rules Validation --- $valid_options = [ 60 => ['rate' => 8, 'min' => 100], 90 => ['rate' => 12, 'min' => 5000], 120 => ['rate' => 15, 'min' => 30000], 180 => ['rate' => 20, 'min' => 100000], 300 => ['rate' => 32, 'min' => 300000], ]; if (!isset($valid_options[$duration]) || $valid_options[$duration]['rate'] != $rate) { echo json_encode(['success' => false, 'error' => 'Invalid duration or profit rate selected.']); exit; } $min_amount = $valid_options[$duration]['min']; if ($amount < $min_amount) { echo json_encode(['success' => false, 'error' => "Minimum amount for {$duration}s is {$min_amount} USDT."]); exit; } // --- Securely Fetch Current Price from Binance API --- function get_current_price($symbol) { $url = "https://api.binance.com/api/v3/ticker/price?symbol=" . urlencode($symbol); $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 5); $response = curl_exec($ch); curl_close($ch); if ($response) { $data = json_decode($response, true); if (isset($data['price'])) { return (float)$data['price']; } } return null; } $open_price = get_current_price($pair); if ($open_price === null) { echo json_encode(['success' => false, 'error' => 'Could not fetch current price for the pair. Please try again.']); exit; } // --- Database Transaction --- $pdo = db(); $pdo->beginTransaction(); try { // 1. Lock user row and check balance $stmt = $pdo->prepare("SELECT balance FROM users WHERE id = ? FOR UPDATE"); $stmt->execute([$user_id]); $user = $stmt->fetch(); if (!$user || $user['balance'] < $amount) { $pdo->rollBack(); echo json_encode(['success' => false, 'error' => 'Insufficient balance.']); exit; } // 2. Deduct balance $new_balance = $user['balance'] - $amount; $stmt = $pdo->prepare("UPDATE users SET balance = ? WHERE id = ?"); $stmt->execute([$new_balance, $user_id]); // 3. Insert the new option order $start_time = date('Y-m-d H:i:s'); $settle_at = date('Y-m-d H:i:s', time() + $duration); $profit_rate_decimal = $rate / 100; // Store as decimal for calculation $stmt = $pdo->prepare( "INSERT INTO option_orders (user_id, pair, amount, direction, duration, profit_rate, open_price, status, start_time, settle_at) " . "VALUES (?, ?, ?, ?, ?, ?, ?, 'pending', ?, ?)" ); $stmt->execute([$user_id, $pair, $amount, $direction, $duration, $profit_rate_decimal, $open_price, $start_time, $settle_at]); $order_id = $pdo->lastInsertId(); // 4. Commit the transaction $pdo->commit(); // 5. Fetch the created order to return to the frontend $stmt = $pdo->prepare("SELECT * FROM option_orders WHERE id = ?"); $stmt->execute([$order_id]); $new_order = $stmt->fetch(PDO::FETCH_ASSOC); echo json_encode(['success' => true, 'order' => $new_order]); } catch (Exception $e) { if ($pdo->inTransaction()) { $pdo->rollBack(); } error_log("Option order failed: " . $e->getMessage()); echo json_encode(['success' => false, 'error' => 'An internal error occurred. Please try again later.']); } ?>