import { Injectable, Logger, OnModuleInit } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { EvmProviderAdapter, TransferEvent } from './evm-provider.adapter'; import { AddressCacheService } from '@/infrastructure/redis/address-cache.service'; import { ChainConfigService } from '@/domain/services/chain-config.service'; import { ChainType, BlockNumber } from '@/domain/value-objects'; import { ChainTypeEnum } from '@/domain/enums'; export interface DepositEvent extends TransferEvent { chainType: ChainTypeEnum; } export type DepositHandler = (deposits: DepositEvent[]) => Promise; /** * 区块扫描服务 * 定期扫描区块,检测充值交易 */ @Injectable() export class BlockScannerService implements OnModuleInit { private readonly logger = new Logger(BlockScannerService.name); private readonly scanBatchSize: number; private depositHandler?: DepositHandler; private isScanning: Map = new Map(); constructor( private readonly configService: ConfigService, private readonly evmProvider: EvmProviderAdapter, private readonly addressCache: AddressCacheService, private readonly chainConfig: ChainConfigService, ) { this.scanBatchSize = this.configService.get('blockchain.scanBatchSize', 100); } async onModuleInit() { // 初始化扫描状态 for (const chainType of this.chainConfig.getSupportedChains()) { this.isScanning.set(chainType, false); } this.logger.log('BlockScannerService initialized'); } /** * 注册充值处理器 */ registerDepositHandler(handler: DepositHandler): void { this.depositHandler = handler; this.logger.log('Deposit handler registered'); } /** * 扫描指定链的区块 */ async scanChain( chainType: ChainType, fromBlock: BlockNumber, toBlock: BlockNumber, ): Promise { const config = this.chainConfig.getConfig(chainType); const deposits: DepositEvent[] = []; // 获取所有监控地址 const monitoredAddresses = await this.addressCache.getAllAddresses(chainType); const addressSet = new Set(monitoredAddresses.map((a) => a.toLowerCase())); if (addressSet.size === 0) { this.logger.debug(`No monitored addresses for ${chainType}, skipping scan`); return deposits; } // 扫描 USDT Transfer 事件 const events = await this.evmProvider.scanTransferEvents( chainType, fromBlock, toBlock, config.usdtContract, ); // 过滤出充值到监控地址的交易 for (const event of events) { if (addressSet.has(event.to.toLowerCase())) { deposits.push({ ...event, chainType: chainType.value, }); this.logger.log( `Deposit detected: ${event.txHash} -> ${event.to} (${event.value.toString()})`, ); } } return deposits; } /** * 执行单次扫描(供应用层调用) */ async executeScan( chainType: ChainType, lastScannedBlock: BlockNumber, ): Promise<{ deposits: DepositEvent[]; newLastBlock: BlockNumber }> { const currentBlock = await this.evmProvider.getCurrentBlockNumber(chainType); // 计算扫描范围 const fromBlock = lastScannedBlock.add(1); let toBlock = fromBlock.add(this.scanBatchSize - 1); // 不超过当前区块 if (toBlock.isGreaterThan(currentBlock)) { toBlock = currentBlock; } // 如果没有新区块,返回空 if (fromBlock.isGreaterThan(currentBlock)) { return { deposits: [], newLastBlock: lastScannedBlock }; } this.logger.debug(`Scanning ${chainType}: blocks ${fromBlock} to ${toBlock}`); const deposits = await this.scanChain(chainType, fromBlock, toBlock); return { deposits, newLastBlock: toBlock }; } }