rwadurian/docs/planting-architecture-optim...

551 lines
17 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.

# 认种功能架构优化方案
## 概述
本文档描述认种Planting功能的架构优化方案基于现有微服务架构进行扩展实现 2199 USDT 的完整分配流程。
**核心原则:**
- 所有账户地址通过 MPC 按需生成
- 所有资金操作都是区块链转账(从认种人钱包转出)
- 不创建新服务,只扩展现有服务
---
## 一、2199 USDT 分配明细
每棵树认种费用 2199 USDT分配如下
| 序号 | 账户类型 | 金额(USDT) | 说明 |
|------|----------|------------|------|
| 1 | 成本账户 | 400 | 固定成本 |
| 2 | 运营账户 | 300 | 运营费用 |
| 3 | 总部社区账户 | 9 | 总部社区收益 |
| 4 | RWAD矿池 | 800 | 注入矿池30天后开始挖矿 |
| 5 | 直接推荐人 | 500 | 仅直推,无多级 |
| 6 | 省公司区域权益 | 15 | 正式省公司含1%算力) |
| 7 | 省公司团队权益 | 20 | 授权省公司 |
| 8 | 市公司区域权益 | 35 | 正式市公司含2%算力) |
| 9 | 市公司团队权益 | 40 | 授权市公司 |
| 10 | 社区权益 | 80 | 社区授权 |
| **合计** | | **2199** | |
---
## 二、系统账户设计
### 2.1 系统账户类型
```typescript
enum SystemAccountType {
COST_ACCOUNT = 'COST_ACCOUNT', // 成本账户
OPERATION_ACCOUNT = 'OPERATION_ACCOUNT', // 运营账户
HQ_COMMUNITY = 'HQ_COMMUNITY', // 总部社区账户
RWAD_POOL_PENDING = 'RWAD_POOL_PENDING', // RWAD矿池待注入
SYSTEM_PROVINCE = 'SYSTEM_PROVINCE', // 系统省账户(无授权时)
SYSTEM_CITY = 'SYSTEM_CITY', // 系统市账户(无授权时)
}
```
### 2.2 数据库表设计(扩展 authorization-service
```prisma
// ============================================
// 系统账户表
// 管理成本、运营、总部社区、矿池等系统级账户
// ============================================
model SystemAccount {
id BigInt @id @default(autoincrement()) @map("account_id")
// 账户类型
accountType String @map("account_type") @db.VarChar(30)
// 区域信息(仅 SYSTEM_PROVINCE/SYSTEM_CITY 需要)
regionCode String? @map("region_code") @db.VarChar(10)
regionName String? @map("region_name") @db.VarChar(50)
// MPC 生成的钱包地址(按需生成)
walletAddress String? @map("wallet_address") @db.VarChar(42)
mpcPublicKey String? @map("mpc_public_key") @db.VarChar(130)
// 余额
usdtBalance Decimal @default(0) @map("usdt_balance") @db.Decimal(20, 8)
hashpower Decimal @default(0) @map("hashpower") @db.Decimal(20, 8)
// 累计统计
totalReceived Decimal @default(0) @map("total_received") @db.Decimal(20, 8)
totalTransferred Decimal @default(0) @map("total_transferred") @db.Decimal(20, 8)
// 状态
status String @default("ACTIVE") @map("status") @db.VarChar(20)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
ledgerEntries SystemAccountLedger[]
@@unique([accountType, regionCode], name: "uk_account_region")
@@index([accountType], name: "idx_account_type")
@@index([walletAddress], name: "idx_wallet_address")
@@map("system_accounts")
}
// ============================================
// 系统账户流水表
// 记录系统账户的所有资金变动
// ============================================
model SystemAccountLedger {
id BigInt @id @default(autoincrement()) @map("ledger_id")
accountId BigInt @map("account_id")
// 流水类型
entryType String @map("entry_type") @db.VarChar(50)
// 金额
amount Decimal @map("amount") @db.Decimal(20, 8)
balanceAfter Decimal @map("balance_after") @db.Decimal(20, 8)
// 关联信息
sourceOrderId BigInt? @map("source_order_id") // 来源认种订单
txHash String? @map("tx_hash") @db.VarChar(66) // 链上交易哈希
memo String? @map("memo") @db.VarChar(500)
createdAt DateTime @default(now()) @map("created_at")
account SystemAccount @relation(fields: [accountId], references: [id])
@@index([accountId, createdAt(sort: Desc)], name: "idx_account_created")
@@index([sourceOrderId], name: "idx_source_order")
@@index([txHash], name: "idx_tx_hash")
@@map("system_account_ledgers")
}
```
---
## 三、MPC 按需生成地址流程
### 3.1 触发条件
当系统账户需要接收资金但尚未生成钱包地址时:
```typescript
async function ensureWalletAddress(systemAccount: SystemAccount): Promise<string> {
if (systemAccount.walletAddress) {
return systemAccount.walletAddress;
}
// 调用 MPC 服务生成地址
const { publicKey, address } = await mpcService.generateAddress({
accountType: 'SYSTEM',
accountId: systemAccount.id.toString(),
});
// 更新系统账户
await prisma.systemAccount.update({
where: { id: systemAccount.id },
data: {
walletAddress: address,
mpcPublicKey: publicKey,
},
});
// 注册到 blockchain-service 进行监听
await blockchainService.registerMonitoredAddress({
address,
accountType: 'SYSTEM',
accountId: systemAccount.id,
});
return address;
}
```
### 3.2 用户账户按需生成
用户钱包地址在以下场景按需生成:
- 首次认种时(需要从钱包扣款)
- 首次充值时(需要收款地址)
- 查询收款地址时
---
## 四、认种完整流程
### 4.1 流程图
```
用户发起认种请求
验证用户钱包余额 ≥ 2199 USDT × 数量
创建认种订单PENDING
计算分配方案(查询省市授权状态)
执行链上转账(多笔转账)
├── 400 → 成本账户
├── 300 → 运营账户
├── 9 → 总部社区账户
├── 800 → RWAD矿池账户
├── 500 → 直接推荐人(作为待领取奖励)
├── 15+1%算力 → 省区域权益接收方
├── 20 → 省团队权益接收方
├── 35+2%算力 → 市区域权益接收方
├── 40 → 市团队权益接收方
└── 80 → 社区权益接收方
更新订单状态COMPLETED
更新团队统计referral-service
更新授权考核进度authorization-service
30天后启动挖矿矿池注入
```
### 4.2 分配目标确定逻辑
```typescript
interface AllocationTarget {
targetType: string;
targetUserId?: bigint; // 用户账户
targetSystemAccountId?: bigint; // 系统账户
amount: Decimal;
hashpowerPercent?: Decimal;
}
async function calculateAllocation(
planterId: bigint,
treeCount: number,
provinceCode: string,
cityCode: string,
): Promise<AllocationTarget[]> {
const unitPrice = new Decimal(2199);
const totalAmount = unitPrice.mul(treeCount);
const allocations: AllocationTarget[] = [];
// 1. 固定系统账户分配
allocations.push(
{ targetType: 'COST_ACCOUNT', targetSystemAccountId: costAccountId, amount: new Decimal(400).mul(treeCount) },
{ targetType: 'OPERATION_ACCOUNT', targetSystemAccountId: operationAccountId, amount: new Decimal(300).mul(treeCount) },
{ targetType: 'HQ_COMMUNITY', targetSystemAccountId: hqCommunityAccountId, amount: new Decimal(9).mul(treeCount) },
{ targetType: 'RWAD_POOL', targetSystemAccountId: rwadPoolAccountId, amount: new Decimal(800).mul(treeCount) },
);
// 2. 直接推荐人500 USDT
const referrer = await referralService.getDirectReferrer(planterId);
if (referrer) {
allocations.push({
targetType: 'DIRECT_REFERRER',
targetUserId: referrer.userId,
amount: new Decimal(500).mul(treeCount),
});
} else {
// 无推荐人,归入运营账户
allocations.push({
targetType: 'OPERATION_ACCOUNT',
targetSystemAccountId: operationAccountId,
amount: new Decimal(500).mul(treeCount),
});
}
// 3. 省公司权益15 区域 + 20 团队)
const provinceAuth = await authorizationService.getActiveProvinceAuth(provinceCode);
if (provinceAuth?.roleType === 'PROVINCE_COMPANY' && provinceAuth.benefitActive) {
// 正式省公司 - 区域权益 15U + 1% 算力
allocations.push({
targetType: 'PROVINCE_REGION',
targetUserId: provinceAuth.userId,
amount: new Decimal(15).mul(treeCount),
hashpowerPercent: new Decimal(1),
});
} else {
// 无正式省公司,归入系统省账户
const systemProvince = await getOrCreateSystemAccount('SYSTEM_PROVINCE', provinceCode);
allocations.push({
targetType: 'SYSTEM_PROVINCE',
targetSystemAccountId: systemProvince.id,
amount: new Decimal(15).mul(treeCount),
});
}
// 授权省公司 - 团队权益 20U
if (provinceAuth?.roleType === 'AUTH_PROVINCE_COMPANY' && provinceAuth.benefitActive) {
allocations.push({
targetType: 'PROVINCE_TEAM',
targetUserId: provinceAuth.userId,
amount: new Decimal(20).mul(treeCount),
});
} else {
const systemProvince = await getOrCreateSystemAccount('SYSTEM_PROVINCE', provinceCode);
allocations.push({
targetType: 'SYSTEM_PROVINCE',
targetSystemAccountId: systemProvince.id,
amount: new Decimal(20).mul(treeCount),
});
}
// 4. 市公司权益35 区域 + 40 团队)- 类似省公司逻辑
// ...
// 5. 社区权益80 USDT
const communityAuth = await authorizationService.getCommunityAuth(planterId);
if (communityAuth && communityAuth.benefitActive) {
allocations.push({
targetType: 'COMMUNITY',
targetUserId: communityAuth.userId,
amount: new Decimal(80).mul(treeCount),
});
} else {
allocations.push({
targetType: 'OPERATION_ACCOUNT',
targetSystemAccountId: operationAccountId,
amount: new Decimal(80).mul(treeCount),
});
}
return allocations;
}
```
---
## 五、24小时待领取奖励机制
### 5.1 奖励状态流转
```
PENDING待领取
↓ 用户认种
CLAIMABLE可结算
↓ 用户结算
SETTLED已结算
PENDING待领取
↓ 24小时未认种
EXPIRED已过期
```
### 5.2 reward-service 现有表结构
```prisma
model RewardLedgerEntry {
// 奖励状态: PENDING → CLAIMABLE → SETTLED 或 PENDING → EXPIRED
rewardStatus String @default("PENDING")
expireAt DateTime? // 24小时后过期时间
claimedAt DateTime? // 用户认种时间(领取)
settledAt DateTime? // 结算时间
expiredAt DateTime? // 实际过期时间
}
```
### 5.3 定时任务
```typescript
// 每分钟检查过期奖励
@Cron('* * * * *')
async checkExpiredRewards() {
const expiredRewards = await prisma.rewardLedgerEntry.findMany({
where: {
rewardStatus: 'PENDING',
expireAt: { lt: new Date() },
},
});
for (const reward of expiredRewards) {
await prisma.$transaction([
// 更新奖励状态
prisma.rewardLedgerEntry.update({
where: { id: reward.id },
data: {
rewardStatus: 'EXPIRED',
expiredAt: new Date(),
},
}),
// 更新用户汇总
prisma.rewardSummary.update({
where: { userId: reward.userId },
data: {
pendingUsdt: { decrement: reward.usdtAmount },
expiredTotalUsdt: { increment: reward.usdtAmount },
},
}),
]);
// 将过期金额转入运营账户
await transferToOperationAccount(reward.usdtAmount, reward.id);
}
}
```
---
## 六、授权考核规则
### 6.1 省市公司授权考核
| 角色 | 初始目标 | 月度考核 | 权益 |
|------|----------|----------|------|
| 授权省公司 | 500棵 | 阶梯递增 | 团队权益 20U |
| 正式省公司 | 已达标 | 无 | 区域权益 15U + 1%算力 |
| 授权市公司 | 200棵 | 阶梯递增 | 团队权益 40U |
| 正式市公司 | 已达标 | 无 | 区域权益 35U + 2%算力 |
### 6.2 阶梯考核目标authorization-service 已有)
```prisma
model LadderTargetConfig {
roleType RoleType
monthIndex Int // 第几个月
monthlyTarget Int // 当月目标
cumulativeTarget Int // 累计目标
}
```
### 6.3 社区考核
- 认种 1 棵后获得社区授权
- 每月保持认种 10 棵维持权益
- 连续 2 个月不达标,降级为普通用户
---
## 七、龙虎榜规则
### 7.1 排名计算referral-service 已有)
```prisma
model TeamStatistics {
// 龙虎榜分值 = 团队总认种量 - 最大单个直推团队认种量
maxSingleTeamPlantingCount Int @default(0)
effectivePlantingCountForRanking Int @default(0)
}
```
### 7.2 计算公式
```typescript
function calculateLeaderboardScore(userId: bigint): number {
const stats = await getTeamStatistics(userId);
// 有效分值 = 团队总认种 - 最大单线团队认种
return stats.totalTeamPlantingCount - stats.maxSingleTeamPlantingCount;
}
```
---
## 八、服务职责划分
| 服务 | 职责 |
|------|------|
| **planting-service** | 认种订单管理、分配计算、矿池注入批次 |
| **wallet-service** | 用户钱包余额、链上转账执行 |
| **blockchain-service** | 地址监听、交易广播、MPC 交互 |
| **reward-service** | 奖励流水、24h过期处理、结算 |
| **referral-service** | 推荐关系、团队统计、龙虎榜 |
| **authorization-service** | 省市社区授权、考核进度、**系统账户管理** |
| **identity-service** | 用户身份、MPC 钱包创建 |
---
## 九、待实现功能清单
### 9.1 authorization-service 扩展
- [ ] 添加 `SystemAccount`
- [ ] 添加 `SystemAccountLedger`
- [ ] 实现系统账户 CRUD API
- [ ] 实现按需生成 MPC 地址逻辑
### 9.2 planting-service 扩展
- [ ] 实现完整分配计算逻辑
- [ ] 集成 wallet-service 执行链上转账
- [ ] 集成 authorization-service 查询授权状态
- [ ] 集成 referral-service 查询推荐人
### 9.3 reward-service 扩展
- [ ] 实现 24 小时过期定时任务
- [ ] 实现用户认种触发奖励领取
- [ ] 实现过期奖励转入运营账户
### 9.4 wallet-service 扩展
- [ ] 实现批量链上转账 API
- [ ] 支持系统账户转账
### 9.5 blockchain-service 扩展
- [ ] 支持系统账户地址监听
- [ ] 实现 MPC 签名批量交易
---
## 十、数据流示意
```
┌─────────────────────────────────────────────────────────────────────────┐
│ 认种数据流 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 用户钱包 (wallet-service) │
│ │ │
│ │ 2199 USDT × N │
│ ▼ │
│ planting-service │
│ │ │
│ ├─── 400 ──→ 成本账户 (authorization-service.SystemAccount) │
│ ├─── 300 ──→ 运营账户 (authorization-service.SystemAccount) │
│ ├─── 9 ──→ 总部社区 (authorization-service.SystemAccount) │
│ ├─── 800 ──→ RWAD矿池 (authorization-service.SystemAccount) │
│ ├─── 500 ──→ 直推人钱包 (wallet-service) → reward-service (待领取) │
│ ├─── 15 ──→ 省区域 (用户钱包 或 系统省账户) │
│ ├─── 20 ──→ 省团队 (用户钱包 或 系统省账户) │
│ ├─── 35 ──→ 市区域 (用户钱包 或 系统市账户) │
│ ├─── 40 ──→ 市团队 (用户钱包 或 系统市账户) │
│ └─── 80 ──→ 社区 (用户钱包 或 运营账户) │
│ │
│ 所有转账通过 blockchain-service 执行链上交易 │
│ 所有地址通过 MPC 按需生成 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
```
---
## 附录:关键配置
### A. 系统账户初始化
```sql
-- 初始化固定系统账户(地址按需生成)
INSERT INTO system_accounts (account_type, region_code, status) VALUES
('COST_ACCOUNT', NULL, 'ACTIVE'),
('OPERATION_ACCOUNT', NULL, 'ACTIVE'),
('HQ_COMMUNITY', NULL, 'ACTIVE'),
('RWAD_POOL_PENDING', NULL, 'ACTIVE');
```
### B. 环境变量
```env
# MPC 服务配置
MPC_SERVICE_URL=http://mpc-service:3010
# 认种相关
PLANTING_UNIT_PRICE=2199
REWARD_EXPIRE_HOURS=24
MINING_START_DELAY_DAYS=30
```
---
*文档版本: v1.0*
*创建日期: 2025-12-08*
*最后更新: 2025-12-08*