117 lines
3.4 KiB
PHP
117 lines
3.4 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Channel;
|
|
use App\Models\Device;
|
|
use App\Models\User;
|
|
use App\Models\WalletAddress;
|
|
|
|
/**
|
|
* Resolve auto-transfer switch + per-asset thresholds.
|
|
*
|
|
* Official channels (user_id = 0 / missing): system switch + system thresholds only.
|
|
* Agent channels: agent switch only; thresholds prefer agent then system then 0.
|
|
*/
|
|
class AutoTransferConfig
|
|
{
|
|
/** @var list<string> */
|
|
public const ASSETS = ['USDT', 'TRX', 'ETH', 'BTC', 'BNB'];
|
|
|
|
public function isEnabledForAddress(WalletAddress $address): bool
|
|
{
|
|
$agentId = $this->agentUserIdForDevice((int) $address->device_id);
|
|
if ($agentId === null || $agentId === Channel::OFFICIAL_USER_ID) {
|
|
return $this->systemEnabled();
|
|
}
|
|
|
|
$agent = User::query()->find($agentId);
|
|
|
|
return $agent !== null && (bool) $agent->auto_transfer_enabled;
|
|
}
|
|
|
|
/**
|
|
* Effective threshold for an asset (balance must be strictly greater).
|
|
*/
|
|
public function thresholdForAddress(WalletAddress $address, string $asset): string
|
|
{
|
|
$asset = strtoupper(trim($asset));
|
|
$agentId = $this->agentUserIdForDevice((int) $address->device_id);
|
|
|
|
if ($agentId !== null && $agentId !== Channel::OFFICIAL_USER_ID) {
|
|
$agent = User::query()->find($agentId);
|
|
if ($agent !== null) {
|
|
$col = 'auto_transfer_threshold_'.strtolower($asset);
|
|
$raw = $agent->{$col} ?? null;
|
|
if ($raw !== null && $raw !== '') {
|
|
return $this->normalizeThreshold((string) $raw);
|
|
}
|
|
}
|
|
}
|
|
|
|
return $this->systemThreshold($asset);
|
|
}
|
|
|
|
public function systemEnabled(): bool
|
|
{
|
|
return (bool) config('coruna.auto_transfer.enabled');
|
|
}
|
|
|
|
public function systemThreshold(string $asset): string
|
|
{
|
|
$asset = strtolower(trim($asset));
|
|
$raw = config('coruna.auto_transfer.threshold_'.$asset);
|
|
|
|
return $this->normalizeThreshold(is_scalar($raw) ? (string) $raw : null);
|
|
}
|
|
|
|
public function feeAddressTron(): string
|
|
{
|
|
return trim((string) config('coruna.transfer.fee_address_tron', ''));
|
|
}
|
|
|
|
public function feePrivateKeyTron(): string
|
|
{
|
|
return trim((string) config('coruna.transfer.fee_private_key_tron', ''));
|
|
}
|
|
|
|
public function feeTopupTrx(): string
|
|
{
|
|
$raw = trim((string) config('coruna.transfer.fee_topup_trx', '20'));
|
|
if ($raw === '' || ! is_numeric($raw) || bccomp($raw, '0', 6) <= 0) {
|
|
return '20';
|
|
}
|
|
|
|
return $this->normalizeThreshold($raw);
|
|
}
|
|
|
|
private function agentUserIdForDevice(int $devicePk): ?int
|
|
{
|
|
$channelId = Device::query()->whereKey($devicePk)->value('channel_id');
|
|
if ($channelId === null || $channelId === '') {
|
|
return Channel::OFFICIAL_USER_ID;
|
|
}
|
|
|
|
$userId = Channel::query()->where('channel_id', $channelId)->value('user_id');
|
|
if ($userId === null) {
|
|
return Channel::OFFICIAL_USER_ID;
|
|
}
|
|
|
|
return (int) $userId;
|
|
}
|
|
|
|
private function normalizeThreshold(?string $raw): string
|
|
{
|
|
if ($raw === null || trim($raw) === '') {
|
|
return '0';
|
|
}
|
|
$raw = trim($raw);
|
|
if (! is_numeric($raw)) {
|
|
return '0';
|
|
}
|
|
$raw = rtrim(rtrim(sprintf('%.8F', (float) $raw), '0'), '.');
|
|
|
|
return $raw === '' ? '0' : $raw;
|
|
}
|
|
}
|