feat(reward): 补全10种认种奖励分配规则

新增4种系统费用类权益:
- COST_FEE: 成本费 400 USDT → 成本账户(userId=2)
- OPERATION_FEE: 运营费 300 USDT → 运营账户(userId=3)
- HEADQUARTERS_BASE_FEE: 总部社区基础费 9 USDT → 总部社区(userId=1)
- RWAD_POOL_INJECTION: RWAD底池注入 800 USDT → 底池账户(userId=4)

原有6种用户权益类保持不变:
- SHARE_RIGHT: 分享权益 500 USDT
- PROVINCE_AREA_RIGHT: 省区域权益 15 USDT + 1%算力
- PROVINCE_TEAM_RIGHT: 省团队权益 20 USDT
- CITY_AREA_RIGHT: 市区域权益 35 USDT + 2%算力
- CITY_TEAM_RIGHT: 市团队权益 40 USDT
- COMMUNITY_RIGHT: 社区权益 80 USDT

总计: 400 + 300 + 9 + 800 + 500 + 15 + 20 + 35 + 40 + 80 = 2199 USDT

同时更新seed脚本创建4个系统账户

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
hailin 2025-12-07 09:19:20 -08:00
parent 667ca1527a
commit 51be55d315
4 changed files with 286 additions and 8 deletions

View File

@ -2,6 +2,48 @@ import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
// ============================================
// 系统账户定义
// ============================================
const SYSTEM_ACCOUNTS = [
{
userId: BigInt(1),
accountSequence: BigInt(1),
nickname: '总部社区',
referralCode: 'HQ000001',
provinceCode: '000000',
cityCode: '000000',
status: 'SYSTEM',
},
{
userId: BigInt(2),
accountSequence: BigInt(2),
nickname: '成本费账户',
referralCode: 'COST0002',
provinceCode: '000000',
cityCode: '000000',
status: 'SYSTEM',
},
{
userId: BigInt(3),
accountSequence: BigInt(3),
nickname: '运营费账户',
referralCode: 'OPER0003',
provinceCode: '000000',
cityCode: '000000',
status: 'SYSTEM',
},
{
userId: BigInt(4),
accountSequence: BigInt(4),
nickname: 'RWAD底池账户',
referralCode: 'POOL0004',
provinceCode: '000000',
cityCode: '000000',
status: 'SYSTEM',
},
];
async function main() {
console.log('Seeding database...');
@ -14,17 +56,29 @@ async function main() {
await prisma.userDevice.deleteMany();
await prisma.userAccount.deleteMany();
// 初始化账户序列号生成器
// 初始化账户序列号生成器 (从100000开始系统账户使用1-99)
await prisma.accountSequenceGenerator.deleteMany();
await prisma.accountSequenceGenerator.create({
data: {
id: 1,
currentSequence: BigInt(100000), // 从100000开始
currentSequence: BigInt(100000), // 普通用户从100000开始
},
});
// 创建系统账户
console.log('Creating system accounts...');
for (const account of SYSTEM_ACCOUNTS) {
await prisma.userAccount.upsert({
where: { userId: account.userId },
update: account,
create: account,
});
console.log(` - Created system account: ${account.nickname} (userId=${account.userId})`);
}
console.log('Database seeded successfully!');
console.log('- Initialized account sequence generator starting at 100000');
console.log(`- Created ${SYSTEM_ACCOUNTS.length} system accounts (userId 1-4)`);
}
main()

View File

@ -3,8 +3,42 @@ import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function main() {
// ============================================
// 初始化权益定义
// 总计 2199 USDT = 400 + 300 + 9 + 800 + 500 + 15 + 20 + 35 + 40 + 80
// ============================================
const rightDefinitions = [
// === 系统费用类 (1509 USDT) ===
{
rightType: 'COST_FEE',
usdtPerTree: 400,
hashpowerPercent: 0,
payableTo: 'SYSTEM_ACCOUNT',
ruleDescription: '成本费每棵树400 USDT进成本账户(userId=2)',
},
{
rightType: 'OPERATION_FEE',
usdtPerTree: 300,
hashpowerPercent: 0,
payableTo: 'SYSTEM_ACCOUNT',
ruleDescription: '运营费每棵树300 USDT进运营账户(userId=3)',
},
{
rightType: 'HEADQUARTERS_BASE_FEE',
usdtPerTree: 9,
hashpowerPercent: 0,
payableTo: 'HEADQUARTERS',
ruleDescription: '总部社区基础费每棵树9 USDT进总部社区账户(userId=1)',
},
{
rightType: 'RWAD_POOL_INJECTION',
usdtPerTree: 800,
hashpowerPercent: 0,
payableTo: 'SYSTEM_ACCOUNT',
ruleDescription: 'RWAD底池注入每棵树800 USDT注入1号底池(userId=4)',
},
// === 用户权益类 (690 USDT + 算力) ===
{
rightType: 'SHARE_RIGHT',
usdtPerTree: 500,

View File

@ -21,9 +21,22 @@ export interface IAuthorizationServiceClient {
export const REFERRAL_SERVICE_CLIENT = Symbol('IReferralServiceClient');
export const AUTHORIZATION_SERVICE_CLIENT = Symbol('IAuthorizationServiceClient');
// ============================================
// 系统账户ID配置
// ============================================
// 总部社区账户ID
const HEADQUARTERS_COMMUNITY_USER_ID = BigInt(1);
// 成本费账户ID (需要在系统初始化时创建)
const COST_FEE_ACCOUNT_ID = BigInt(2);
// 运营费账户ID (需要在系统初始化时创建)
const OPERATION_FEE_ACCOUNT_ID = BigInt(3);
// RWAD 1号底池账户ID (需要在系统初始化时创建)
const RWAD_POOL_ACCOUNT_ID = BigInt(4);
@Injectable()
export class RewardCalculationService {
constructor(
@ -35,6 +48,7 @@ export class RewardCalculationService {
/**
*
* 2199 USDT = 400 + 300 + 9 + 800 + 500 + 15 + 20 + 35 + 40 + 80
*/
async calculateRewards(params: {
sourceOrderId: bigint;
@ -45,7 +59,47 @@ export class RewardCalculationService {
}): Promise<RewardLedgerEntry[]> {
const rewards: RewardLedgerEntry[] = [];
// 1. 分享权益 (500 USDT)
// ============================================
// 系统费用类 (709 USDT)
// ============================================
// 1. 成本费 (400 USDT)
const costFeeReward = this.calculateCostFee(
params.sourceOrderId,
params.sourceUserId,
params.treeCount,
);
rewards.push(costFeeReward);
// 2. 运营费 (300 USDT)
const operationFeeReward = this.calculateOperationFee(
params.sourceOrderId,
params.sourceUserId,
params.treeCount,
);
rewards.push(operationFeeReward);
// 3. 总部社区基础费 (9 USDT)
const headquartersBaseFeeReward = this.calculateHeadquartersBaseFee(
params.sourceOrderId,
params.sourceUserId,
params.treeCount,
);
rewards.push(headquartersBaseFeeReward);
// 4. RWAD底池注入 (800 USDT)
const rwadPoolReward = this.calculateRwadPoolInjection(
params.sourceOrderId,
params.sourceUserId,
params.treeCount,
);
rewards.push(rwadPoolReward);
// ============================================
// 用户权益类 (690 USDT + 算力)
// ============================================
// 5. 分享权益 (500 USDT)
const shareRewards = await this.calculateShareRights(
params.sourceOrderId,
params.sourceUserId,
@ -53,7 +107,7 @@ export class RewardCalculationService {
);
rewards.push(...shareRewards);
// 2. 省团队权益 (20 USDT)
// 6. 省团队权益 (20 USDT)
const provinceTeamReward = await this.calculateProvinceTeamRight(
params.sourceOrderId,
params.sourceUserId,
@ -62,7 +116,7 @@ export class RewardCalculationService {
);
rewards.push(provinceTeamReward);
// 3. 省区域权益 (15 USDT + 1%算力)
// 7. 省区域权益 (15 USDT + 1%算力)
const provinceAreaReward = this.calculateProvinceAreaRight(
params.sourceOrderId,
params.sourceUserId,
@ -71,7 +125,7 @@ export class RewardCalculationService {
);
rewards.push(provinceAreaReward);
// 4. 市团队权益 (40 USDT)
// 8. 市团队权益 (40 USDT)
const cityTeamReward = await this.calculateCityTeamRight(
params.sourceOrderId,
params.sourceUserId,
@ -80,7 +134,7 @@ export class RewardCalculationService {
);
rewards.push(cityTeamReward);
// 5. 市区域权益 (35 USDT + 2%算力)
// 9. 市区域权益 (35 USDT + 2%算力)
const cityAreaReward = this.calculateCityAreaRight(
params.sourceOrderId,
params.sourceUserId,
@ -89,7 +143,7 @@ export class RewardCalculationService {
);
rewards.push(cityAreaReward);
// 6. 社区权益 (80 USDT)
// 10. 社区权益 (80 USDT)
const communityReward = await this.calculateCommunityRight(
params.sourceOrderId,
params.sourceUserId,
@ -100,6 +154,126 @@ export class RewardCalculationService {
return rewards;
}
// ============================================
// 系统费用计算方法
// ============================================
/**
* (400 USDT)
*
*/
private calculateCostFee(
sourceOrderId: bigint,
sourceUserId: bigint,
treeCount: number,
): RewardLedgerEntry {
const { usdt, hashpowerPercent } = RIGHT_AMOUNTS[RightType.COST_FEE];
const usdtAmount = Money.USDT(usdt * treeCount);
const hashpower = Hashpower.fromTreeCount(treeCount, hashpowerPercent);
const rewardSource = RewardSource.create(
RightType.COST_FEE,
sourceOrderId,
sourceUserId,
);
return RewardLedgerEntry.createSettleable({
userId: COST_FEE_ACCOUNT_ID,
rewardSource,
usdtAmount,
hashpowerAmount: hashpower,
memo: `成本费:来自用户${sourceUserId}的认种,${treeCount}棵树`,
});
}
/**
* (300 USDT)
*
*/
private calculateOperationFee(
sourceOrderId: bigint,
sourceUserId: bigint,
treeCount: number,
): RewardLedgerEntry {
const { usdt, hashpowerPercent } = RIGHT_AMOUNTS[RightType.OPERATION_FEE];
const usdtAmount = Money.USDT(usdt * treeCount);
const hashpower = Hashpower.fromTreeCount(treeCount, hashpowerPercent);
const rewardSource = RewardSource.create(
RightType.OPERATION_FEE,
sourceOrderId,
sourceUserId,
);
return RewardLedgerEntry.createSettleable({
userId: OPERATION_FEE_ACCOUNT_ID,
rewardSource,
usdtAmount,
hashpowerAmount: hashpower,
memo: `运营费:来自用户${sourceUserId}的认种,${treeCount}棵树`,
});
}
/**
* (9 USDT)
*
*/
private calculateHeadquartersBaseFee(
sourceOrderId: bigint,
sourceUserId: bigint,
treeCount: number,
): RewardLedgerEntry {
const { usdt, hashpowerPercent } = RIGHT_AMOUNTS[RightType.HEADQUARTERS_BASE_FEE];
const usdtAmount = Money.USDT(usdt * treeCount);
const hashpower = Hashpower.fromTreeCount(treeCount, hashpowerPercent);
const rewardSource = RewardSource.create(
RightType.HEADQUARTERS_BASE_FEE,
sourceOrderId,
sourceUserId,
);
return RewardLedgerEntry.createSettleable({
userId: HEADQUARTERS_COMMUNITY_USER_ID,
rewardSource,
usdtAmount,
hashpowerAmount: hashpower,
memo: `总部社区基础费:来自用户${sourceUserId}的认种,${treeCount}棵树`,
});
}
/**
* RWAD底池注入 (800 USDT)
* RWAD 1
*/
private calculateRwadPoolInjection(
sourceOrderId: bigint,
sourceUserId: bigint,
treeCount: number,
): RewardLedgerEntry {
const { usdt, hashpowerPercent } = RIGHT_AMOUNTS[RightType.RWAD_POOL_INJECTION];
const usdtAmount = Money.USDT(usdt * treeCount);
const hashpower = Hashpower.fromTreeCount(treeCount, hashpowerPercent);
const rewardSource = RewardSource.create(
RightType.RWAD_POOL_INJECTION,
sourceOrderId,
sourceUserId,
);
return RewardLedgerEntry.createSettleable({
userId: RWAD_POOL_ACCOUNT_ID,
rewardSource,
usdtAmount,
hashpowerAmount: hashpower,
memo: `RWAD底池注入来自用户${sourceUserId}的认种,${treeCount}棵树800U注入1号底池`,
});
}
// ============================================
// 用户权益计算方法
// ============================================
/**
* (500 USDT)
*/

View File

@ -1,4 +1,11 @@
export enum RightType {
// === 系统费用类 ===
COST_FEE = 'COST_FEE', // 成本费 400U
OPERATION_FEE = 'OPERATION_FEE', // 运营费 300U
HEADQUARTERS_BASE_FEE = 'HEADQUARTERS_BASE_FEE', // 总部社区基础费 9U
RWAD_POOL_INJECTION = 'RWAD_POOL_INJECTION', // RWAD底池注入 800U
// === 用户权益类 ===
SHARE_RIGHT = 'SHARE_RIGHT', // 分享权益 500U
PROVINCE_AREA_RIGHT = 'PROVINCE_AREA_RIGHT', // 省区域权益 15U + 1%算力
PROVINCE_TEAM_RIGHT = 'PROVINCE_TEAM_RIGHT', // 省团队权益 20U
@ -9,6 +16,13 @@ export enum RightType {
// 权益金额配置
export const RIGHT_AMOUNTS: Record<RightType, { usdt: number; hashpowerPercent: number }> = {
// 系统费用类
[RightType.COST_FEE]: { usdt: 400, hashpowerPercent: 0 },
[RightType.OPERATION_FEE]: { usdt: 300, hashpowerPercent: 0 },
[RightType.HEADQUARTERS_BASE_FEE]: { usdt: 9, hashpowerPercent: 0 },
[RightType.RWAD_POOL_INJECTION]: { usdt: 800, hashpowerPercent: 0 },
// 用户权益类
[RightType.SHARE_RIGHT]: { usdt: 500, hashpowerPercent: 0 },
[RightType.PROVINCE_AREA_RIGHT]: { usdt: 15, hashpowerPercent: 1 },
[RightType.PROVINCE_TEAM_RIGHT]: { usdt: 20, hashpowerPercent: 0 },
@ -16,3 +30,5 @@ export const RIGHT_AMOUNTS: Record<RightType, { usdt: number; hashpowerPercent:
[RightType.CITY_TEAM_RIGHT]: { usdt: 40, hashpowerPercent: 0 },
[RightType.COMMUNITY_RIGHT]: { usdt: 80, hashpowerPercent: 0 },
};
// 总金额验证: 400 + 300 + 9 + 800 + 500 + 15 + 20 + 35 + 40 + 80 = 2199 USDT