mirror of
https://github.com/WhatCD/Gazelle.git
synced 2024-12-15 11:56:25 +00:00
186 lines
5.3 KiB
PHP
186 lines
5.3 KiB
PHP
|
<?
|
||
|
class DonationsBitcoin {
|
||
|
/**
|
||
|
* Ask bitcoind for a list of all addresses that have received bitcoins
|
||
|
*
|
||
|
* @return array (BitcoinAddress => Amount, ...)
|
||
|
*/
|
||
|
public static function get_received() {
|
||
|
if (defined('BITCOIN_RPC_URL')) {
|
||
|
$Donations = BitcoinRpc::listreceivedbyaddress();
|
||
|
}
|
||
|
if (empty($Donations)) {
|
||
|
return array();
|
||
|
}
|
||
|
$BTCUsers = array();
|
||
|
foreach ($Donations as $Account) {
|
||
|
$BTCUsers[$Account->address] = $Account->amount;
|
||
|
}
|
||
|
return $BTCUsers;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Ask bitcoind for the current account balance
|
||
|
*
|
||
|
* @return float balance
|
||
|
*/
|
||
|
public static function get_balance() {
|
||
|
if (defined('BITCOIN_RPC_URL')) {
|
||
|
return BitcoinRpc::getbalance();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get a user's existing bitcoin address or generate a new one
|
||
|
*
|
||
|
* @param int $UserID
|
||
|
* @param bool $GenAddress whether to create a new address if it doesn't exist
|
||
|
* @return false if no address exists and $GenAddress is false
|
||
|
* string bitcoin address otherwise
|
||
|
*/
|
||
|
public static function get_address($UserID, $GenAddress = false) {
|
||
|
$UserID = (int)$UserID;
|
||
|
$QueryID = G::$DB->get_query_id();
|
||
|
G::$DB->query("
|
||
|
SELECT BitcoinAddress
|
||
|
FROM users_info
|
||
|
WHERE UserID = '$UserID'");
|
||
|
list($Addr) = G::$DB->next_record();
|
||
|
G::$DB->set_query_id($QueryID);
|
||
|
|
||
|
if (!empty($Addr)) {
|
||
|
return $Addr;
|
||
|
} elseif ($GenAddress) {
|
||
|
if (defined('BITCOIN_RPC_URL')) {
|
||
|
$NewAddr = BitcoinRpc::getnewaddress();
|
||
|
}
|
||
|
if (empty($NewAddr)) {
|
||
|
error(0);
|
||
|
}
|
||
|
$QueryID = G::$DB->get_query_id();
|
||
|
G::$DB->query("
|
||
|
UPDATE users_info
|
||
|
SET BitcoinAddress = '".db_string($NewAddr)."'
|
||
|
WHERE UserID = '$UserID'
|
||
|
AND BitcoinAddress IS NULL");
|
||
|
G::$DB->set_query_id($QueryID);
|
||
|
return $NewAddr;
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Ask bitcoind for the total amount of bitcoins received
|
||
|
*
|
||
|
* @return float amount
|
||
|
*/
|
||
|
public static function get_total_received() {
|
||
|
if (defined('BITCOIN_RPC_URL')) {
|
||
|
$Accounts = BitcoinRpc::listreceivedbyaccount();
|
||
|
}
|
||
|
if (empty($Accounts)) {
|
||
|
return 0.0;
|
||
|
}
|
||
|
foreach ($Accounts as $Account) {
|
||
|
if ($Account->account == '') {
|
||
|
return $Account->amount;
|
||
|
}
|
||
|
}
|
||
|
return 0.0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Translate bitcoin addresses to user IDs
|
||
|
*
|
||
|
* @param array $Addresses list of bitcoin addresses
|
||
|
* @return array (BitcoinAddress => UserID, ...)
|
||
|
*/
|
||
|
public static function get_userids($Addresses) {
|
||
|
if (!is_array($Addresses) || empty($Addresses)) {
|
||
|
return false;
|
||
|
}
|
||
|
$QueryID = G::$DB->get_query_id();
|
||
|
G::$DB->query("
|
||
|
SELECT BitcoinAddress, UserID
|
||
|
FROM users_info
|
||
|
WHERE BitcoinAddress IN ('" . implode("', '", $Addresses) . "')");
|
||
|
if (G::$DB->has_results()) {
|
||
|
$UserIDs = G::$DB->to_pair(0, 1);
|
||
|
} else {
|
||
|
$UserIDs = array();
|
||
|
}
|
||
|
G::$DB->set_query_id($QueryID);
|
||
|
return $UserIDs;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Find and process new donations since the last time this function was called.
|
||
|
*/
|
||
|
public static function find_new_donations() {
|
||
|
global $Debug;
|
||
|
if (($OldAmount = G::$Cache->get_value('btc_total_received')) === false) {
|
||
|
$QueryID = G::$DB->get_query_id();
|
||
|
G::$DB->query("
|
||
|
SELECT IFNULL(SUM(Amount), 0)
|
||
|
FROM donations_bitcoin");
|
||
|
list($OldAmount) = G::$DB->next_record(MYSQLI_NUM, false);
|
||
|
G::$DB->set_query_id($QueryID);
|
||
|
}
|
||
|
$NewAmount = self::get_total_received();
|
||
|
if ($NewAmount < $OldAmount) {
|
||
|
// This shouldn't happen. Perhaps bitcoind was restarted recently
|
||
|
// or the block index was removed. Either way, try again later
|
||
|
send_irc('PRIVMSG ' . LAB_CHAN . " :Bad bitcoin donation data (is $NewAmount, was $OldAmount). If this persists, something is probably wrong");
|
||
|
return false;
|
||
|
}
|
||
|
if ($NewAmount > $OldAmount) {
|
||
|
// I really wish we didn't have to do it like this
|
||
|
$QueryID = G::$DB->get_query_id();
|
||
|
G::$DB->query("
|
||
|
SELECT BitcoinAddress, SUM(Amount)
|
||
|
FROM donations_bitcoin
|
||
|
GROUP BY BitcoinAddress");
|
||
|
$OldDonations = G::$DB->to_pair(0, 1, false);
|
||
|
G::$DB->set_query_id($QueryID);
|
||
|
$NewDonations = self::get_received();
|
||
|
foreach ($NewDonations as $Address => &$Amount) {
|
||
|
if (isset($OldDonations[$Address])) {
|
||
|
if ($Amount == $OldDonations[$Address]) { // Direct comparison should be fine as everything comes from bitcoind
|
||
|
unset($NewDonations[$Address]);
|
||
|
continue;
|
||
|
}
|
||
|
$Debug->log_var(array('old' => $OldDonations[$Address], 'new' => $Amount), "New donations from $Address");
|
||
|
// PHP doesn't do fixed-point math, and json_decode has already botched the precision
|
||
|
// so let's just round this off to satoshis and pray that we're on a 64 bit system
|
||
|
$Amount = round($Amount - $OldDonations[$Address], 8);
|
||
|
}
|
||
|
$NewDonations[$Address] = $Amount;
|
||
|
}
|
||
|
$Debug->log_var($NewDonations, '$NewDonations');
|
||
|
foreach (self::get_userids(array_keys($NewDonations)) as $Address => $UserID) {
|
||
|
Donations::regular_donate($UserID, $NewDonations[$Address], 'Bitcoin Parser', '', 'BTC');
|
||
|
self::store_donation($Address, $NewDonations[$Address]);
|
||
|
}
|
||
|
G::$Cache->cache_value('btc_total_received', $NewAmount, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Record a donation in the database
|
||
|
*
|
||
|
* @param string $Address bitcoin address
|
||
|
* @param double $Amount amount of bitcoins transferred
|
||
|
*/
|
||
|
public static function store_donation($Address, $Amount) {
|
||
|
if (!is_numeric($Amount) || $Amount <= 0) {
|
||
|
// Panic!
|
||
|
return false;
|
||
|
}
|
||
|
G::$DB->query("
|
||
|
INSERT INTO donations_bitcoin
|
||
|
(BitcoinAddress, Amount)
|
||
|
VALUES
|
||
|
('$Address', $Amount)");
|
||
|
}
|
||
|
}
|