rwadurian/backend/services/identity-service/src/infrastructure/external/blockchain/blockchain-client.service.ts

144 lines
4.0 KiB
TypeScript

/**
* 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: number;
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<string>(
'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<VerifyMnemonicResult> {
this.logger.log(`Verifying mnemonic against ${params.expectedAddresses.length} addresses`);
try {
const response = await firstValueFrom(
this.httpService.post<VerifyMnemonicResult>(
`${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<VerifyMnemonicHashResult> {
this.logger.log(`Verifying mnemonic for account ${params.accountSequence}`);
try {
const response = await firstValueFrom(
this.httpService.post<VerifyMnemonicHashResult>(
`${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<DerivedAddress[]> {
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;
}
}
}