# 认种功能架构优化方案 ## 概述 本文档描述认种(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 { 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 { 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*