/** * Blockchain Client Service * * identity-service 调用 blockchain-service API * - 验证助记词 * - 从助记词派生地址 */ import { Injectable, Logger } from '@nestjs/common'; import { HttpService } from '@nestjs/axios'; import { ConfigService } from '@nestjs/config'; import { firstValueFrom } from 'rxjs'; export interface VerifyMnemonicParams { mnemonic: string; expectedAddresses: Array<{ chainType: string; address: string; }>; } export interface VerifyMnemonicResult { valid: boolean; matchedAddresses: string[]; mismatchedAddresses: string[]; } export interface VerifyMnemonicByAccountParams { accountSequence: string; // 格式: D + YYMMDD + 5位序号 mnemonic: string; } export interface VerifyMnemonicHashResult { valid: boolean; message?: string; } export interface DerivedAddress { chainType: string; address: string; } @Injectable() export class BlockchainClientService { private readonly logger = new Logger(BlockchainClientService.name); private readonly blockchainServiceUrl: string; constructor( private readonly httpService: HttpService, private readonly configService: ConfigService, ) { this.blockchainServiceUrl = this.configService.get( 'BLOCKCHAIN_SERVICE_URL', 'http://blockchain-service:3000', ); this.logger.log(`[INIT] BlockchainClientService initialized`); this.logger.log(`[INIT] URL: ${this.blockchainServiceUrl}`); } /** * 验证助记词是否匹配指定的钱包地址 */ async verifyMnemonic( params: VerifyMnemonicParams, ): Promise { this.logger.log( `Verifying mnemonic against ${params.expectedAddresses.length} addresses`, ); try { const response = await firstValueFrom( this.httpService.post( `${this.blockchainServiceUrl}/internal/verify-mnemonic`, { mnemonic: params.mnemonic, expectedAddresses: params.expectedAddresses, }, { headers: { 'Content-Type': 'application/json' }, timeout: 30000, }, ), ); this.logger.log( `Mnemonic verification result: valid=${response.data.valid}`, ); return response.data; } catch (error) { this.logger.error('Failed to verify mnemonic', error); throw error; } } /** * 通过账户序列号验证助记词(用于账户恢复) */ async verifyMnemonicByAccount( params: VerifyMnemonicByAccountParams, ): Promise { this.logger.log(`Verifying mnemonic for account ${params.accountSequence}`); try { const response = await firstValueFrom( this.httpService.post( `${this.blockchainServiceUrl}/internal/verify-mnemonic-hash`, { accountSequence: params.accountSequence, mnemonic: params.mnemonic, }, { headers: { 'Content-Type': 'application/json' }, timeout: 30000, }, ), ); this.logger.log( `Mnemonic verification result: valid=${response.data.valid}`, ); return response.data; } catch (error) { this.logger.error('Failed to verify mnemonic', error); throw error; } } /** * 从助记词派生所有链的钱包地址 */ async deriveFromMnemonic(mnemonic: string): Promise { this.logger.log('Deriving addresses from mnemonic'); try { const response = await firstValueFrom( this.httpService.post<{ addresses: DerivedAddress[] }>( `${this.blockchainServiceUrl}/internal/derive-from-mnemonic`, { mnemonic }, { headers: { 'Content-Type': 'application/json' }, timeout: 30000, }, ), ); this.logger.log( `Derived ${response.data.addresses.length} addresses from mnemonic`, ); return response.data.addresses; } catch (error) { this.logger.error('Failed to derive addresses from mnemonic', error); throw error; } } /** * 标记助记词已备份 */ async markMnemonicBackedUp(accountSequence: string): Promise { this.logger.log( `Marking mnemonic as backed up for account ${accountSequence}`, ); try { await firstValueFrom( this.httpService.put( `${this.blockchainServiceUrl}/internal/mnemonic/backup`, { accountSequence }, { headers: { 'Content-Type': 'application/json' }, timeout: 30000, }, ), ); this.logger.log( `Mnemonic marked as backed up for account ${accountSequence}`, ); } catch (error) { this.logger.error('Failed to mark mnemonic as backed up', error); throw error; } } /** * 挂失助记词 */ async revokeMnemonic( accountSequence: string, reason: string, ): Promise<{ success: boolean; message: string }> { this.logger.log( `Revoking mnemonic for account ${accountSequence}, reason: ${reason}`, ); try { const response = await firstValueFrom( this.httpService.post<{ success: boolean; message: string }>( `${this.blockchainServiceUrl}/internal/mnemonic/revoke`, { accountSequence, reason }, { headers: { 'Content-Type': 'application/json' }, timeout: 30000, }, ), ); this.logger.log( `Mnemonic revoke result: success=${response.data.success}`, ); return response.data; } catch (error) { this.logger.error('Failed to revoke mnemonic', error); throw error; } } }