22 KiB
22 KiB
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 (钱包账户聚合)
钱包账户是核心聚合根,管理用户的所有资产状态:
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 模式,不可修改,确保审计追溯:
LedgerEntry {
entryType: LedgerEntryType // 流水类型
amount: Money // 金额 (正入账/负支出)
assetType: AssetType // 资产类型
balanceAfter: Money? // 操作后余额快照
refOrderId?: string // 关联订单号
refTxHash?: string // 关联交易哈希
memo?: string // 备注
}
4. 流水类型枚举
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. 领域事件
所有聚合操作都会产生领域事件,可用于:
- 异步通知
- 事件溯源
- 跨服务通信
wallet.deposit(amount, chainType, txHash);
// 产生 DepositCompletedEvent
wallet.deduct(amount, reason);
// 产生 BalanceDeductedEvent
2. 仓储接口
基础设施层实现可替换:
- 当前:Prisma + PostgreSQL
- 可扩展:Redis 缓存、MongoDB 等
3. 消息队列集成
预留事件发布接口,可集成:
- RabbitMQ
- Kafka
- Redis Pub/Sub