rwadurian/backend/services/wallet-service/docs/ARCHITECTURE.md

384 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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