BnbChainService.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. <?php
  2. namespace App\Module\Blockchain\Services;
  3. use App\Module\Blockchain\Contracts\BlockchainServiceInterface;
  4. use App\Module\Blockchain\Enums\TokenType;
  5. use Illuminate\Support\Facades\Http;
  6. use Illuminate\Support\Facades\Cache;
  7. use Web3\Web3;
  8. use Web3\Providers\HttpProvider;
  9. use Web3\RequestManagers\HttpRequestManager;
  10. use InvalidArgumentException;
  11. class BnbChainService implements BlockchainServiceInterface
  12. {
  13. protected Web3 $web3;
  14. protected array $config;
  15. protected string $network;
  16. protected BscScanService $bscScanService;
  17. public function __construct(BscScanService $bscScanService, string $network = 'mainnet')
  18. {
  19. $this->config = config('blockchain.bnbchain');
  20. $this->network = $network;
  21. $this->bscScanService = $bscScanService;
  22. // 初始化 Web3 连接
  23. $provider = new HttpProvider(new HttpRequestManager(
  24. $this->config['networks'][$network]['rpc'][0],
  25. 10 // 超时时间(秒)
  26. ));
  27. $this->web3 = new Web3($provider);
  28. }
  29. /**
  30. * 获取当前网络配置
  31. */
  32. public function getNetwork(): array
  33. {
  34. return $this->config['networks'][$this->network];
  35. }
  36. /**
  37. * 获取当前链 ID
  38. */
  39. public function getChainId(): int
  40. {
  41. return $this->config['networks'][$this->network]['chain_id'];
  42. }
  43. /**
  44. * 获取区块浏览器 URL
  45. */
  46. public function getExplorerUrl(): string
  47. {
  48. return $this->config['networks'][$this->network]['explorer'];
  49. }
  50. /**
  51. * 获取交易浏览器链接
  52. */
  53. public function getTransactionUrl(string $txHash): string
  54. {
  55. return $this->getExplorerUrl() . '/tx/' . $txHash;
  56. }
  57. /**
  58. * 获取地址浏览器链接
  59. */
  60. public function getAddressUrl(string $address): string
  61. {
  62. return $this->getExplorerUrl() . '/address/' . $address;
  63. }
  64. /**
  65. * 获取代币合约浏览器链接
  66. */
  67. public function getTokenUrl(TokenType $tokenType): ?string
  68. {
  69. $contractAddress = $tokenType->contractAddress();
  70. if (!$contractAddress) {
  71. return null;
  72. }
  73. return $this->getExplorerUrl() . '/token/' . $contractAddress;
  74. }
  75. /**
  76. * 获取最新区块号
  77. */
  78. public function getLatestBlockNumber(): int
  79. {
  80. return Cache::remember('latest_block_number', 10, function () {
  81. $response = $this->web3->eth->blockNumber();
  82. return hexdec($response);
  83. });
  84. }
  85. /**
  86. * 获取当前推荐的 Gas 价格
  87. */
  88. public function getGasPrice(): array
  89. {
  90. return Cache::remember('gas_price', $this->config['cache']['gas_price_ttl'], function () {
  91. $response = $this->web3->eth->gasPrice();
  92. $gasPrice = hexdec($response) / 1e9; // 转换为 GWEI
  93. return [
  94. 'safe_low' => max($this->config['gas']['price']['safe_low'], $gasPrice),
  95. 'standard' => max($this->config['gas']['price']['standard'], $gasPrice * 1.1),
  96. 'fast' => max($this->config['gas']['price']['fast'], $gasPrice * 1.2),
  97. 'current' => $gasPrice
  98. ];
  99. });
  100. }
  101. /**
  102. * MEV 保护:获取带有保护的 Gas 价格
  103. */
  104. public function getMevProtectedGasPrice(): array
  105. {
  106. if (!$this->config['mev_protection']['enabled']) {
  107. return $this->getGasPrice();
  108. }
  109. $gasPrice = $this->getGasPrice();
  110. return [
  111. 'max_priority_fee_per_gas' => $this->config['mev_protection']['max_priority_fee'],
  112. 'max_fee_per_gas' => min(
  113. $this->config['mev_protection']['max_fee'],
  114. $gasPrice['standard'] + $this->config['mev_protection']['max_priority_fee']
  115. )
  116. ];
  117. }
  118. /**
  119. * 实现接口方法:获取余额
  120. */
  121. public function getBalance(string $address, TokenType $tokenType): float
  122. {
  123. return $this->bscScanService->getBalance($address, $tokenType);
  124. }
  125. /**
  126. * 实现接口方法:验证地址
  127. */
  128. public function isValidAddress(string $address): bool
  129. {
  130. return $this->bscScanService->isValidAddress($address);
  131. }
  132. /**
  133. * 实现接口方法:获取交易状态
  134. */
  135. public function getTransactionStatus(string $txHash): array
  136. {
  137. return $this->bscScanService->getTransactionStatus($txHash);
  138. }
  139. /**
  140. * 实现接口方法:获取交易收据
  141. */
  142. public function getTransactionReceipt(string $txHash): array
  143. {
  144. return $this->bscScanService->getTransactionReceipt($txHash);
  145. }
  146. /**
  147. * 实现接口方法:估算 Gas 费用
  148. */
  149. public function estimateGasFee(string $from, string $to, TokenType $tokenType, float $amount): float
  150. {
  151. return $this->bscScanService->estimateGasFee($from, $to, $tokenType, $amount);
  152. }
  153. /**
  154. * 实现接口方法:获取交易历史
  155. */
  156. public function getTransactionHistory(string $address, TokenType $tokenType, int $page = 1, int $limit = 10): array
  157. {
  158. return $this->bscScanService->getTransactionHistory($address, $tokenType, $page, $limit);
  159. }
  160. /**
  161. * 检查交易确认数
  162. */
  163. public function getTransactionConfirmations(string $txHash): int
  164. {
  165. $receipt = $this->getTransactionReceipt($txHash);
  166. if (!isset($receipt['blockNumber'])) {
  167. return 0;
  168. }
  169. $currentBlock = $this->getLatestBlockNumber();
  170. $txBlock = hexdec($receipt['blockNumber']);
  171. return max(0, $currentBlock - $txBlock);
  172. }
  173. /**
  174. * 检查交易是否已经安全确认
  175. */
  176. public function isTransactionSafe(string $txHash): bool
  177. {
  178. $confirmations = $this->getTransactionConfirmations($txHash);
  179. return $confirmations >= $this->config['confirmations']['safe'];
  180. }
  181. }