105 lines
4.6 KiB
TypeScript
105 lines
4.6 KiB
TypeScript
import { Injectable, Inject, Logger } from '@nestjs/common';
|
|
import { AutoCreateAccountCommand } from './auto-create-account.command';
|
|
import { UserAccountRepository, USER_ACCOUNT_REPOSITORY } from '@/domain/repositories/user-account.repository.interface';
|
|
import { UserAccount } from '@/domain/aggregates/user-account/user-account.aggregate';
|
|
import { AccountSequenceGeneratorService, UserValidatorService, WalletGeneratorService } from '@/domain/services';
|
|
import { ReferralCode, AccountSequence, ProvinceCode, CityCode, ChainType } from '@/domain/value-objects';
|
|
import { TokenService } from '@/application/services/token.service';
|
|
import { EventPublisherService } from '@/infrastructure/kafka/event-publisher.service';
|
|
import { ApplicationError } from '@/shared/exceptions/domain.exception';
|
|
import { AutoCreateAccountResult } from '../index';
|
|
import { MpcShareStorageService } from '@/infrastructure/external/backup/mpc-share-storage.service';
|
|
|
|
@Injectable()
|
|
export class AutoCreateAccountHandler {
|
|
private readonly logger = new Logger(AutoCreateAccountHandler.name);
|
|
|
|
constructor(
|
|
@Inject(USER_ACCOUNT_REPOSITORY)
|
|
private readonly userRepository: UserAccountRepository,
|
|
private readonly sequenceGenerator: AccountSequenceGeneratorService,
|
|
private readonly validatorService: UserValidatorService,
|
|
private readonly walletGenerator: WalletGeneratorService,
|
|
private readonly tokenService: TokenService,
|
|
private readonly eventPublisher: EventPublisherService,
|
|
private readonly mpcShareStorage: MpcShareStorageService,
|
|
) {}
|
|
|
|
async execute(command: AutoCreateAccountCommand): Promise<AutoCreateAccountResult> {
|
|
const deviceValidation = await this.validatorService.validateDeviceId(command.deviceId);
|
|
if (!deviceValidation.isValid) throw new ApplicationError(deviceValidation.errorMessage!);
|
|
|
|
let inviterSequence: AccountSequence | null = null;
|
|
if (command.inviterReferralCode) {
|
|
const referralCode = ReferralCode.create(command.inviterReferralCode);
|
|
const referralValidation = await this.validatorService.validateReferralCode(referralCode);
|
|
if (!referralValidation.isValid) throw new ApplicationError(referralValidation.errorMessage!);
|
|
const inviter = await this.userRepository.findByReferralCode(referralCode);
|
|
inviterSequence = inviter!.accountSequence;
|
|
}
|
|
|
|
const accountSequence = await this.sequenceGenerator.generateNext();
|
|
|
|
const account = UserAccount.createAutomatic({
|
|
accountSequence,
|
|
initialDeviceId: command.deviceId,
|
|
deviceName: command.deviceName,
|
|
inviterSequence,
|
|
province: ProvinceCode.create(command.provinceCode || 'DEFAULT'),
|
|
city: CityCode.create(command.cityCode || 'DEFAULT'),
|
|
});
|
|
|
|
// 使用 MPC 2-of-3 生成三链钱包
|
|
this.logger.log(`Generating MPC wallet for user=${account.userId.toString()}`);
|
|
const mpcResult = await this.walletGenerator.generateMpcWalletSystem({
|
|
userId: account.userId.toString(),
|
|
deviceId: command.deviceId,
|
|
});
|
|
|
|
// 将 MPC 钱包信息转换为领域实体
|
|
const wallets = this.walletGenerator.convertToWalletEntities(
|
|
account.userId,
|
|
mpcResult.wallets,
|
|
);
|
|
|
|
// 保存备份分片到备份服务
|
|
this.logger.log(`Storing backup share for user=${account.userId.toString()}`);
|
|
await this.mpcShareStorage.storeBackupShare({
|
|
userId: account.userId.toString(),
|
|
shareData: mpcResult.backupShareData,
|
|
publicKey: mpcResult.publicKey,
|
|
});
|
|
|
|
account.bindMultipleWalletAddresses(wallets);
|
|
await this.userRepository.save(account);
|
|
await this.userRepository.saveWallets(account.userId, Array.from(wallets.values()));
|
|
|
|
const tokens = await this.tokenService.generateTokenPair({
|
|
userId: account.userId.toString(),
|
|
accountSequence: account.accountSequence.value,
|
|
deviceId: command.deviceId,
|
|
});
|
|
|
|
await this.eventPublisher.publishAll(account.domainEvents);
|
|
account.clearDomainEvents();
|
|
|
|
this.logger.log(`Account created successfully: userId=${account.userId.toString()}, seq=${account.accountSequence.value}`);
|
|
|
|
return {
|
|
userId: account.userId.toString(),
|
|
accountSequence: account.accountSequence.value,
|
|
referralCode: account.referralCode.value,
|
|
mnemonic: '', // MPC 模式下不再使用助记词
|
|
clientShareData: mpcResult.clientShareData, // 客户端需安全存储此分片
|
|
publicKey: mpcResult.publicKey,
|
|
walletAddresses: {
|
|
kava: wallets.get(ChainType.KAVA)!.address,
|
|
dst: wallets.get(ChainType.DST)!.address,
|
|
bsc: wallets.get(ChainType.BSC)!.address,
|
|
},
|
|
accessToken: tokens.accessToken,
|
|
refreshToken: tokens.refreshToken,
|
|
};
|
|
}
|
|
}
|