151 lines
6.0 KiB
PHP
Executable File
151 lines
6.0 KiB
PHP
Executable File
<?php
|
|
// salvium_tipbot_monitor.php
|
|
use Salvium\SalviumTipBotDB;
|
|
use Salvium\SalviumWallet;
|
|
|
|
$config = require __DIR__ . '/config.php';
|
|
require_once __DIR__ . '/src/salvium_tipbot_db.php';
|
|
require_once __DIR__ . '/src/salvium_tipbot_wallet.php';
|
|
require_once __DIR__ . '/src/salvium_tipbot_common.php';
|
|
|
|
$db = new SalviumTipBotDB($config);
|
|
$wallet = new SalviumWallet(
|
|
$config['SALVIUM_RPC_HOST'],
|
|
$config['SALVIUM_RPC_PORT'],
|
|
$config['SALVIUM_RPC_USERNAME'],
|
|
$config['SALVIUM_RPC_PASSWORD']
|
|
);
|
|
|
|
// Handle incoming transfers
|
|
$incoming = $wallet->getTransfers('in');
|
|
if ($incoming) {
|
|
foreach ($incoming as $tx) {
|
|
$subaddress = $tx['address'];
|
|
$user = $db->getUserBySubaddress($subaddress);
|
|
if (!$user) continue;
|
|
|
|
try {
|
|
$assetType = $db->normalizeAssetType($tx['asset_type'] ?? 'SAL1');
|
|
} catch (Throwable $e) {
|
|
error_log("Unsupported asset type in {$tx['txid']}: " . ($tx['asset_type'] ?? 'missing'));
|
|
continue;
|
|
}
|
|
|
|
if ($db->isDepositLogged($tx['txid'], $user['id'], $assetType)) continue;
|
|
|
|
$amount = $tx['amount'] / 1e8; // Convert atomic to major units (1 SAL = 1e8 atomic)
|
|
$db->logDeposit($user['id'], $tx['txid'], $amount, $tx['height'], $assetType);
|
|
$db->updateUserBalance($user['id'], $amount, 'add', $assetType);
|
|
|
|
sendMessage($user['telegram_user_id'], "Deposit received: {$amount} {$assetType} added to your balance.");
|
|
}
|
|
}
|
|
|
|
// Handle pending withdrawals
|
|
if (!filter_var($config['WITHDRAWALS_ENABLED'] ?? false, FILTER_VALIDATE_BOOL)) {
|
|
error_log('Withdrawals disabled; skipping pending withdrawal processing.');
|
|
} else {
|
|
$withdrawals = $db->getPendingWithdrawals();
|
|
foreach ($withdrawals as $withdrawal) {
|
|
$assetType = $db->normalizeAssetType($withdrawal['asset_type'] ?? 'SAL1');
|
|
$chatId = (int)($withdrawal['telegram_user_id'] ?? $withdrawal['user_id']);
|
|
$amount = (float)$withdrawal['amount'];
|
|
|
|
$withdrawalFee = (float)($withdrawal['fee_amount'] ?? 0);
|
|
$feeAssetType = null;
|
|
if ($withdrawalFee > 0) {
|
|
$feeAssetType = $db->normalizeAssetType($withdrawal['fee_asset_type'] ?? 'SAL1');
|
|
} elseif ($assetType === 'SAL1') {
|
|
$withdrawalFee = (float)($config['WITHDRAWAL_FEE'] ?? 0);
|
|
$feeAssetType = $withdrawalFee > 0 ? 'SAL1' : null;
|
|
}
|
|
|
|
$refundText = function () use ($db, $withdrawal, $assetType, $amount, $feeAssetType, $withdrawalFee): string {
|
|
$db->updateUserBalance($withdrawal['user_id'], $amount, 'add', $assetType);
|
|
$returned = "{$amount} {$assetType}";
|
|
|
|
if ($feeAssetType !== null && $feeAssetType !== $assetType && $withdrawalFee > 0) {
|
|
$db->updateUserBalance($withdrawal['user_id'], $withdrawalFee, 'add', $feeAssetType);
|
|
$returned .= " and {$withdrawalFee} {$feeAssetType}";
|
|
}
|
|
|
|
return $returned;
|
|
};
|
|
|
|
// Skip if SAL1 amount too low. Token withdrawals use the requested token amount unchanged.
|
|
if ($assetType === 'SAL1' && $amount < $config['MIN_WITHDRAWAL_AMOUNT']) {
|
|
$db->updateWithdrawalStatus($withdrawal['id'], 'failed');
|
|
$returned = $refundText();
|
|
sendMessage($chatId, "Withdrawal amount too low. Minimum is {$config['MIN_WITHDRAWAL_AMOUNT']} SAL1. {$returned} returned to your balance.");
|
|
continue;
|
|
}
|
|
|
|
$amountToSend = $amount;
|
|
if ($feeAssetType !== null && $feeAssetType === $assetType) {
|
|
$amountToSend -= $withdrawalFee;
|
|
}
|
|
|
|
if ($amountToSend <= 0) {
|
|
$db->updateWithdrawalStatus($withdrawal['id'], 'failed');
|
|
$returned = $refundText();
|
|
sendMessage($chatId, "Withdrawal amount must be greater than the fee. {$returned} returned to your balance.");
|
|
continue;
|
|
}
|
|
|
|
$destinations = [
|
|
[
|
|
'address' => $withdrawal['address'],
|
|
'amount' => (int)round($amountToSend * 1e8)
|
|
]
|
|
];
|
|
|
|
$result = $assetType === 'SAL1'
|
|
? $wallet->transfer($destinations, 0, [], 0, 16, true, $assetType)
|
|
: $wallet->transferSplit($destinations, 0, [], 0, null, true, $assetType);
|
|
|
|
$txids = [];
|
|
if (is_array($result)) {
|
|
if (!empty($result['tx_hash'])) {
|
|
$txids[] = $result['tx_hash'];
|
|
}
|
|
if (!empty($result['tx_hash_list']) && is_array($result['tx_hash_list'])) {
|
|
$txids = array_merge($txids, $result['tx_hash_list']);
|
|
}
|
|
}
|
|
$txids = array_values(array_unique(array_filter($txids)));
|
|
|
|
if (!empty($txids)) {
|
|
$txidText = implode(',', $txids);
|
|
$db->updateWithdrawalTxid($withdrawal['id'], $txidText);
|
|
$db->updateWithdrawalStatus($withdrawal['id'], 'sent');
|
|
$feeText = $feeAssetType !== null && $withdrawalFee > 0 ? " Fee: {$withdrawalFee} {$feeAssetType}." : "";
|
|
$txLabel = count($txids) === 1 ? "TxID: {$txidText}" : "TxIDs: {$txidText}";
|
|
sendMessage($chatId, "Withdrawal of {$amountToSend} {$assetType} sent.{$feeText} {$txLabel}");
|
|
} else {
|
|
$db->updateWithdrawalStatus($withdrawal['id'], 'failed');
|
|
$returned = $refundText();
|
|
sendMessage($chatId, "Withdrawal failed. {$returned} returned to your balance. Please try again later.");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Handle pending tips
|
|
$users = [];
|
|
$tips = $db->getAllPendingTips();
|
|
foreach ($tips as $tip) {
|
|
|
|
if ($tip['amount'] < $config['MIN_TIP_AMOUNT']) continue; // skip small tips
|
|
|
|
$recipientId = $tip['recipient_user_id'];
|
|
$assetType = $tip['asset_type'] ?? 'SAL1';
|
|
if (!isset($users[$recipientId])) {
|
|
$users[$recipientId] = $db->getUserByTelegramId($recipientId);
|
|
}
|
|
$db->updateUserBalance($recipientId, $tip['amount'], 'add', $assetType);
|
|
$db->markTipsAsCredited([$tip['id']]);
|
|
sendMessage($recipientId, "You received a credited tip of {$tip['amount']} {$assetType}. Use /balance to check.");
|
|
}
|
|
|
|
?>
|