Greetings everyone I am developing an e-commerce site that allows bitcoin transactions. I am trying to allow buyers to purchase products on the site using bitcoin. I have setup a wallet system that detects the amount of bitcoin the user has by scraping the blockchain explorer or blockchain.info. I have a problem though. I am using blockcypher which is an api to allow the processing of bitcoin transactions. I am stumped as to why it is saying order successfully placed and then it gives a transaction ID as confirmation so that the user can track the progress of the transaction on any of the blockchain explorers such as blochain.com or blockcyper. The code has been put through chatgpt and has no errors and it says the order was placed successfully. Huge disclaimer this is just a hobby project I have no intentions of ever taking it live so don’t mind the products. Can anyone here help me with getting the transactions to broadcast and show up properly. Below is the code from checkout.php
<?php
session_start();
require_once("db.php"); // Ensure the database connection is established
// Ensure the user is logged in
if (!isset($_SESSION['username'])) {
echo "<h1>You must be logged in to view your cart.</h1>";
exit;
}
// Get the logged-in user's username
$username = $_SESSION['username'];
// Query to get the user's available Bitcoin balance and wallet address from the register table
$queryBalance = "SELECT available_bitcoin_balance, bitcoin_wallet_address FROM register WHERE username = ?";
$stmtBalance = $conn->prepare($queryBalance);
$stmtBalance->bind_param("s", $username);
$stmtBalance->execute();
$resultBalance = $stmtBalance->get_result();
if ($resultBalance->num_rows === 0) {
echo "<h1 style='text-align:center;'>No Bitcoin balance found for this user.</h1>";
exit;
}
$rowBalance = $resultBalance->fetch_assoc();
$availableBitcoinBalance = $rowBalance['available_bitcoin_balance'];
$userBitcoinWalletAddress = $rowBalance['bitcoin_wallet_address']; // Get the user's Bitcoin wallet address
// Fetch the live BTC to USD conversion rate from CoinGecko API
function getBtcToUsdConversionRate() {
$url = 'https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
if ($response === false) {
return 30000; // Default value in case of an error
}
$data = json_decode($response, true);
return isset($data['bitcoin']['usd']) ? $data['bitcoin']['usd'] : 30000; // Default to 30000 USD/BTC if not found
}
// Fetch Bitcoin balance from Blockchain API (Blockchain.info)
function getWalletBalance($walletAddress) {
$url = "https://blockchain.info/rawaddr/$walletAddress";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
if ($response === false) {
return 0; // In case of an error, return 0
}
$data = json_decode($response, true);
if (isset($data['final_balance'])) {
// Final balance is in satoshis, convert it to BTC (1 BTC = 100,000,000 satoshis)
return $data['final_balance'] / 100000000;
}
return 0; // Return 0 if balance is not found
}
// Query to get cart items for the user
$query = "
SELECT c.product_id, c.name, c.quantity, c.total_price, c.vendor_bitcoin_wallet_address
FROM cart c
WHERE c.username = ?
";
$stmt = $conn->prepare($query);
$stmt->bind_param("s", $username); // Bind the username parameter securely
$stmt->execute(); // Execute the query
$result = $stmt->get_result(); // Get the result set
// Debugging: check if any rows are returned
if ($result->num_rows === 0) {
echo "<h1 style='text-align:center;'>Your cart is empty.</h1>";
exit;
}
$totalCartPrice = 0;
// Display the user's Bitcoin wallet balance above the purchase button
$userWalletBalance = getWalletBalance($userBitcoinWalletAddress);
echo "<h2 style='text-align:center;'>Your Wallet Balance: <b>$userWalletBalance BTC</b></h2>";
echo "<table style='width:60%; border-radius: 20px;'>
<tbody>
<tr>
<td style='border-radius: 20px 20px 0px 0px;' bgcolor='#2f3947'>
<center><font color='white'>
<i class='fab fa-bitcoin'></i> Bitcoin - Cart</font></center>
</td>
</tr>
<tr><td>
<table border='0'>
<tbody>
<tr>
<td bgcolor='#D8D8D8' style='width:1%'></td>
<td bgcolor='#D8D8D8'><h6><b>Title</b></h6></td>
<td bgcolor='#D8D8D8' style='width:15%'><h6><b>Total Price</b></h6></td>
<td align='center' bgcolor='#D8D8D8' style='width:10%'><h6><b>Action</b></h6></td>
</tr>";
while ($row = $result->fetch_assoc()) {
$productId = htmlspecialchars($row['product_id']);
$productName = htmlspecialchars($row['name']);
$quantity = (int)$row['quantity'];
$totalPriceItem = number_format(floatval($row['total_price']), 2);
$vendorBitcoinWalletAddress = htmlspecialchars($row['vendor_bitcoin_wallet_address']); // Vendor Bitcoin address
// Add item total price to the cart total price
$totalCartPrice += floatval($row['total_price']);
// Convert total USD price to Bitcoin
$totalCartPriceInBtc = $totalCartPrice / getBtcToUsdConversionRate();
// Check if user has enough Bitcoin to cover the total price in Bitcoin
$hasEnoughBitcoin = $userWalletBalance >= $totalCartPriceInBtc;
// Decide which button to show
$actionButton = $hasEnoughBitcoin
? "<form method='POST'>
<input type='hidden' name='username' value='$username'>
<input type='hidden' name='total_price' value='$totalCartPrice'>
<input type='hidden' name='available_bitcoin_balance' value='$userWalletBalance'>
<input type='hidden' name='vendor_bitcoin_address' value='$vendorBitcoinWalletAddress'>
<button class='btn btn-danger' style='border-radius: 50px; padding: 15px 25px; font-size: 18px;' type='submit'>Purchase</button>
</form>"
: "<button class='btn btn-outline-secondary btn-xs' type='button'>-</button>";
// Display the cart item
echo "<tr>
<td><center>
<a href='cart.php?remove_id=$productId'> <font color='#4a536e'><i class='fas fa-trash'></i> Delete</font></a>
</center></td>
<td valign='top'>
<a href='product.php?id=$productId'>$productName</a><br>
$quantity x | <a href='product.php?id=$productId'>
<font color='#4a536e'> $productName</font></a><br>
<h6><i>Priority Mail - <b><font color='#007bff'>USD $totalPriceItem</font></b></i> |
<button class='escrow2 button3'> Escrow </button></h6>
</td>
<td align='center'>
<h6><b><font color='#007bff'>USD $totalPriceItem</font></b></h6>
</td>
<td>
<center>
$actionButton
</center>
</td>
</tr>";
}
echo " </table>
</tbody>
</table>";
// Process the payment after the "Purchase" button is clicked
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Check if POST keys exist before accessing them
if (isset($_POST['username'], $_POST['total_price'], $_POST['available_bitcoin_balance'], $_POST['vendor_bitcoin_address'])) {
// Fetch data from POST request
$username = $_POST['username'];
$totalPrice = $_POST['total_price'];
$availableBitcoinBalance = $_POST['available_bitcoin_balance'];
$vendorBitcoinWalletAddress = $_POST['vendor_bitcoin_address'];
// Fetch the live BTC to USD conversion rate
$btcToUsdConversionRate = getBtcToUsdConversionRate();
// Convert the total price to Bitcoin
$totalCartPriceInBtc = $totalPrice / $btcToUsdConversionRate;
// Set the fixed miner fee in USD
$minerFeeUsd = 3.00;
$minerFeeBtc = $minerFeeUsd / $btcToUsdConversionRate;
// Add miner fee to the total price in Bitcoin
$totalAmountInBtc = $totalCartPriceInBtc + $minerFeeBtc;
// Check if user has enough Bitcoin to cover the total price + fee
if ($availableBitcoinBalance < $totalAmountInBtc) {
echo "<h1 style='text-align:center;'>Insufficient Bitcoin balance</h1>";
exit;
}
// BlockCypher Transaction Creation
$blockCypherToken = '6fcd4a8a0a4a4bf383b8da45f1f84410'; // Replace with your BlockCypher API token
$buyerPrivateKey = 'L1JeSdynCTX8LwYcp2VUL8dxY1BSmGBwfUqTsYpuyZH8Mf8FDLUo'; // Replace with the buyer's private key
$sellerPrivateKey = 'L4YqKJYjFRBnHZoQDMWi1ugimGqsaHW2LyqDvzrV8V2f1h4p6FGU'; // Replace with the seller's private key
// Create the transaction data with two inputs
$txData = [
'inputs' => [
['addresses' => [$userBitcoinWalletAddress]], // Buyer address
['addresses' => [$vendorBitcoinWalletAddress]], // Seller address
],
'outputs' => [
['addresses' => [$vendorBitcoinWalletAddress], 'value' => (int)($totalCartPriceInBtc * 100000000)], // Amount to the seller in satoshis
['addresses' => [$userBitcoinWalletAddress], 'value' => (int)($minerFeeBtc * 100000000)], // Miner fee to the buyer's address
],
];
// Step 1: Create the transaction with BlockCypher
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.blockcypher.com/v1/btc/main/txs/new?token=' . $blockCypherToken);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($txData));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
$response = curl_exec($ch);
curl_close($ch);
// Handle the BlockCypher response and sign the transaction
$txResponse = json_decode($response, true);
if (isset($txResponse['tx']['hash'])) {
$unsignedTx = $txResponse['tx'];
// Sign the transaction with both private keys (buyer & seller)
$signData = [
'tx' => $unsignedTx,
'signatures' => [
$buyerPrivateKey, // Sign with buyer's private key for the first input
$sellerPrivateKey, // Sign with seller's private key for the second input
],
];
// Step 2: Send the signed transaction
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.blockcypher.com/v1/btc/main/txs/send?token=' . $blockCypherToken);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($signData));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
$signedResponse = curl_exec($ch);
curl_close($ch);
$signedTxResponse = json_decode($signedResponse, true);
if (isset($signedTxResponse['tx']['hash'])) {
// Broadcasted transaction hash
$txid = $signedTxResponse['tx']['hash'];
// Show the success message
echo "<h1 style='text-align:center;'>Order placed successfully!</h1>";
echo "<p>Transaction ID: $txid</p>";
echo "<p>Transaction Hash: $txid</p>";
// Optionally, update the user's Bitcoin balance after the successful transaction
$newBitcoinBalance = $availableBitcoinBalance - $totalAmountInBtc;
$queryUpdateBalance = "UPDATE register SET available_bitcoin_balance = ? WHERE username = ?";
$stmtUpdateBalance = $conn->prepare($queryUpdateBalance);
$stmtUpdateBalance->bind_param("ds", $newBitcoinBalance, $username);
$stmtUpdateBalance->execute();
} else {
echo "<pre>" . print_r($signedTxResponse, true) . "</pre>";
echo "<h1 style='text-align:center;'>Transaction broadcasting failed</h1>";
}
} else {
echo "<h1 style='text-align:center;'>Transaction creation failed</h1>";
}
} else {
echo "<h1 style='text-align:center;'>Missing form data</h1>";
}
}
?>
If anyone can help with this it would be greatly appreciated enter image description here Picture of the order successful but yet not broadcastting to the blockchain correctly