17 KiB
17 KiB
认种功能架构优化方案
概述
本文档描述认种(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 系统账户类型
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)
// ============================================
// 系统账户表
// 管理成本、运营、总部社区、矿池等系统级账户
// ============================================
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 触发条件
当系统账户需要接收资金但尚未生成钱包地址时:
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 分配目标确定逻辑
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 现有表结构
model RewardLedgerEntry {
// 奖励状态: PENDING → CLAIMABLE → SETTLED 或 PENDING → EXPIRED
rewardStatus String @default("PENDING")
expireAt DateTime? // 24小时后过期时间
claimedAt DateTime? // 用户认种时间(领取)
settledAt DateTime? // 结算时间
expiredAt DateTime? // 实际过期时间
}
5.3 定时任务
// 每分钟检查过期奖励
@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 已有)
model LadderTargetConfig {
roleType RoleType
monthIndex Int // 第几个月
monthlyTarget Int // 当月目标
cumulativeTarget Int // 累计目标
}
6.3 社区考核
- 认种 1 棵后获得社区授权
- 每月保持认种 10 棵维持权益
- 连续 2 个月不达标,降级为普通用户
七、龙虎榜规则
7.1 排名计算(referral-service 已有)
model TeamStatistics {
// 龙虎榜分值 = 团队总认种量 - 最大单个直推团队认种量
maxSingleTeamPlantingCount Int @default(0)
effectivePlantingCountForRanking Int @default(0)
}
7.2 计算公式
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. 系统账户初始化
-- 初始化固定系统账户(地址按需生成)
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. 环境变量
# 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