38350-vm/api/place_option_order.php
Flatlogic Bot 1fcaec3d09 2026-213
2026-02-13 15:48:44 +00:00

127 lines
4.1 KiB
PHP

<?php
header('Content-Type: application/json');
require_once '../db/config.php';
session_start();
if (!isset($_SESSION['user_id'])) {
echo json_encode(['success' => 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
$frontend_price = isset($data['price']) ? (float)$data['price'] : null;
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);
// Fallback to frontend price if server fetch fails
if ($open_price === null) {
if ($frontend_price !== null && $frontend_price > 0) {
$open_price = $frontend_price;
} else {
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;
$stmt = $pdo->prepare(
"INSERT INTO option_orders (user_id, symbol, amount, direction, duration, profit_rate, opening_price, status, created_at, 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.']);
}
?>