pool/web/yaamp/commands/PayoutCommand.php
Tanguy Pruvot 9a8c40c71b payouts: detect wallet send timeouts, using tx field
also create a command line script to find the missing db payouts.
2015-10-01 14:53:34 +02:00

193 lines
5.5 KiB
PHP

<?php
/**
* PayoutCommand is a console command :
* - check: compare wallet's chain history and database payouts
*
* To use this command, enter the following on the command line:
* <pre>
* yiimp payout check LYB
* </pre>
*
* @property string $help The command description.
*
*/
class PayoutCommand extends CConsoleCommand
{
protected $basePath;
/**
* Execute the action.
* @param array $args command line parameters specific for this command
* @return integer non zero application exit code after printing help
*/
public function run($args)
{
$runner=$this->getCommandRunner();
$commands=$runner->commands;
$root = realpath(Yii::app()->getBasePath().DIRECTORY_SEPARATOR.'..');
$this->basePath = str_replace(DIRECTORY_SEPARATOR, '/', $root);
$command = arraySafeVal($args,0);
$coinsym = arraySafeVal($args,1);
if (!isset($args[1]) || empty($coinsym)) {
echo "Yiimp payout command\n";
echo "Usage: yiimp payout check <symbol>\n";
return 1;
} elseif ($command == 'check') {
$nbUpdated = $this->checkPayouts($coinsym);
echo "total updated: $nbUpdated\n";
return 0;
}
}
/**
* Provides the command description.
* @return string the command description.
*/
public function getHelp()
{
return parent::getHelp().'payout check';
}
/**
* Check in a wallet completed payouts and missing/extra ones
*/
public function checkPayouts($symbol)
{
$nbUpdated = 0; $nbCreated = 0;
$coin = getdbosql('db_coins', "symbol=:symbol", array(':symbol'=>$symbol));
if (!$coin) {
echo "wallet $symbol not found!\n";
return 0;
}
// Get users using the coin...
$users = dbolist("SELECT DISTINCT A.id AS userid, A.username AS username ".
"FROM accounts A LEFT JOIN coins C ON C.id = A.coinid ".
"WHERE A.coinid={$coin->id} AND A.balance > 0.0"
);
$ids = array();
foreach ($users as $uids) {
$uid = (int) $uids['userid'];
$ids[$uid] = $uids['username'];
}
if (empty($ids))
return 0;
// Get their payouts
$dbPayouts = new db_payouts;
$payouts = $dbPayouts->findAll(array(
'condition'=>"account_id IN (".implode(',',array_keys($ids)).')',
'order'=>'time DESC',
));
if (empty($payouts))
return 0;
$remote = new Bitcoin($coin->rpcuser, $coin->rpcpasswd, $coin->rpchost, $coin->rpcport);
$rawtxs = $remote->listtransactions('', 25000);
foreach ($ids as $uid => $user_addr)
{
$totalsent = 0.0; $totalpayouts = 0.0;
// search the last time the user balance was 0
$since = dboscalar("SELECT time FROM balanceuser WHERE userid=:uid AND balance <= 0 ORDER BY time DESC",
array(':uid'=>$uid)
);
//$since = 0;
if (empty($since)) $since = time()-(7*24*3600);
echo "User was at 0 at this date: ".strftime('%F %c', $since)."\n";
// Get their payouts
$payouts = $dbPayouts->findAll(array(
'condition'=>"account_id=$uid AND time > ".intval($since),
'order'=>'time DESC',
));
// filter user raw transactions
foreach ($rawtxs as $ntx => $tx) {
$time = arraySafeVal($tx,'time');
if ($time < $since) continue;
$match = false;
if (arraySafeVal($tx,'category') == 'send' && arraySafeVal($tx,'address') == $user_addr) {
$amount = abs(arraySafeVal($tx,'amount'));
$txid = arraySafeVal($tx,'txid');
$totalsent += $amount + (float) abs(arraySafeVal($tx,'fee'));
foreach ($payouts as $payout) {
if ($payout->tx == $txid && round($payout->amount) == round($amount)) {
$totalpayouts += $amount + (float) abs(arraySafeVal($tx,'fee'));
$match = true;
if (arraySafeVal($tx, 'confirmations') > 5) {
$payout->completed = 1;
$nbUpdated += $payout->save();
//echo "tx {$payout->tx} {$payout->amount} $symbol confirmed\n";
}
break;
}
}
if (!$match) {
/*
// uncomment to do it manually on insufficient founds (need manual checks)
$payout = new db_payouts;
$payout->account_id = $uid;
$payout->tx = $txid;
$payout->time = $time;
$payout->completed = 1;
$payout->amount = $amount;
$payout->fee = abs(arraySafeVal($tx,'fee'));
$nbCreated += $payout->save();
$user = getdbo('db_accounts', $uid);
if ($user) {
$user->balance = floatval($user->balance) - $amount;
dborun("UPDATE balanceuser SET balance = (balance - $amount) WHERE userid=$uid AND time>=$time");
$user->save();
}
$match = true;
*/
$time = strftime('%F %c', $time);
echo "extra user tx $txid $time $amount $symbol\n";
}
}
//if (0 && !$match && arraySafeVal($tx,'category') == 'send') {
// $time = strftime('%F %c', $time);
// $txid = arraySafeVal($tx,'txid');
// $amount = abs(arraySafeVal($tx,'amount'));
// $address = arraySafeVal($tx,'address');
// echo "unknown tx $txid $time $amount $symbol to $address\n";
//}
}
// get the extra payouts
$payouts = $dbPayouts->findAll(array(
'condition'=>"completed=0 AND account_id=$uid AND time > ".intval($since),
'order'=>'time DESC',
));
$totaldiff = $totalsent - $totalpayouts;
if ($totaldiff > 0.0) {
// search payouts not in db
foreach ($payouts as $payout) {
$time = strftime('%F %c', $payout->time);
echo "extra db tx: $time {$payout->tx} {$payout->amount} $symbol\n";
}
}
echo "Total sent to $user_addr: $totalsent (real) $totalpayouts (db) -> Diff $totaldiff $symbol\n";
}
if ($nbCreated)
echo "$nbUpdated payouts confirmed, $nbUpdated payouts created\n";
else if ($nbUpdated)
echo "$nbUpdated payouts confirmed\n";
return $nbCreated;
}
}