384 lines
21 KiB
Markdown
384 lines
21 KiB
Markdown
# Wallet Service 架构设计文档
|
||
|
||
## 概述
|
||
|
||
Wallet Service 是 RWA (Real World Assets) 榴莲认种平台的核心钱包与账本服务,负责管理用户资产、处理充值/提现、记录交易流水、管理奖励结算等功能。
|
||
|
||
## 技术栈
|
||
|
||
| 组件 | 技术选型 | 版本 |
|
||
|------|---------|------|
|
||
| 运行时 | Node.js | 20.x |
|
||
| 框架 | NestJS | 10.x |
|
||
| 语言 | TypeScript | 5.x |
|
||
| ORM | Prisma | 5.x |
|
||
| 数据库 | PostgreSQL | 15.x |
|
||
| 认证 | JWT (passport-jwt) | - |
|
||
| 精度计算 | Decimal.js | 10.x |
|
||
| API文档 | Swagger | 7.x |
|
||
|
||
## 架构模式
|
||
|
||
本服务采用 **领域驱动设计 (DDD)** + **CQRS** 架构模式:
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────────┐
|
||
│ Presentation Layer │
|
||
│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────────┐ │
|
||
│ │ WalletController │ │ LedgerController │ │ DepositController │ │
|
||
│ │ /wallet/* │ │ /wallet/ledger │ │ /wallet/deposit │ │
|
||
│ └────────┬─────────┘ └────────┬─────────┘ └──────────┬───────────┘ │
|
||
└───────────┼─────────────────────┼──────────────────────┼────────────────┘
|
||
│ │ │
|
||
┌───────────┼─────────────────────┼──────────────────────┼────────────────┐
|
||
│ │ Application Layer (CQRS) │ │
|
||
│ ▼ ▼ ▼ │
|
||
│ ┌────────────────────────────────────────────────────────────────┐ │
|
||
│ │ WalletApplicationService │ │
|
||
│ │ ┌─────────────────────┐ ┌─────────────────────────────┐ │ │
|
||
│ │ │ Commands │ │ Queries │ │ │
|
||
│ │ │ - HandleDeposit │ │ - GetMyWallet │ │ │
|
||
│ │ │ - DeductForPlanting │ │ - GetMyLedger │ │ │
|
||
│ │ │ - AddRewards │ │ │ │ │
|
||
│ │ │ - ClaimRewards │ │ │ │ │
|
||
│ │ │ - SettleRewards │ │ │ │ │
|
||
│ │ └─────────────────────┘ └─────────────────────────────┘ │ │
|
||
│ └────────────────────────────────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────────────────┘
|
||
│
|
||
┌─────────────────────────────────┼───────────────────────────────────────┐
|
||
│ Domain Layer │ │
|
||
│ ┌──────────────────────────────┼──────────────────────────────────┐ │
|
||
│ │ Aggregates │ │
|
||
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │
|
||
│ │ │ WalletAccount │ │ DepositOrder │ │ SettlementOrder │ │ │
|
||
│ │ │ (聚合根) │ │ │ │ │ │ │
|
||
│ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │
|
||
│ │ │ │ │
|
||
│ │ ┌──────┴──────────────────────────────────────────────────┐ │ │
|
||
│ │ │ LedgerEntry │ │ │
|
||
│ │ └─────────────────────────────────────────────────────────┘ │ │
|
||
│ └───────────────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ ┌───────────────────────────────────────────────────────────────────┐ │
|
||
│ │ Value Objects │ │
|
||
│ │ Money │ Balance │ Hashpower │ UserId │ WalletId │ Enums │ │
|
||
│ └───────────────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ ┌───────────────────────────────────────────────────────────────────┐ │
|
||
│ │ Domain Events │ │
|
||
│ │ DepositCompleted │ BalanceDeducted │ RewardAdded │ etc. │ │
|
||
│ └───────────────────────────────────────────────────────────────────┘ │
|
||
└──────────────────────────────────────────────────────────────────────────┘
|
||
│
|
||
┌─────────────────────────────────┼───────────────────────────────────────┐
|
||
│ Infrastructure Layer │
|
||
│ ┌────────────────────────────────────────────────────────────────────┐ │
|
||
│ │ Repository Implementations │ │
|
||
│ │ WalletAccountRepository │ LedgerEntryRepository │ etc. │ │
|
||
│ └────────────────────────────────────────────────────────────────────┘ │
|
||
│ ┌────────────────────────────────────────────────────────────────────┐ │
|
||
│ │ Prisma Service │ │
|
||
│ │ (Database Connection Pool) │ │
|
||
│ └────────────────────────────────────────────────────────────────────┘ │
|
||
└──────────────────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌──────────────────┐
|
||
│ PostgreSQL │
|
||
│ Database │
|
||
└──────────────────┘
|
||
```
|
||
|
||
## 目录结构
|
||
|
||
```
|
||
src/
|
||
├── api/ # 表示层 (Presentation Layer)
|
||
│ ├── controllers/ # HTTP 控制器
|
||
│ │ ├── wallet.controller.ts # 钱包相关接口
|
||
│ │ ├── ledger.controller.ts # 流水查询接口
|
||
│ │ ├── deposit.controller.ts # 充值入账接口 (内部)
|
||
│ │ └── health.controller.ts # 健康检查
|
||
│ ├── dto/
|
||
│ │ ├── request/ # 请求 DTO
|
||
│ │ └── response/ # 响应 DTO
|
||
│ └── api.module.ts
|
||
│
|
||
├── application/ # 应用层 (Application Layer)
|
||
│ ├── commands/ # 命令 (写操作)
|
||
│ │ ├── handle-deposit.command.ts
|
||
│ │ ├── deduct-for-planting.command.ts
|
||
│ │ ├── add-rewards.command.ts
|
||
│ │ ├── claim-rewards.command.ts
|
||
│ │ └── settle-rewards.command.ts
|
||
│ ├── queries/ # 查询 (读操作)
|
||
│ │ ├── get-my-wallet.query.ts
|
||
│ │ └── get-my-ledger.query.ts
|
||
│ └── services/
|
||
│ └── wallet-application.service.ts
|
||
│
|
||
├── domain/ # 领域层 (Domain Layer)
|
||
│ ├── aggregates/ # 聚合
|
||
│ │ ├── wallet-account.aggregate.ts
|
||
│ │ ├── ledger-entry.aggregate.ts
|
||
│ │ ├── deposit-order.aggregate.ts
|
||
│ │ └── settlement-order.aggregate.ts
|
||
│ ├── value-objects/ # 值对象
|
||
│ │ ├── money.vo.ts
|
||
│ │ ├── balance.vo.ts
|
||
│ │ ├── hashpower.vo.ts
|
||
│ │ ├── user-id.vo.ts
|
||
│ │ ├── wallet-id.vo.ts
|
||
│ │ └── [各种枚举].enum.ts
|
||
│ ├── events/ # 领域事件
|
||
│ │ ├── deposit-completed.event.ts
|
||
│ │ ├── balance-deducted.event.ts
|
||
│ │ └── [其他事件].ts
|
||
│ └── repositories/ # 仓储接口
|
||
│ ├── wallet-account.repository.interface.ts
|
||
│ └── [其他接口].ts
|
||
│
|
||
├── infrastructure/ # 基础设施层
|
||
│ ├── persistence/
|
||
│ │ ├── prisma/
|
||
│ │ │ └── prisma.service.ts
|
||
│ │ └── repositories/ # 仓储实现
|
||
│ │ ├── wallet-account.repository.impl.ts
|
||
│ │ └── [其他实现].ts
|
||
│ └── infrastructure.module.ts
|
||
│
|
||
├── shared/ # 共享模块
|
||
│ ├── decorators/ # 装饰器
|
||
│ ├── filters/ # 异常过滤器
|
||
│ ├── guards/ # 守卫
|
||
│ ├── interceptors/ # 拦截器
|
||
│ ├── strategies/ # 认证策略
|
||
│ └── exceptions/ # 自定义异常
|
||
│
|
||
├── app.module.ts # 根模块
|
||
└── main.ts # 入口文件
|
||
```
|
||
|
||
## 核心领域模型
|
||
|
||
### 1. WalletAccount (钱包账户聚合)
|
||
|
||
钱包账户是核心聚合根,管理用户的所有资产状态:
|
||
|
||
```typescript
|
||
WalletAccount {
|
||
// 标识
|
||
walletId: WalletId
|
||
userId: UserId
|
||
|
||
// 多币种余额
|
||
balances: {
|
||
usdt: Balance { available, frozen }
|
||
dst: Balance { available, frozen }
|
||
bnb: Balance { available, frozen }
|
||
og: Balance { available, frozen }
|
||
rwad: Balance { available, frozen }
|
||
}
|
||
|
||
// 算力
|
||
hashpower: Hashpower
|
||
|
||
// 奖励状态机
|
||
rewards: {
|
||
pending -> 待领取 (24小时内必须领取)
|
||
settleable -> 可结算 (可兑换为其他币种)
|
||
settled -> 已结算累计
|
||
expired -> 已过期累计
|
||
}
|
||
|
||
// 状态
|
||
status: ACTIVE | FROZEN
|
||
}
|
||
```
|
||
|
||
### 2. 奖励状态机
|
||
|
||
```
|
||
┌──────────────────┐
|
||
│ addReward() │
|
||
└────────┬─────────┘
|
||
▼
|
||
┌──────────────────┐
|
||
┌─────────│ PENDING │─────────┐
|
||
│ │ (待领取, 有过期) │ │
|
||
│ └──────────────────┘ │
|
||
│ │ │
|
||
expire() │ claim() │
|
||
│ │ │
|
||
▼ ▼ │
|
||
┌──────────────────┐ ┌──────────────────┐ │
|
||
│ EXPIRED │ │ SETTLEABLE │ │
|
||
│ (已过期累计) │ │ (可结算) │ │
|
||
└──────────────────┘ └────────┬─────────┘ │
|
||
│ │
|
||
settle() │
|
||
│ │
|
||
▼ │
|
||
┌──────────────────┐ │
|
||
│ SETTLED │ │
|
||
│ (已结算累计) │ │
|
||
└──────────────────┘ │
|
||
```
|
||
|
||
### 3. LedgerEntry (账本流水)
|
||
|
||
采用 **Append-Only** 模式,不可修改,确保审计追溯:
|
||
|
||
```typescript
|
||
LedgerEntry {
|
||
entryType: LedgerEntryType // 流水类型
|
||
amount: Money // 金额 (正入账/负支出)
|
||
assetType: AssetType // 资产类型
|
||
balanceAfter: Money? // 操作后余额快照
|
||
refOrderId?: string // 关联订单号
|
||
refTxHash?: string // 关联交易哈希
|
||
memo?: string // 备注
|
||
}
|
||
```
|
||
|
||
### 4. 流水类型枚举
|
||
|
||
```typescript
|
||
enum LedgerEntryType {
|
||
// 充值相关
|
||
DEPOSIT_KAVA = 'DEPOSIT_KAVA' // KAVA链充值
|
||
DEPOSIT_BSC = 'DEPOSIT_BSC' // BSC链充值
|
||
|
||
// 认种相关
|
||
PLANT_PAYMENT = 'PLANT_PAYMENT' // 认种支付
|
||
|
||
// 奖励相关
|
||
REWARD_PENDING = 'REWARD_PENDING' // 奖励待领取
|
||
REWARD_TO_SETTLEABLE = 'REWARD_TO_SETTLEABLE' // 奖励转可结算
|
||
REWARD_SETTLED = 'REWARD_SETTLED' // 奖励已结算
|
||
REWARD_EXPIRED = 'REWARD_EXPIRED' // 奖励已过期
|
||
|
||
// 其他
|
||
WITHDRAWAL = 'WITHDRAWAL' // 提现
|
||
ADMIN_ADJUST = 'ADMIN_ADJUST' // 管理员调整
|
||
}
|
||
```
|
||
|
||
## 数据库设计
|
||
|
||
### ER 图
|
||
|
||
```
|
||
┌─────────────────────┐ ┌─────────────────────┐
|
||
│ wallet_accounts │ │ wallet_ledger_ │
|
||
│ │ │ entries │
|
||
├─────────────────────┤ ├─────────────────────┤
|
||
│ wallet_id (PK) │───┐ │ entry_id (PK) │
|
||
│ user_id (UK) │ │ │ user_id (FK) │
|
||
│ usdt_available │ └──▶│ entry_type │
|
||
│ usdt_frozen │ │ amount │
|
||
│ dst_available │ │ asset_type │
|
||
│ dst_frozen │ │ balance_after │
|
||
│ bnb_available │ │ ref_order_id │
|
||
│ bnb_frozen │ │ ref_tx_hash │
|
||
│ og_available │ │ memo │
|
||
│ og_frozen │ │ payload_json │
|
||
│ rwad_available │ │ created_at │
|
||
│ rwad_frozen │ └─────────────────────┘
|
||
│ hashpower │
|
||
│ pending_usdt │ ┌─────────────────────┐
|
||
│ pending_hashpower │ │ deposit_orders │
|
||
│ pending_expire_at │ ├─────────────────────┤
|
||
│ settleable_usdt │ │ order_id (PK) │
|
||
│ settleable_hashpower│ │ user_id (FK) │
|
||
│ settled_total_usdt │ │ chain_type │
|
||
│ settled_total_hp │ │ amount │
|
||
│ expired_total_usdt │ │ tx_hash (UK) │
|
||
│ expired_total_hp │ │ status │
|
||
│ status │ │ confirmed_at │
|
||
│ created_at │ │ created_at │
|
||
│ updated_at │ └─────────────────────┘
|
||
└─────────────────────┘
|
||
┌─────────────────────┐
|
||
│ settlement_orders │
|
||
├─────────────────────┤
|
||
│ order_id (PK) │
|
||
│ user_id (FK) │
|
||
│ usdt_amount │
|
||
│ settle_currency │
|
||
│ swap_tx_hash │
|
||
│ received_amount │
|
||
│ status │
|
||
│ settled_at │
|
||
│ created_at │
|
||
└─────────────────────┘
|
||
```
|
||
|
||
### 精度处理
|
||
|
||
所有金额字段使用 `Decimal(20, 8)` 存储:
|
||
- 20位总精度,8位小数
|
||
- 支持最大 999,999,999,999.99999999
|
||
- 使用 `decimal.js` 库进行计算,避免浮点数精度问题
|
||
|
||
## 安全设计
|
||
|
||
### 认证与授权
|
||
|
||
```
|
||
┌────────────────┐
|
||
│ JWT Token │
|
||
│ (Bearer) │
|
||
└───────┬────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────┐
|
||
│ JwtAuthGuard │
|
||
│ - 验证 Token 签名 │
|
||
│ - 检查 Token 过期 │
|
||
│ - 提取 userId 和 seq │
|
||
└───────────────────────────┬─────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────┐
|
||
│ @Public() 装饰器 │
|
||
│ - 标记为公开接口,跳过认证 │
|
||
│ - 用于内部服务调用 (如 /deposit) │
|
||
└─────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 内部服务调用
|
||
|
||
充值入账接口 (`POST /wallet/deposit`) 使用 `@Public()` 装饰器,跳过 JWT 认证,仅供内部链监控服务调用。生产环境应通过网络隔离保护。
|
||
|
||
## 扩展点
|
||
|
||
### 1. 领域事件
|
||
|
||
所有聚合操作都会产生领域事件,可用于:
|
||
- 异步通知
|
||
- 事件溯源
|
||
- 跨服务通信
|
||
|
||
```typescript
|
||
wallet.deposit(amount, chainType, txHash);
|
||
// 产生 DepositCompletedEvent
|
||
|
||
wallet.deduct(amount, reason);
|
||
// 产生 BalanceDeductedEvent
|
||
```
|
||
|
||
### 2. 仓储接口
|
||
|
||
基础设施层实现可替换:
|
||
- 当前:Prisma + PostgreSQL
|
||
- 可扩展:Redis 缓存、MongoDB 等
|
||
|
||
### 3. 消息队列集成
|
||
|
||
预留事件发布接口,可集成:
|
||
- RabbitMQ
|
||
- Kafka
|
||
- Redis Pub/Sub
|