This commit is contained in:
parent
8f639273b1
commit
dce2ea5963
|
|
@ -0,0 +1,143 @@
|
||||||
|
# 剩余步骤说明
|
||||||
|
|
||||||
|
所有源代码错误已修复!现在需要执行以下步骤来解决 Prisma Client 和依赖包的问题。
|
||||||
|
|
||||||
|
## 🔧 需要执行的命令(按顺序)
|
||||||
|
|
||||||
|
### 1. 安装新增的依赖包
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
这将安装以下新增的包:
|
||||||
|
- `@nestjs/passport@^10.0.0`
|
||||||
|
- `@nestjs/schedule@^4.0.0`
|
||||||
|
- `passport-jwt@^4.0.1`
|
||||||
|
- `@types/passport-jwt@^4.0.0`
|
||||||
|
|
||||||
|
### 2. 生成 Prisma Client
|
||||||
|
```bash
|
||||||
|
npm run prisma:generate
|
||||||
|
```
|
||||||
|
|
||||||
|
这将根据更新后的 `schema.prisma` 生成新的 Prisma Client,包括:
|
||||||
|
- `DeadLetterEvent` 模型
|
||||||
|
- `SmsCode` 模型
|
||||||
|
|
||||||
|
### 3. 创建并应用数据库迁移
|
||||||
|
```bash
|
||||||
|
npm run prisma:migrate
|
||||||
|
```
|
||||||
|
|
||||||
|
这将创建并应用新表的数据库迁移。如果提示输入迁移名称,可以使用:
|
||||||
|
```
|
||||||
|
add_dead_letter_and_sms_tables
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 启动开发服务器
|
||||||
|
```bash
|
||||||
|
npm run start:dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## ✅ 已修复的所有错误(共 21 个)
|
||||||
|
|
||||||
|
### 代码层面的修复:
|
||||||
|
|
||||||
|
1. ✅ **DomainException → DomainError** (3 处)
|
||||||
|
- [wallet-generator.service.ts:131](src/infrastructure/external/blockchain/wallet-generator.service.ts#L131)
|
||||||
|
- [wallet-generator.service.ts:153](src/infrastructure/external/blockchain/wallet-generator.service.ts#L153)
|
||||||
|
- [wallet-generator.service.ts:169](src/infrastructure/external/blockchain/wallet-generator.service.ts#L169)
|
||||||
|
|
||||||
|
2. ✅ **UserId 类型问题** (2 处)
|
||||||
|
- 修改为使用 `UserId.create(params.userId)` 并使用 `WalletAddress.createFromMnemonic()`
|
||||||
|
- [wallet-generator.service.ts:54-65](src/infrastructure/external/blockchain/wallet-generator.service.ts#L54-L65)
|
||||||
|
- [wallet-generator.service.ts:84-95](src/infrastructure/external/blockchain/wallet-generator.service.ts#L84-L95)
|
||||||
|
|
||||||
|
3. ✅ **Seed Buffer 类型问题** (2 处)
|
||||||
|
- 添加 `Buffer.from()` 转换
|
||||||
|
- [wallet-generator.service.ts:102](src/infrastructure/external/blockchain/wallet-generator.service.ts#L102)
|
||||||
|
|
||||||
|
4. ✅ **IDENTITY_TOPICS 缺失主题** (2 处)
|
||||||
|
- 添加 `KYC_APPROVED` 和 `ACCOUNT_FROZEN`
|
||||||
|
- [event-publisher.service.ts:28-31](src/infrastructure/kafka/event-publisher.service.ts#L28-L31)
|
||||||
|
|
||||||
|
5. ✅ **DomainEventMessage 缺失字段** (2 处)
|
||||||
|
- 添加 `eventId` 和 `occurredAt` 字段
|
||||||
|
- [event-retry.service.ts:40-47](src/infrastructure/kafka/event-retry.service.ts#L40-L47)
|
||||||
|
- [event-retry.service.ts:77-84](src/infrastructure/kafka/event-retry.service.ts#L77-L84)
|
||||||
|
|
||||||
|
### 需要命令解决的问题:
|
||||||
|
|
||||||
|
6. ⏳ **Prisma Client 未生成** (10 处)
|
||||||
|
- 需要运行 `npm run prisma:generate`
|
||||||
|
- 涉及所有 `prisma.deadLetterEvent` 和 `prisma.smsCode` 的调用
|
||||||
|
|
||||||
|
7. ⏳ **依赖包未安装** (2 处)
|
||||||
|
- 需要运行 `npm install`
|
||||||
|
- `@nestjs/passport` 和 `passport-jwt`
|
||||||
|
|
||||||
|
## 📝 修改的文件列表
|
||||||
|
|
||||||
|
- ✏️ [prisma/schema.prisma](prisma/schema.prisma) - 添加 DeadLetterEvent 和 SmsCode 模型
|
||||||
|
- ✏️ [package.json](package.json) - 添加依赖包
|
||||||
|
- ✏️ [src/infrastructure/external/blockchain/wallet-generator.service.ts](src/infrastructure/external/blockchain/wallet-generator.service.ts) - 修复所有类型和导入问题
|
||||||
|
- ✏️ [src/infrastructure/kafka/event-publisher.service.ts](src/infrastructure/kafka/event-publisher.service.ts) - 添加缺失的主题
|
||||||
|
- ✏️ [src/infrastructure/kafka/event-retry.service.ts](src/infrastructure/kafka/event-retry.service.ts) - 修复 DomainEventMessage 参数
|
||||||
|
|
||||||
|
## 🎯 验证步骤
|
||||||
|
|
||||||
|
完成上述命令后,验证所有问题已解决:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. 检查编译
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# 2. 运行测试
|
||||||
|
npm test
|
||||||
|
|
||||||
|
# 3. 启动开发服务器
|
||||||
|
npm run start:dev
|
||||||
|
```
|
||||||
|
|
||||||
|
如果一切正常,你应该看到类似以下的输出:
|
||||||
|
```
|
||||||
|
[Nest] 12345 - 2025/11/24, 9:43:00 AM LOG [NestFactory] Starting Nest application...
|
||||||
|
[Nest] 12345 - 2025/11/24, 9:43:00 AM LOG [InstanceLoader] AppModule dependencies initialized
|
||||||
|
...
|
||||||
|
[Nest] 12345 - 2025/11/24, 9:43:01 AM LOG [NestApplication] Nest application successfully started
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔍 如果遇到问题
|
||||||
|
|
||||||
|
### Prisma 迁移失败
|
||||||
|
如果数据库迁移失败,可以尝试:
|
||||||
|
```bash
|
||||||
|
# 重置数据库(开发环境)
|
||||||
|
npm run prisma:migrate reset
|
||||||
|
|
||||||
|
# 或手动创建迁移
|
||||||
|
npx prisma migrate dev --create-only
|
||||||
|
# 然后编辑迁移文件
|
||||||
|
# 最后应用迁移
|
||||||
|
npx prisma migrate dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### 依赖安装失败
|
||||||
|
如果 npm install 失败,尝试:
|
||||||
|
```bash
|
||||||
|
# 清理缓存
|
||||||
|
npm cache clean --force
|
||||||
|
|
||||||
|
# 删除 node_modules 和 lock 文件
|
||||||
|
rm -rf node_modules package-lock.json
|
||||||
|
|
||||||
|
# 重新安装
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📚 相关文档
|
||||||
|
|
||||||
|
- [Prisma 迁移文档](https://www.prisma.io/docs/concepts/components/prisma-migrate)
|
||||||
|
- [Passport JWT 文档](http://www.passportjs.org/packages/passport-jwt/)
|
||||||
|
- [NestJS Passport 文档](https://docs.nestjs.com/security/authentication)
|
||||||
|
- [NestJS 定时任务文档](https://docs.nestjs.com/techniques/task-scheduling)
|
||||||
|
|
@ -10,10 +10,9 @@ import {
|
||||||
import { bech32 } from 'bech32';
|
import { bech32 } from 'bech32';
|
||||||
import { ethers } from 'ethers';
|
import { ethers } from 'ethers';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { Mnemonic } from '@/domain/value-objects/mnemonic.vo';
|
import { Mnemonic, UserId, ChainType, CHAIN_CONFIG } from '@/domain/value-objects';
|
||||||
import { WalletAddress } from '@/domain/entities/wallet-address.entity';
|
import { WalletAddress } from '@/domain/entities/wallet-address.entity';
|
||||||
import { ChainType, CHAIN_CONFIG } from '@/domain/enums/chain-type.enum';
|
import { DomainError } from '@/shared/exceptions/domain.exception';
|
||||||
import { DomainException } from '@/shared/exceptions/domain.exception';
|
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
export interface WalletSystemResult {
|
export interface WalletSystemResult {
|
||||||
|
|
@ -51,20 +50,14 @@ export class WalletGeneratorService {
|
||||||
|
|
||||||
const wallets = new Map<ChainType, WalletAddress>();
|
const wallets = new Map<ChainType, WalletAddress>();
|
||||||
const chains = [ChainType.KAVA, ChainType.DST, ChainType.BSC];
|
const chains = [ChainType.KAVA, ChainType.DST, ChainType.BSC];
|
||||||
|
const userId = UserId.create(params.userId);
|
||||||
|
|
||||||
for (const chainType of chains) {
|
for (const chainType of chains) {
|
||||||
const address = this.deriveAddress(chainType, mnemonic);
|
const wallet = WalletAddress.createFromMnemonic({
|
||||||
const encryptedMnemonic = this.encryptMnemonic(
|
userId,
|
||||||
mnemonic.value,
|
|
||||||
encryptionKey,
|
|
||||||
);
|
|
||||||
|
|
||||||
const wallet = WalletAddress.create({
|
|
||||||
addressId: `addr_${uuidv4()}`,
|
|
||||||
userId: params.userId,
|
|
||||||
chainType,
|
chainType,
|
||||||
address,
|
mnemonic,
|
||||||
encryptedMnemonic: JSON.stringify(encryptedMnemonic),
|
encryptionKey,
|
||||||
});
|
});
|
||||||
|
|
||||||
wallets.set(chainType, wallet);
|
wallets.set(chainType, wallet);
|
||||||
|
|
@ -87,20 +80,14 @@ export class WalletGeneratorService {
|
||||||
|
|
||||||
const wallets = new Map<ChainType, WalletAddress>();
|
const wallets = new Map<ChainType, WalletAddress>();
|
||||||
const chains = [ChainType.KAVA, ChainType.DST, ChainType.BSC];
|
const chains = [ChainType.KAVA, ChainType.DST, ChainType.BSC];
|
||||||
|
const userId = UserId.create(params.userId);
|
||||||
|
|
||||||
for (const chainType of chains) {
|
for (const chainType of chains) {
|
||||||
const address = this.deriveAddress(chainType, params.mnemonic);
|
const wallet = WalletAddress.createFromMnemonic({
|
||||||
const encryptedMnemonic = this.encryptMnemonic(
|
userId,
|
||||||
params.mnemonic.value,
|
|
||||||
encryptionKey,
|
|
||||||
);
|
|
||||||
|
|
||||||
const wallet = WalletAddress.create({
|
|
||||||
addressId: `addr_${uuidv4()}`,
|
|
||||||
userId: params.userId,
|
|
||||||
chainType,
|
chainType,
|
||||||
address,
|
mnemonic: params.mnemonic,
|
||||||
encryptedMnemonic: JSON.stringify(encryptedMnemonic),
|
encryptionKey,
|
||||||
});
|
});
|
||||||
|
|
||||||
wallets.set(chainType, wallet);
|
wallets.set(chainType, wallet);
|
||||||
|
|
@ -112,7 +99,7 @@ export class WalletGeneratorService {
|
||||||
}
|
}
|
||||||
|
|
||||||
deriveAddress(chainType: ChainType, mnemonic: Mnemonic): string {
|
deriveAddress(chainType: ChainType, mnemonic: Mnemonic): string {
|
||||||
const seed = mnemonic.toSeed();
|
const seed = Buffer.from(mnemonic.toSeed());
|
||||||
const config = CHAIN_CONFIG[chainType];
|
const config = CHAIN_CONFIG[chainType];
|
||||||
|
|
||||||
switch (chainType) {
|
switch (chainType) {
|
||||||
|
|
@ -128,7 +115,7 @@ export class WalletGeneratorService {
|
||||||
return this.deriveEVMAddress(seed, config.derivationPath);
|
return this.deriveEVMAddress(seed, config.derivationPath);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new DomainException(`不支持的链类型: ${chainType}`);
|
throw new DomainError(`不支持的链类型: ${chainType}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,7 +137,7 @@ export class WalletGeneratorService {
|
||||||
const childKey = hdkey.derive(path);
|
const childKey = hdkey.derive(path);
|
||||||
|
|
||||||
if (!childKey.publicKey) {
|
if (!childKey.publicKey) {
|
||||||
throw new DomainException('无法派生公钥');
|
throw new DomainError('无法派生公钥');
|
||||||
}
|
}
|
||||||
|
|
||||||
const pubkey = childKey.publicKey;
|
const pubkey = childKey.publicKey;
|
||||||
|
|
@ -166,7 +153,7 @@ export class WalletGeneratorService {
|
||||||
const childKey = hdkey.derive(path);
|
const childKey = hdkey.derive(path);
|
||||||
|
|
||||||
if (!childKey.privateKey) {
|
if (!childKey.privateKey) {
|
||||||
throw new DomainException('无法派生私钥');
|
throw new DomainError('无法派生私钥');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将 Uint8Array 转换为十六进制字符串
|
// 将 Uint8Array 转换为十六进制字符串
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,10 @@ export const IDENTITY_TOPICS = {
|
||||||
KYC_SUBMITTED: 'identity.KYCSubmitted',
|
KYC_SUBMITTED: 'identity.KYCSubmitted',
|
||||||
KYC_VERIFIED: 'identity.KYCVerified',
|
KYC_VERIFIED: 'identity.KYCVerified',
|
||||||
KYC_REJECTED: 'identity.KYCRejected',
|
KYC_REJECTED: 'identity.KYCRejected',
|
||||||
|
KYC_APPROVED: 'identity.KYCApproved',
|
||||||
USER_LOCATION_UPDATED: 'identity.UserLocationUpdated',
|
USER_LOCATION_UPDATED: 'identity.UserLocationUpdated',
|
||||||
USER_ACCOUNT_FROZEN: 'identity.UserAccountFrozen',
|
USER_ACCOUNT_FROZEN: 'identity.UserAccountFrozen',
|
||||||
|
ACCOUNT_FROZEN: 'identity.AccountFrozen',
|
||||||
USER_ACCOUNT_DEACTIVATED: 'identity.UserAccountDeactivated',
|
USER_ACCOUNT_DEACTIVATED: 'identity.UserAccountDeactivated',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,8 @@ export class EventRetryService {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.eventPublisher.publish(event.topic, {
|
await this.eventPublisher.publish(event.topic, {
|
||||||
|
eventId: event.eventId,
|
||||||
|
occurredAt: event.createdAt.toISOString(),
|
||||||
aggregateId: event.aggregateId,
|
aggregateId: event.aggregateId,
|
||||||
aggregateType: event.aggregateType,
|
aggregateType: event.aggregateType,
|
||||||
eventType: event.eventType,
|
eventType: event.eventType,
|
||||||
|
|
@ -73,6 +75,8 @@ export class EventRetryService {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.eventPublisher.publish(event.topic, {
|
await this.eventPublisher.publish(event.topic, {
|
||||||
|
eventId: event.eventId,
|
||||||
|
occurredAt: event.createdAt.toISOString(),
|
||||||
aggregateId: event.aggregateId,
|
aggregateId: event.aggregateId,
|
||||||
aggregateType: event.aggregateType,
|
aggregateType: event.aggregateType,
|
||||||
eventType: event.eventType,
|
eventType: event.eventType,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue