BlockchainWallet.php 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. <?php
  2. namespace App\Module\Blockchain\Models;
  3. use App\Module\Blockchain\Enums\TokenType;
  4. use Illuminate\Database\Eloquent\Model;
  5. use Illuminate\Database\Eloquent\Relations\HasMany;
  6. use Illuminate\Support\Facades\DB;
  7. use InvalidArgumentException;
  8. use Illuminate\Support\Facades\Cache;
  9. class BlockchainWallet extends Model
  10. {
  11. protected $table = 'blockchain_wallets';
  12. protected $fillable = [
  13. 'address',
  14. 'type',
  15. 'balance',
  16. 'balance_updated_at',
  17. 'status'
  18. ];
  19. protected $casts = [
  20. 'type' => TokenType::class,
  21. 'balance' => 'decimal:18',
  22. 'balance_updated_at' => 'datetime',
  23. 'status' => 'boolean'
  24. ];
  25. protected static function booted()
  26. {
  27. static::creating(function ($wallet) {
  28. if (!preg_match('/^0x[a-fA-F0-9]{40}$/', $wallet->address)) {
  29. throw new InvalidArgumentException('Invalid wallet address format');
  30. }
  31. });
  32. static::updating(function ($wallet) {
  33. if ($wallet->isDirty('balance')) {
  34. $wallet->balance_updated_at = now();
  35. }
  36. });
  37. }
  38. /**
  39. * 更新钱包余额
  40. * @param float $newBalance 新余额
  41. * @param array|null $syncData 同步数据
  42. */
  43. public function updateBalance(float $newBalance, ?array $syncData = null): void
  44. {
  45. DB::transaction(function () use ($newBalance, $syncData) {
  46. // 获取原始余额
  47. $oldBalance = $this->balance;
  48. // 更新钱包余额
  49. DB::table($this->table)
  50. ->where('id', $this->id)
  51. ->lockForUpdate()
  52. ->update([
  53. 'balance' => $newBalance,
  54. 'balance_updated_at' => now()
  55. ]);
  56. // 刷新模型
  57. $this->refresh();
  58. // 记录余额变更
  59. $logData = [
  60. 'wallet_id' => $this->id,
  61. 'old_balance' => $oldBalance,
  62. 'new_balance' => $newBalance,
  63. 'change_type' => 2, // 2=同步
  64. 'created_at' => now()
  65. ];
  66. // 如果有同步数据,添加到日志
  67. if ($syncData) {
  68. $logData['sync_block_number'] = $syncData['block_number'] ?? null;
  69. $logData['sync_tx_hash'] = $syncData['tx_hash'] ?? null;
  70. $logData['sync_timestamp'] = $syncData['timestamp'] ?? null;
  71. $logData['sync_data'] = json_encode($syncData);
  72. }
  73. DB::table('blockchain_wallet_balance_logs')->insert($logData);
  74. // 清除缓存
  75. $this->clearBalanceCache();
  76. });
  77. }
  78. public function transactions(): HasMany
  79. {
  80. return $this->hasMany(BlockchainTransaction::class, 'from_address', 'address');
  81. }
  82. public function receivedTransactions(): HasMany
  83. {
  84. return $this->hasMany(BlockchainTransaction::class, 'to_address', 'address');
  85. }
  86. public function getCachedBalance(): float
  87. {
  88. $cacheKey = "wallet_balance_{$this->address}_{$this->type->value}";
  89. return Cache::remember($cacheKey, config('blockchain.cache.balance_ttl', 300), function () {
  90. return $this->balance;
  91. });
  92. }
  93. /**
  94. * 清除余额缓存
  95. */
  96. protected function clearBalanceCache(): void
  97. {
  98. $cacheKey = "wallet_balance_{$this->address}_{$this->type->value}";
  99. Cache::forget($cacheKey);
  100. }
  101. }