feat(mnemonic): propagate accountSequence through MPC keygen flow (DDD)
Changes across all three services to properly associate recovery mnemonics with account sequence numbers instead of user IDs, following DDD principles: identity-service: - Add accountSequence to MpcKeygenRequestedEvent payload - Pass accountSequence when publishing keygen request - Remove direct access to recoveryMnemonic table (now in blockchain-service) - Call blockchain-service for mnemonic backup marking - BlockchainWalletHandler no longer saves mnemonic (stored in blockchain-service) mpc-service: - Add accountSequence to KeygenRequestedPayload interface - Pass accountSequence through to blockchain-service when deriving addresses - Include accountSequence in KeygenCompleted event extraPayload blockchain-service: - Add accountSequence to derive-address API and internal interfaces - Add accountSequence to KeygenCompletedPayload extraPayload - Add PUT /internal/mnemonic/backup API for marking mnemonic as backed up - Store recovery mnemonic with accountSequence association 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
e95dc4ca57
commit
1bfbaa06f1
|
|
@ -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<DeriveAddressResponseDto> {
|
||||
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',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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...',
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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<void> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<DeriveAddressResult> {
|
||||
this.logger.log(`[DERIVE] Starting address derivation for user ${userId}`);
|
||||
async deriveAndRegister(params: DeriveAddressParams): Promise<DeriveAddressResult> {
|
||||
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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { DomainEvent } from './domain-event.base';
|
|||
|
||||
export interface WalletAddressCreatedPayload {
|
||||
userId: string;
|
||||
accountSequence: number; // 8位账户序列号
|
||||
publicKey: string;
|
||||
addresses: {
|
||||
chainType: string;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ export interface KeygenCompletedPayload {
|
|||
threshold: string;
|
||||
extraPayload?: {
|
||||
userId: string;
|
||||
accountSequence: number; // 8位账户序列号,用于关联恢复助记词
|
||||
username: string;
|
||||
delegateShare?: {
|
||||
partyId: string;
|
||||
|
|
|
|||
|
|
@ -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<void> {
|
||||
// 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,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<string | null> {
|
||||
// 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<void> {
|
||||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -140,4 +140,29 @@ export class BlockchainClientService {
|
|||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记助记词已备份
|
||||
*/
|
||||
async markMnemonicBackedUp(accountSequence: number): Promise<void> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ export interface KeygenCompletedPayload {
|
|||
threshold: string;
|
||||
extraPayload?: {
|
||||
userId: string;
|
||||
accountSequence: number; // 8位账户序列号
|
||||
username: string;
|
||||
delegateShare?: {
|
||||
partyId: string;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue