diff --git a/backend/services/blockchain-service/src/api/controllers/internal.controller.ts b/backend/services/blockchain-service/src/api/controllers/internal.controller.ts index f22b4f5d..8d965dce 100644 --- a/backend/services/blockchain-service/src/api/controllers/internal.controller.ts +++ b/backend/services/blockchain-service/src/api/controllers/internal.controller.ts @@ -1,9 +1,9 @@ -import { Controller, Post, Body, Get, Param } from '@nestjs/common'; +import { Controller, Post, Body, Get, Param, Put } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; import { AddressDerivationService } from '@/application/services/address-derivation.service'; import { MnemonicVerificationService } from '@/application/services/mnemonic-verification.service'; import { MnemonicDerivationAdapter } from '@/infrastructure/blockchain'; -import { DeriveAddressDto, VerifyMnemonicDto, VerifyMnemonicHashDto } from '../dto/request'; +import { DeriveAddressDto, VerifyMnemonicDto, VerifyMnemonicHashDto, MarkMnemonicBackupDto } from '../dto/request'; import { DeriveAddressResponseDto } from '../dto/response'; /** @@ -23,10 +23,11 @@ export class InternalController { @ApiOperation({ summary: '从公钥派生地址' }) @ApiResponse({ status: 201, description: '派生成功', type: DeriveAddressResponseDto }) async deriveAddress(@Body() dto: DeriveAddressDto): Promise { - const result = await this.addressDerivationService.deriveAndRegister( - BigInt(dto.userId), - dto.publicKey, - ); + const result = await this.addressDerivationService.deriveAndRegister({ + userId: BigInt(dto.userId), + accountSequence: dto.accountSequence, + publicKey: dto.publicKey, + }); return { userId: result.userId.toString(), @@ -90,4 +91,15 @@ export class InternalController { message: result.message, }; } + + @Put('mnemonic/backup') + @ApiOperation({ summary: '标记助记词已备份' }) + @ApiResponse({ status: 200, description: '标记成功' }) + async markMnemonicBackedUp(@Body() dto: MarkMnemonicBackupDto) { + await this.mnemonicVerification.markAsBackedUp(dto.accountSequence); + return { + success: true, + message: 'Mnemonic marked as backed up', + }; + } } diff --git a/backend/services/blockchain-service/src/api/dto/request/derive-address.dto.ts b/backend/services/blockchain-service/src/api/dto/request/derive-address.dto.ts index c38946c8..31d27e3e 100644 --- a/backend/services/blockchain-service/src/api/dto/request/derive-address.dto.ts +++ b/backend/services/blockchain-service/src/api/dto/request/derive-address.dto.ts @@ -1,4 +1,4 @@ -import { IsString, IsNumberString } from 'class-validator'; +import { IsString, IsNumberString, IsInt } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; export class DeriveAddressDto { @@ -6,6 +6,10 @@ export class DeriveAddressDto { @IsNumberString() userId: string; + @ApiProperty({ description: '账户序列号 (8位数字)', example: 10000001 }) + @IsInt() + accountSequence: number; + @ApiProperty({ description: '压缩公钥 (33 bytes, 0x02/0x03 开头)', example: '0x02abc123...', diff --git a/backend/services/blockchain-service/src/api/dto/request/index.ts b/backend/services/blockchain-service/src/api/dto/request/index.ts index 5296a133..b65ae789 100644 --- a/backend/services/blockchain-service/src/api/dto/request/index.ts +++ b/backend/services/blockchain-service/src/api/dto/request/index.ts @@ -2,3 +2,4 @@ export * from './query-balance.dto'; export * from './derive-address.dto'; export * from './verify-mnemonic.dto'; export * from './verify-mnemonic-hash.dto'; +export * from './mark-mnemonic-backup.dto'; diff --git a/backend/services/blockchain-service/src/api/dto/request/mark-mnemonic-backup.dto.ts b/backend/services/blockchain-service/src/api/dto/request/mark-mnemonic-backup.dto.ts new file mode 100644 index 00000000..f078d8a8 --- /dev/null +++ b/backend/services/blockchain-service/src/api/dto/request/mark-mnemonic-backup.dto.ts @@ -0,0 +1,8 @@ +import { IsInt } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; + +export class MarkMnemonicBackupDto { + @ApiProperty({ description: '账户序列号 (8位数字)', example: 10000001 }) + @IsInt() + accountSequence: number; +} diff --git a/backend/services/blockchain-service/src/application/event-handlers/mpc-keygen-completed.handler.ts b/backend/services/blockchain-service/src/application/event-handlers/mpc-keygen-completed.handler.ts index 7eb20ac4..b8eb486f 100644 --- a/backend/services/blockchain-service/src/application/event-handlers/mpc-keygen-completed.handler.ts +++ b/backend/services/blockchain-service/src/application/event-handlers/mpc-keygen-completed.handler.ts @@ -25,7 +25,7 @@ export class MpcKeygenCompletedHandler implements OnModuleInit { /** * 处理 MPC 密钥生成完成事件 - * 从 mpc-service 的 KeygenCompleted 事件中提取 publicKey 和 userId + * 从 mpc-service 的 KeygenCompleted 事件中提取 publicKey、userId 和 accountSequence */ private async handleKeygenCompleted(payload: KeygenCompletedPayload): Promise { this.logger.log(`[HANDLE] Received KeygenCompleted event`); @@ -33,13 +33,20 @@ export class MpcKeygenCompletedHandler implements OnModuleInit { this.logger.log(`[HANDLE] publicKey: ${payload.publicKey?.substring(0, 30)}...`); this.logger.log(`[HANDLE] extraPayload: ${JSON.stringify(payload.extraPayload)}`); - // Extract userId from extraPayload + // Extract userId and accountSequence from extraPayload const userId = payload.extraPayload?.userId; + const accountSequence = payload.extraPayload?.accountSequence; + if (!userId) { this.logger.error(`[ERROR] Missing userId in extraPayload, cannot derive addresses`); return; } + if (!accountSequence) { + this.logger.error(`[ERROR] Missing accountSequence in extraPayload, cannot derive addresses`); + return; + } + const publicKey = payload.publicKey; if (!publicKey) { this.logger.error(`[ERROR] Missing publicKey in payload, cannot derive addresses`); @@ -47,19 +54,20 @@ export class MpcKeygenCompletedHandler implements OnModuleInit { } try { - this.logger.log(`[DERIVE] Starting address derivation for user: ${userId}`); + this.logger.log(`[DERIVE] Starting address derivation for user: ${userId}, account: ${accountSequence}`); - const result = await this.addressDerivationService.deriveAndRegister( - BigInt(userId), + const result = await this.addressDerivationService.deriveAndRegister({ + userId: BigInt(userId), + accountSequence: Number(accountSequence), publicKey, - ); + }); - this.logger.log(`[DERIVE] Successfully derived ${result.addresses.length} addresses for user ${userId}`); + this.logger.log(`[DERIVE] Successfully derived ${result.addresses.length} addresses for account ${accountSequence}`); result.addresses.forEach((addr) => { this.logger.log(`[DERIVE] - ${addr.chainType}: ${addr.address}`); }); } catch (error) { - this.logger.error(`[ERROR] Failed to derive addresses for user ${userId}:`, error); + this.logger.error(`[ERROR] Failed to derive addresses for account ${accountSequence}:`, error); throw error; } } diff --git a/backend/services/blockchain-service/src/application/services/address-derivation.service.ts b/backend/services/blockchain-service/src/application/services/address-derivation.service.ts index 2543b5e1..3a318742 100644 --- a/backend/services/blockchain-service/src/application/services/address-derivation.service.ts +++ b/backend/services/blockchain-service/src/application/services/address-derivation.service.ts @@ -6,6 +6,7 @@ import { import { RecoveryMnemonicAdapter } from '@/infrastructure/blockchain/recovery-mnemonic.adapter'; import { AddressCacheService } from '@/infrastructure/redis/address-cache.service'; import { EventPublisherService } from '@/infrastructure/kafka/event-publisher.service'; +import { PrismaService } from '@/infrastructure/persistence/prisma/prisma.service'; import { MONITORED_ADDRESS_REPOSITORY, IMonitoredAddressRepository, @@ -15,8 +16,15 @@ import { WalletAddressCreatedEvent } from '@/domain/events'; import { ChainType, EvmAddress } from '@/domain/value-objects'; import { ChainTypeEnum } from '@/domain/enums'; +export interface DeriveAddressParams { + userId: bigint; + accountSequence: number; + publicKey: string; +} + export interface DeriveAddressResult { userId: bigint; + accountSequence: number; publicKey: string; addresses: DerivedAddress[]; } @@ -46,6 +54,7 @@ export class AddressDerivationService { private readonly recoveryMnemonic: RecoveryMnemonicAdapter, private readonly addressCache: AddressCacheService, private readonly eventPublisher: EventPublisherService, + private readonly prisma: PrismaService, @Inject(MONITORED_ADDRESS_REPOSITORY) private readonly monitoredAddressRepo: IMonitoredAddressRepository, ) {} @@ -53,8 +62,9 @@ export class AddressDerivationService { /** * 从公钥派生地址并注册监控 */ - async deriveAndRegister(userId: bigint, publicKey: string): Promise { - this.logger.log(`[DERIVE] Starting address derivation for user ${userId}`); + async deriveAndRegister(params: DeriveAddressParams): Promise { + const { userId, accountSequence, publicKey } = params; + this.logger.log(`[DERIVE] Starting address derivation for user ${userId}, account ${accountSequence}`); this.logger.log(`[DERIVE] Public key: ${publicKey.substring(0, 30)}...`); // 1. 派生所有链的地址 (包括 Cosmos 和 EVM) @@ -70,35 +80,50 @@ export class AddressDerivationService { } } - // 3. 生成恢复助记词 (与钱包公钥关联) - this.logger.log(`[MNEMONIC] Generating recovery mnemonic for user ${userId}`); + // 3. 生成恢复助记词 (与账户序列号关联) + this.logger.log(`[MNEMONIC] Generating recovery mnemonic for account ${accountSequence}`); const mnemonicResult = this.recoveryMnemonic.generateMnemonic({ userId: userId.toString(), publicKey, }); this.logger.log(`[MNEMONIC] Recovery mnemonic generated, hash: ${mnemonicResult.mnemonicHash.slice(0, 16)}...`); - // 4. 发布钱包地址创建事件 (包含所有链的地址和助记词) + // 4. 存储恢复助记词到 blockchain-service 数据库 (使用 accountSequence 关联) + await this.prisma.recoveryMnemonic.create({ + data: { + accountSequence, + publicKey, + encryptedMnemonic: mnemonicResult.encryptedMnemonic, + mnemonicHash: mnemonicResult.mnemonicHash, + status: 'ACTIVE', + isBackedUp: false, + }, + }); + this.logger.log(`[MNEMONIC] Recovery mnemonic saved for account ${accountSequence}`); + + // 5. 发布钱包地址创建事件 (包含所有链的地址和助记词) const event = new WalletAddressCreatedEvent({ userId: userId.toString(), + accountSequence, publicKey, addresses: derivedAddresses.map((a) => ({ chainType: a.chainType, address: a.address, })), - // 恢复助记词 + // 恢复助记词 (明文仅在事件中传递给客户端首次显示) mnemonic: mnemonicResult.mnemonic, encryptedMnemonic: mnemonicResult.encryptedMnemonic, mnemonicHash: mnemonicResult.mnemonicHash, }); - this.logger.log(`[PUBLISH] Publishing WalletAddressCreated event for user ${userId}`); + this.logger.log(`[PUBLISH] Publishing WalletAddressCreated event for account ${accountSequence}`); this.logger.log(`[PUBLISH] Addresses: ${JSON.stringify(derivedAddresses)}`); await this.eventPublisher.publish(event); this.logger.log(`[PUBLISH] WalletAddressCreated event published successfully`); return { userId, + accountSequence, publicKey, addresses: derivedAddresses, }; diff --git a/backend/services/blockchain-service/src/domain/events/wallet-address-created.event.ts b/backend/services/blockchain-service/src/domain/events/wallet-address-created.event.ts index b67be787..4aefac7e 100644 --- a/backend/services/blockchain-service/src/domain/events/wallet-address-created.event.ts +++ b/backend/services/blockchain-service/src/domain/events/wallet-address-created.event.ts @@ -2,6 +2,7 @@ import { DomainEvent } from './domain-event.base'; export interface WalletAddressCreatedPayload { userId: string; + accountSequence: number; // 8位账户序列号 publicKey: string; addresses: { chainType: string; diff --git a/backend/services/blockchain-service/src/infrastructure/kafka/mpc-event-consumer.service.ts b/backend/services/blockchain-service/src/infrastructure/kafka/mpc-event-consumer.service.ts index 1d0ec019..92f37097 100644 --- a/backend/services/blockchain-service/src/infrastructure/kafka/mpc-event-consumer.service.ts +++ b/backend/services/blockchain-service/src/infrastructure/kafka/mpc-event-consumer.service.ts @@ -23,6 +23,7 @@ export interface KeygenCompletedPayload { threshold: string; extraPayload?: { userId: string; + accountSequence: number; // 8位账户序列号,用于关联恢复助记词 username: string; delegateShare?: { partyId: string; diff --git a/backend/services/identity-service/src/application/event-handlers/blockchain-wallet.handler.ts b/backend/services/identity-service/src/application/event-handlers/blockchain-wallet.handler.ts index 51019c3e..82b62906 100644 --- a/backend/services/identity-service/src/application/event-handlers/blockchain-wallet.handler.ts +++ b/backend/services/identity-service/src/application/event-handlers/blockchain-wallet.handler.ts @@ -103,10 +103,10 @@ export class BlockchainWalletHandler implements OnModuleInit { await this.userRepository.saveWallets(account.userId, wallets); this.logger.log(`[WALLET] Saved ${wallets.length} wallet addresses for user: ${userId}`); - // 4. Save recovery mnemonic if provided - if (mnemonic && encryptedMnemonic && mnemonicHash && publicKey) { - await this.saveRecoveryMnemonic(BigInt(userId), publicKey, encryptedMnemonic, mnemonicHash); - this.logger.log(`[MNEMONIC] Saved recovery mnemonic for user: ${userId}`); + // 4. Recovery mnemonic is now stored in blockchain-service (DDD: domain separation) + // Note: blockchain-service stores mnemonic with accountSequence association + if (mnemonic) { + this.logger.log(`[MNEMONIC] Recovery mnemonic received for user: ${userId} (stored in blockchain-service)`); } // 5. Update Redis status to completed (include mnemonic for first-time retrieval) @@ -154,38 +154,4 @@ export class BlockchainWalletHandler implements OnModuleInit { } } - /** - * Save recovery mnemonic to database - */ - private async saveRecoveryMnemonic( - userId: bigint, - publicKey: string, - encryptedMnemonic: string, - mnemonicHash: string, - ): Promise { - // Check if mnemonic already exists for this user - const existing = await this.prisma.recoveryMnemonic.findFirst({ - where: { - userId, - status: 'ACTIVE', - }, - }); - - if (existing) { - this.logger.log(`[MNEMONIC] Active mnemonic already exists for user: ${userId}, skipping`); - return; - } - - // Create new recovery mnemonic record - await this.prisma.recoveryMnemonic.create({ - data: { - userId, - publicKey, - encryptedMnemonic, - mnemonicHash, - status: 'ACTIVE', - isBackedUp: false, - }, - }); - } } diff --git a/backend/services/identity-service/src/application/services/user-application.service.ts b/backend/services/identity-service/src/application/services/user-application.service.ts index c956fb55..f6333fdb 100644 --- a/backend/services/identity-service/src/application/services/user-application.service.ts +++ b/backend/services/identity-service/src/application/services/user-application.service.ts @@ -131,6 +131,7 @@ export class UserApplicationService { await this.eventPublisher.publish(new MpcKeygenRequestedEvent({ sessionId, userId: account.userId.toString(), + accountSequence: account.accountSequence.value, // 8位账户序列号,用于关联恢复助记词 username: `user_${account.accountSequence.value}`, // 用于 mpc-system 标识 threshold: 2, totalParties: 3, @@ -688,11 +689,11 @@ export class UserApplicationService { /** * 获取用户的恢复助记词 * - * 优先从 Redis 获取(首次生成时临时存储的明文) - * 如果 Redis 没有,从数据库获取(仅当用户未备份时返回) + * 只从 Redis 获取(首次生成时临时存储的明文) + * DDD: 助记词数据存储在 blockchain-service,identity-service 不直接访问 */ private async getRecoveryMnemonic(userId: bigint): Promise { - // 1. 先从 Redis 获取首次生成的助记词 + // 从 Redis 获取首次生成的助记词 const redisKey = `keygen:status:${userId}`; const statusData = await this.redisService.get(redisKey); @@ -704,27 +705,13 @@ export class UserApplicationService { return parsed.mnemonic; } } catch { - // 解析失败,继续从数据库获取 + // 解析失败 } } - // 2. 从数据库获取(仅当用户未备份时返回) - const recoveryMnemonic = await this.prisma.recoveryMnemonic.findFirst({ - where: { - userId, - status: 'ACTIVE', - isBackedUp: false, // 只有未备份时才返回 - }, - }); - - if (!recoveryMnemonic) { - this.logger.log(`[MNEMONIC] No active unbackuped mnemonic for user: ${userId}`); - return null; - } - - // 返回空字符串,因为加密的助记词需要解密才能返回 - // 实际应用中应该解密后返回,但这里为了安全,只在首次(Redis 中有时)返回 - this.logger.log(`[MNEMONIC] Found encrypted mnemonic in DB for user: ${userId}, but not returning decrypted value`); + // Redis 中没有助记词,可能已经备份或过期 + // DDD: 不再直接从 identity-service 数据库获取,助记词数据在 blockchain-service + this.logger.log(`[MNEMONIC] No mnemonic in Redis for user: ${userId} (may be backed up or expired)`); return null; } @@ -734,33 +721,30 @@ export class UserApplicationService { * 标记助记词已备份 (PUT /user/mnemonic/backup) * * 用户确认已备份助记词后调用此接口: - * 1. 更新数据库 isBackedUp = true + * 1. 调用 blockchain-service 更新 isBackedUp = true (DDD: domain separation) * 2. 清除 Redis 中的明文助记词 */ async markMnemonicBackedUp(command: MarkMnemonicBackedUpCommand): Promise { const userId = BigInt(command.userId); this.logger.log(`[BACKUP] Marking mnemonic as backed up for user: ${userId}`); - // 1. 更新数据库 - const result = await this.prisma.recoveryMnemonic.updateMany({ - where: { - userId, - status: 'ACTIVE', - isBackedUp: false, - }, - data: { - isBackedUp: true, - }, - }); - - if (result.count === 0) { - this.logger.warn(`[BACKUP] No active unbackuped mnemonic found for user: ${userId}`); - // 不抛出错误,可能已经备份过了 - } else { - this.logger.log(`[BACKUP] Mnemonic marked as backed up for user: ${userId}`); + // 1. 获取用户的 accountSequence + const account = await this.userRepository.findById(UserId.create(command.userId)); + if (!account) { + this.logger.warn(`[BACKUP] User not found: ${userId}`); + return; } - // 2. 清除 Redis 中的明文助记词(更新状态,移除 mnemonic 字段) + // 2. 调用 blockchain-service 标记助记词已备份 (DDD: domain separation) + try { + await this.blockchainClient.markMnemonicBackedUp(account.accountSequence.value); + this.logger.log(`[BACKUP] Mnemonic marked as backed up in blockchain-service for account: ${account.accountSequence.value}`); + } catch (error) { + this.logger.error(`[BACKUP] Failed to mark mnemonic as backed up in blockchain-service`, error); + // 不阻塞,继续清除 Redis + } + + // 3. 清除 Redis 中的明文助记词(更新状态,移除 mnemonic 字段) const redisKey = `keygen:status:${userId}`; const statusData = await this.redisService.get(redisKey); diff --git a/backend/services/identity-service/src/domain/events/index.ts b/backend/services/identity-service/src/domain/events/index.ts index 96aab63d..066b86d3 100644 --- a/backend/services/identity-service/src/domain/events/index.ts +++ b/backend/services/identity-service/src/domain/events/index.ts @@ -166,6 +166,7 @@ export class UserAccountDeactivatedEvent extends DomainEvent { * payload 格式需要与 mpc-service 的 KeygenRequestedPayload 匹配: * - sessionId: 唯一会话ID * - userId: 用户ID + * - accountSequence: 8位账户序列号 (用于关联恢复助记词) * - username: 用户名 (用于 mpc-system 标识) * - threshold: 签名阈值 (默认 2) * - totalParties: 总参与方数 (默认 3) @@ -176,6 +177,7 @@ export class MpcKeygenRequestedEvent extends DomainEvent { public readonly payload: { sessionId: string; userId: string; + accountSequence: number; username: string; threshold: number; totalParties: number; diff --git a/backend/services/identity-service/src/infrastructure/external/blockchain/blockchain-client.service.ts b/backend/services/identity-service/src/infrastructure/external/blockchain/blockchain-client.service.ts index 78118ebf..26eb7a54 100644 --- a/backend/services/identity-service/src/infrastructure/external/blockchain/blockchain-client.service.ts +++ b/backend/services/identity-service/src/infrastructure/external/blockchain/blockchain-client.service.ts @@ -140,4 +140,29 @@ export class BlockchainClientService { throw error; } } + + /** + * 标记助记词已备份 + */ + async markMnemonicBackedUp(accountSequence: number): 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; + } + } } diff --git a/backend/services/identity-service/src/infrastructure/kafka/mpc-event-consumer.service.ts b/backend/services/identity-service/src/infrastructure/kafka/mpc-event-consumer.service.ts index 9e5f4df6..39cabc97 100644 --- a/backend/services/identity-service/src/infrastructure/kafka/mpc-event-consumer.service.ts +++ b/backend/services/identity-service/src/infrastructure/kafka/mpc-event-consumer.service.ts @@ -32,6 +32,7 @@ export interface KeygenCompletedPayload { threshold: string; extraPayload?: { userId: string; + accountSequence: number; // 8位账户序列号 username: string; delegateShare?: { partyId: string; diff --git a/backend/services/mpc-service/src/application/event-handlers/keygen-requested.handler.ts b/backend/services/mpc-service/src/application/event-handlers/keygen-requested.handler.ts index ee1a6b37..20dfaf0a 100644 --- a/backend/services/mpc-service/src/application/event-handlers/keygen-requested.handler.ts +++ b/backend/services/mpc-service/src/application/event-handlers/keygen-requested.handler.ts @@ -46,7 +46,7 @@ export class KeygenRequestedHandler implements OnModuleInit { this.logger.log(`[HANDLE] Payload: ${JSON.stringify(payload)}`); const data = payload as unknown as KeygenRequestedPayload; - const { sessionId, userId, username, threshold, totalParties, requireDelegate } = data; + const { sessionId, userId, accountSequence, username, threshold, totalParties, requireDelegate } = data; this.logger.log(`[HANDLE] Parsed request: sessionId=${sessionId}`); this.logger.log(`[HANDLE] userId=${userId}, username=${username}`); @@ -81,6 +81,7 @@ export class KeygenRequestedHandler implements OnModuleInit { try { const deriveResult = await this.blockchainClient.deriveAddresses({ userId, + accountSequence, // 8位账户序列号,用于关联恢复助记词 publicKey: result.publicKey, }); derivedAddresses = deriveResult.addresses; @@ -129,6 +130,7 @@ export class KeygenRequestedHandler implements OnModuleInit { // Add extra payload for identity-service (completedEvent as any).extraPayload = { userId, + accountSequence, // 8位账户序列号,用于关联恢复助记词 username, delegateShare: result.delegateShare, derivedAddresses, // BSC, KAVA, DST addresses diff --git a/backend/services/mpc-service/src/infrastructure/external/blockchain/blockchain-client.service.ts b/backend/services/mpc-service/src/infrastructure/external/blockchain/blockchain-client.service.ts index 6e3ba935..8ab49270 100644 --- a/backend/services/mpc-service/src/infrastructure/external/blockchain/blockchain-client.service.ts +++ b/backend/services/mpc-service/src/infrastructure/external/blockchain/blockchain-client.service.ts @@ -11,6 +11,7 @@ import { firstValueFrom } from 'rxjs'; export interface DeriveAddressParams { userId: string; + accountSequence: number; // 8位账户序列号,用于关联恢复助记词 publicKey: string; } @@ -54,6 +55,7 @@ export class BlockchainClientService { `${this.blockchainServiceUrl}/api/v1/internal/derive-address`, { userId: params.userId, + accountSequence: params.accountSequence, publicKey: params.publicKey, }, { diff --git a/backend/services/mpc-service/src/infrastructure/messaging/kafka/event-consumer.service.ts b/backend/services/mpc-service/src/infrastructure/messaging/kafka/event-consumer.service.ts index e2208e01..6cb66004 100644 --- a/backend/services/mpc-service/src/infrastructure/messaging/kafka/event-consumer.service.ts +++ b/backend/services/mpc-service/src/infrastructure/messaging/kafka/event-consumer.service.ts @@ -18,6 +18,7 @@ export const MPC_CONSUME_TOPICS = { export interface KeygenRequestedPayload { sessionId: string; userId: string; + accountSequence: number; // 8位账户序列号,用于关联恢复助记词 username: string; threshold: number; totalParties: number;