PHP WebShell

Текущая директория: /var/www/bitcardoApp/models/crypto

Просмотр файла: swap.php

<?php
session_start();
// models/crypto/swap.php
require_once "../../config/db_config.php";

if (!isset($_SESSION['user_id'])) {
  header("Location: login.php");
  exit();
}
$user_id = (int)$_SESSION['user_id'];

$from   = strtoupper(trim($_POST['currencyFrom'] ?? ''));
$to     = strtoupper(trim($_POST['currencyTo'] ?? ''));
$amount = (float)($_POST['fromAmount'] ?? 0);

if (!$from || !$to || $amount <= 0 || $from === $to) {
  exit("Invalid swap input.");
}

if (!empty($_SESSION['swap_lock'])) {
  exit("Please wait, a swap is already in progress.");
}
$_SESSION['swap_lock'] = true;

// -- helpers -------------------------------------------------
function fetchRate(mysqli $conn, string $coin, string $col = 'buy_rate'): float {
  $col = in_array($col, ['buy_rate', 'sell_rate'], true) ? $col : 'buy_rate';
  $coin = strtoupper($coin);
  $stmt = $conn->prepare("SELECT $col FROM coin_rates WHERE UPPER(coin) = ?");
  $stmt->bind_param("s", $coin);
  $stmt->execute();
  $row = $stmt->get_result()->fetch_assoc();
  $stmt->close();
  return (float)($row[$col] ?? 0);
}

function fetchMinSwap(mysqli $conn, string $coin): float {
  $coin = strtoupper($coin);
  $stmt = $conn->prepare("SELECT COALESCE(min_swap,0) AS m FROM coin_rates WHERE UPPER(coin) = ?");
  $stmt->bind_param("s", $coin);
  $stmt->execute();
  $row = $stmt->get_result()->fetch_assoc();
  $stmt->close();
  return (float)($row['m'] ?? 0);
}

// -- load wallets -------------------------------------------
$stmt = $conn->prepare("SELECT wallet_id, balance, wallet_add FROM user_wallets WHERE user_id = ? AND UPPER(coin) = ?");
$stmt->bind_param("is", $user_id, $from);
$stmt->execute();
$fromWallet = $stmt->get_result()->fetch_assoc();
$stmt->close();

if (!$fromWallet || (float)$fromWallet['balance'] < $amount) {
  $_SESSION['swap_lock'] = false;
  exit("Insufficient balance.");
}
$from_wallet_id = (int)$fromWallet['wallet_id'];
$from_address   = $fromWallet['wallet_add'];

$stmt = $conn->prepare("SELECT wallet_id, wallet_add FROM user_wallets WHERE user_id = ? AND UPPER(coin) = ?");
$stmt->bind_param("is", $user_id, $to);
$stmt->execute();
$toWallet = $stmt->get_result()->fetch_assoc();
$stmt->close();

if (!$toWallet) {
  $_SESSION['swap_lock'] = false;
  exit("Destination wallet not found.");
}
$to_wallet_id = (int)$toWallet['wallet_id'];
$to_address   = $toWallet['wallet_add'];

// -- enforce min_swap ---------------------------------------
// NGN min is in Naira; all other coins’ min_swap is in USD.
// Compare NGN directly; for others, convert FROM amount to USDT using FROM.buy_rate.
$min_swap_from = fetchMinSwap($conn, $from);
if ($min_swap_from > 0) {
  if ($from === 'NGN') {
    if ($amount < $min_swap_from) {
      $_SESSION['swap_lock'] = false;
      exit("Minimum swap amount for NGN is ₦" . number_format($min_swap_from, 0));
    }
  } else {
    // amount_in_usdt = amount * (USDT per FROM) using buy_rate
    $from_buy = fetchRate($conn, $from, 'buy_rate'); // USDT / FROM
    $amount_usdt = $amount * $from_buy;
    if ($amount_usdt < $min_swap_from) {
      $_SESSION['swap_lock'] = false;
      exit("Minimum swap amount for $from is $" . number_format($min_swap_from, 2));
    }
  }
}

// -- rate logic (OLD NGN<->USDT math, extended to NGN<->(BTC|SOL|ETH)) ----
$rate = 0.0;
$to_amount = 0.0;

// Case A: USDT <-> NGN (OLD logic)
if (($from === 'USDT' && $to === 'NGN') || ($from === 'NGN' && $to === 'USDT')) {
  if ($from === 'USDT') {
    // USDT → NGN: multiply by NGN.sell_rate
    $rate = fetchRate($conn, 'NGN', 'sell_rate');     // NGN / 1 USDT
    $to_amount = $rate > 0 ? $amount * $rate : 0.0;
  } else { // NGN -> USDT
    // NGN → USDT: divide by NGN.buy_rate
    $rate = fetchRate($conn, 'NGN', 'buy_rate');      // NGN / 1 USDT
    $to_amount = $rate > 0 ? $amount / $rate : 0.0;
  }

// Case B: NGN -> (BTC|SOL|ETH) via USDT (OLD math extended)
} elseif ($from === 'NGN' && in_array($to, ['BTC','SOL','ETH','USDT'], true)) {
  if ($to === 'USDT') {
    // Handled above; but if we get here due to logic order, do the same:
    $rate = fetchRate($conn, 'NGN', 'buy_rate');
    $to_amount = $rate > 0 ? $amount / $rate : 0.0;
  } else {
    // NGN → USDT (divide by NGN.buy_rate), then USDT → COIN (divide by COIN.sell_rate)
    $ngn_buy   = fetchRate($conn, 'NGN', 'buy_rate');   // NGN / USDT
    $coin_sell = fetchRate($conn, $to,   'sell_rate');  // USDT / COIN
    $usdt = $ngn_buy > 0 ? ($amount / $ngn_buy) : 0.0;
    $to_amount = ($coin_sell > 0) ? ($usdt / $coin_sell) : 0.0;

    // Composite rate (optional, for record): COIN per NGN
    $rate = ($ngn_buy > 0 && $coin_sell > 0) ? (1.0 / $ngn_buy) / $coin_sell : 0.0;
  }

// Case C: (BTC|SOL|ETH) -> NGN via USDT (OLD math extended)
} elseif (in_array($from, ['BTC','SOL','ETH','USDT'], true) && $to === 'NGN') {
  if ($from === 'USDT') {
    // USDT → NGN: multiply by NGN.sell_rate
    $rate = fetchRate($conn, 'NGN', 'sell_rate');      // NGN / USDT
    $to_amount = $rate > 0 ? $amount * $rate : 0.0;
  } else {
    // COIN → USDT (multiply by COIN.buy_rate), then USDT → NGN (multiply by NGN.sell_rate)
    $coin_buy = fetchRate($conn, $from, 'buy_rate');   // USDT / COIN
    $ngn_sell = fetchRate($conn, 'NGN', 'sell_rate');  // NGN / USDT
    $usdt = $amount * $coin_buy;
    $to_amount = $usdt * $ngn_sell;

    // Composite rate (optional): NGN per COIN
    $rate = $coin_buy * $ngn_sell;
  }

// Case D: everything else (existing logic retained)
} else {
  if ($to === 'USDT') {
    // Coin → USDT: use buy_rate of coin
    $rate = fetchRate($conn, $from, 'buy_rate');  // USDT / FROM
    $to_amount = $amount * $rate;
  } elseif ($from === 'USDT') {
    // USDT → Coin: use sell_rate of coin
    $rate = fetchRate($conn, $to, 'sell_rate');   // USDT / TO
    $to_amount = $rate > 0 ? $amount / $rate : 0.0;
  } else {
    // Coin → Coin: from → USDT (buy_rate), then USDT → to (sell_rate)
    $buy_rate  = fetchRate($conn, $from, 'buy_rate');  // USDT / FROM
    $sell_rate = fetchRate($conn, $to,   'sell_rate'); // USDT / TO
    $usdt_value = $amount * $buy_rate;
    $to_amount  = $sell_rate > 0 ? $usdt_value / $sell_rate : 0.0;
    $rate       = ($buy_rate > 0 && $sell_rate > 0) ? ($buy_rate / $sell_rate) : 0.0;
  }
}

// Final validation
if ($to_amount <= 0) {
  $_SESSION['swap_lock'] = false;
  exit("Failed to fetch swap rate.");
}

$swap_id = uniqid("", true);

$conn->begin_transaction();

try {
  // Deduct FROM
  $stmt = $conn->prepare("UPDATE user_wallets SET balance = balance - ? WHERE wallet_id = ?");
  $stmt->bind_param("di", $amount, $from_wallet_id);
  $stmt->execute();
  $stmt->close();

  // Credit TO
  $stmt = $conn->prepare("UPDATE user_wallets SET balance = balance + ? WHERE wallet_id = ?");
  $stmt->bind_param("di", $to_amount, $to_wallet_id);
  $stmt->execute();
  $stmt->close();

  // Log swap
  $stmt = $conn->prepare("INSERT INTO swap_transactions
    (swap_id, user_id, from_coin, to_coin, from_amount, to_amount, rate_used, created_at)
    VALUES (?, ?, ?, ?, ?, ?, ?, NOW())");
  $stmt->bind_param("sissdds", $swap_id, $user_id, $from, $to, $amount, $to_amount, $rate);
  $stmt->execute();
  $stmt->close();

  // Log send
  $txid1 = uniqid("txid_", true);
  $stmt = $conn->prepare("INSERT INTO transactions
    (coin, wallet_id, sender_address, receiver_address, amount, type, txid, confirmation, status, applied, swap_id, note, created_at)
    VALUES (?, ?, ?, ?, ?, 'send', ?, 0, 'completed', 1, ?, 'Swap out', NOW())");
  $stmt->bind_param("sissdss", $from, $from_wallet_id, $from_address, $to_address, $amount, $txid1, $swap_id);
  $stmt->execute();
  $stmt->close();

  // Log receive
  $txid2 = uniqid("txid_", true);
  $stmt = $conn->prepare("INSERT INTO transactions
    (coin, wallet_id, sender_address, receiver_address, amount, type, txid, confirmation, status, applied, swap_id, note, created_at)
    VALUES (?, ?, ?, ?, ?, 'receive', ?, 0, 'completed', 1, ?, 'Swap in', NOW())");
  $stmt->bind_param("sissdss", $to, $to_wallet_id, $from_address, $to_address, $to_amount, $txid2, $swap_id);
  $stmt->execute();
  $stmt->close();

  $conn->commit();
  $_SESSION['swap_lock'] = false;

  $_SESSION['swap_success'] = [
    'amount'       => $amount,
    'from'         => $from,
    'to_amount'    => $to_amount,
    'to'           => $to,
    'rate'         => $rate,
    'swap_id'      => $swap_id,
    'from_address' => $from_address,
    'to_address'   => $to_address,
    'timestamp'    => date('M j, Y • h:i A'),
  ];

  header("Location: ../../user/wallets/swap_success.php");
  exit;

} catch (Exception $e) {
  $conn->rollback();
  $_SESSION['swap_lock'] = false;
  exit("Swap failed: " . $e->getMessage());
}

Выполнить команду


Для локальной разработки. Не используйте в интернете!