fix(batch-mining): 修正补发计算逻辑
- 去掉虚构的'全网算力'概念 - 每天固定分配70%产出给参与用户 - 用户收益 = 每日产出 × 70% × 天数 × (用户算力/当前参与总算力) - 总补发金额固定为: 日产出 × 70% × 总天数 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
702fa937e8
commit
f14ad0b7ad
|
|
@ -89,8 +89,8 @@ export interface BatchMiningPreviewResult {
|
||||||
// 常量
|
// 常量
|
||||||
const BASE_CONTRIBUTION_PER_TREE = new Decimal('22617'); // 每棵树的基础算力
|
const BASE_CONTRIBUTION_PER_TREE = new Decimal('22617'); // 每棵树的基础算力
|
||||||
const SECONDS_PER_DAY = 86400;
|
const SECONDS_PER_DAY = 86400;
|
||||||
// 用户算力占全网算力的比例(用户占70%,30%是系统、运营、层级、团队的)
|
// 每天产出的70%分给补发用户
|
||||||
const USER_NETWORK_RATIO = new Decimal('0.70');
|
const DAILY_DISTRIBUTION_RATIO = new Decimal('0.70');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 挖矿阶段信息
|
* 挖矿阶段信息
|
||||||
|
|
@ -100,7 +100,7 @@ interface MiningPhase {
|
||||||
startDate: Date;
|
startDate: Date;
|
||||||
endDate: Date;
|
endDate: Date;
|
||||||
daysInPhase: number;
|
daysInPhase: number;
|
||||||
networkContribution: Decimal; // 该阶段的全网算力
|
participatingContribution: Decimal; // 该阶段参与用户的总算力
|
||||||
participatingBatches: number[]; // 参与该阶段的批次号
|
participatingBatches: number[]; // 参与该阶段的批次号
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,9 +109,9 @@ interface MiningPhase {
|
||||||
*
|
*
|
||||||
* 核心逻辑(分阶段计算):
|
* 核心逻辑(分阶段计算):
|
||||||
* 1. 根据各批次的挖矿开始时间,划分挖矿阶段
|
* 1. 根据各批次的挖矿开始时间,划分挖矿阶段
|
||||||
* 2. 每个阶段有不同的全网算力(随着新批次加入而增加)
|
* 2. 每天产出的70%固定分给当前参与的用户
|
||||||
* 3. 用户算力 = 认种棵数 × 基础算力/棵 × 70%
|
* 3. 用户算力 = 认种棵数 × 基础算力/棵
|
||||||
* 4. 用户在每个阶段的收益 = (用户算力 / 该阶段全网算力) × 每秒分配量 × 阶段天数 × 86400
|
* 4. 用户在每个阶段的收益 = 每日产出 × 70% × 阶段天数 × (用户算力 / 当前参与总算力)
|
||||||
* 5. 用户总收益 = 用户参与的各阶段收益之和
|
* 5. 用户总收益 = 用户参与的各阶段收益之和
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
|
@ -196,18 +196,23 @@ export class BatchMiningService {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 定义挖矿阶段
|
// 定义挖矿阶段
|
||||||
// 阶段1: 批次1独挖3天
|
// 阶段1: 批次1独挖 preMineDays 天
|
||||||
// 阶段2: 批次1+2共挖2天
|
// 阶段2: 批次1+2共挖 preMineDays 天
|
||||||
// 阶段3: 批次1+2+3共挖1天
|
// ...依次类推
|
||||||
// 阶段4: 所有批次共挖(剩余天数)
|
// 最后阶段: 所有批次共挖(剩余天数)
|
||||||
const phases = this.buildMiningPhases(items, sortedBatches, batchContributions);
|
const phases = this.buildMiningPhases(items, sortedBatches, batchContributions);
|
||||||
this.logger.log(`[preview] 挖矿阶段: ${JSON.stringify(phases.map(p => ({
|
this.logger.log(`[preview] 挖矿阶段: ${JSON.stringify(phases.map(p => ({
|
||||||
phase: p.phaseNumber,
|
phase: p.phaseNumber,
|
||||||
days: p.daysInPhase,
|
days: p.daysInPhase,
|
||||||
batches: p.participatingBatches,
|
batches: p.participatingBatches,
|
||||||
networkContribution: p.networkContribution.toFixed(2)
|
participatingContribution: p.participatingContribution.toFixed(2)
|
||||||
})))}`);
|
})))}`);
|
||||||
|
|
||||||
|
// 每天补发额度 = 日产出 × 70%
|
||||||
|
const dailyDistribution = secondDistribution.times(SECONDS_PER_DAY);
|
||||||
|
const dailyAllocation = dailyDistribution.times(DAILY_DISTRIBUTION_RATIO);
|
||||||
|
this.logger.log(`[preview] 每日产出: ${dailyDistribution.toFixed(8)}, 每日补发额度(70%): ${dailyAllocation.toFixed(8)}`);
|
||||||
|
|
||||||
// 计算每个用户在各阶段的收益
|
// 计算每个用户在各阶段的收益
|
||||||
const userAmounts = new Map<string, Decimal>();
|
const userAmounts = new Map<string, Decimal>();
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
|
|
@ -215,15 +220,16 @@ export class BatchMiningService {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const phase of phases) {
|
for (const phase of phases) {
|
||||||
const dailyDistribution = secondDistribution.times(SECONDS_PER_DAY);
|
// 该阶段的总补发额 = 每日补发额度 × 阶段天数
|
||||||
const phaseDistribution = dailyDistribution.times(phase.daysInPhase);
|
const phaseAllocation = dailyAllocation.times(phase.daysInPhase);
|
||||||
|
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
// 检查该用户的批次是否参与此阶段
|
// 检查该用户的批次是否参与此阶段
|
||||||
if (phase.participatingBatches.includes(item.batch)) {
|
if (phase.participatingBatches.includes(item.batch)) {
|
||||||
const userContribution = userContributions.get(item.accountSequence)!;
|
const userContribution = userContributions.get(item.accountSequence)!;
|
||||||
const ratio = userContribution.dividedBy(phase.networkContribution);
|
// 用户收益 = 阶段补发额 × (用户算力 / 当前参与总算力)
|
||||||
const phaseAmount = phaseDistribution.times(ratio);
|
const ratio = userContribution.dividedBy(phase.participatingContribution);
|
||||||
|
const phaseAmount = phaseAllocation.times(ratio);
|
||||||
|
|
||||||
const currentAmount = userAmounts.get(item.accountSequence)!;
|
const currentAmount = userAmounts.get(item.accountSequence)!;
|
||||||
userAmounts.set(item.accountSequence, currentAmount.plus(phaseAmount));
|
userAmounts.set(item.accountSequence, currentAmount.plus(phaseAmount));
|
||||||
|
|
@ -235,14 +241,12 @@ export class BatchMiningService {
|
||||||
let grandTotalAmount = new Decimal(0);
|
let grandTotalAmount = new Decimal(0);
|
||||||
const batchResults: BatchMiningPreviewResult['batches'] = [];
|
const batchResults: BatchMiningPreviewResult['batches'] = [];
|
||||||
|
|
||||||
// 计算累计全网算力(最终状态)
|
// 计算用户总算力(用于显示)
|
||||||
// 用户只占全网的70%(30%是系统、运营、层级、团队),所以全网算力 = 用户算力 / 0.7
|
|
||||||
let totalUserContribution = new Decimal(0);
|
let totalUserContribution = new Decimal(0);
|
||||||
for (const contribution of batchContributions.values()) {
|
for (const contribution of batchContributions.values()) {
|
||||||
totalUserContribution = totalUserContribution.plus(contribution);
|
totalUserContribution = totalUserContribution.plus(contribution);
|
||||||
}
|
}
|
||||||
const finalNetworkContribution = totalUserContribution.dividedBy(USER_NETWORK_RATIO);
|
this.logger.log(`[preview] 用户总算力: ${totalUserContribution.toFixed(2)}`);
|
||||||
this.logger.log(`[preview] 用户总算力: ${totalUserContribution.toFixed(2)}, 全网算力(用户占70%): ${finalNetworkContribution.toFixed(2)}`);
|
|
||||||
|
|
||||||
for (const batchNum of sortedBatches) {
|
for (const batchNum of sortedBatches) {
|
||||||
const batchItems = batchGroups.get(batchNum)!;
|
const batchItems = batchGroups.get(batchNum)!;
|
||||||
|
|
@ -254,14 +258,15 @@ export class BatchMiningService {
|
||||||
for (const item of batchItems) {
|
for (const item of batchItems) {
|
||||||
const userContribution = userContributions.get(item.accountSequence)!;
|
const userContribution = userContributions.get(item.accountSequence)!;
|
||||||
const amount = userAmounts.get(item.accountSequence)!;
|
const amount = userAmounts.get(item.accountSequence)!;
|
||||||
const ratio = userContribution.dividedBy(finalNetworkContribution);
|
// 显示用:用户算力占总用户算力的比例
|
||||||
|
const ratio = userContribution.dividedBy(totalUserContribution);
|
||||||
|
|
||||||
users.push({
|
users.push({
|
||||||
accountSequence: item.accountSequence,
|
accountSequence: item.accountSequence,
|
||||||
treeCount: item.treeCount,
|
treeCount: item.treeCount,
|
||||||
preMineDays: item.preMineDays,
|
preMineDays: item.preMineDays,
|
||||||
userContribution: userContribution.toFixed(10),
|
userContribution: userContribution.toFixed(10),
|
||||||
networkContribution: finalNetworkContribution.toFixed(10),
|
networkContribution: totalUserContribution.toFixed(10), // 显示总用户算力
|
||||||
contributionRatio: ratio.toFixed(18),
|
contributionRatio: ratio.toFixed(18),
|
||||||
totalSeconds: (item.preMineDays * SECONDS_PER_DAY).toString(),
|
totalSeconds: (item.preMineDays * SECONDS_PER_DAY).toString(),
|
||||||
estimatedAmount: amount.toFixed(8),
|
estimatedAmount: amount.toFixed(8),
|
||||||
|
|
@ -367,25 +372,22 @@ export class BatchMiningService {
|
||||||
const phaseDays = currentPreMineDays;
|
const phaseDays = currentPreMineDays;
|
||||||
|
|
||||||
if (phaseDays > 0) {
|
if (phaseDays > 0) {
|
||||||
// 计算该阶段参与用户的算力
|
// 计算该阶段参与用户的总算力
|
||||||
let participatingContribution = new Decimal(0);
|
let participatingContribution = new Decimal(0);
|
||||||
for (const batch of participatingBatches) {
|
for (const batch of participatingBatches) {
|
||||||
participatingContribution = participatingContribution.plus(batchContributions.get(batch) || 0);
|
participatingContribution = participatingContribution.plus(batchContributions.get(batch) || 0);
|
||||||
}
|
}
|
||||||
// 实际全网算力 = 参与用户算力 / 用户占比
|
|
||||||
// 因为用户只占全网的70%(30%是系统、运营、层级、团队),所以全网算力 = 用户算力 / 0.7
|
|
||||||
const networkContribution = participatingContribution.dividedBy(USER_NETWORK_RATIO);
|
|
||||||
|
|
||||||
phases.push({
|
phases.push({
|
||||||
phaseNumber: currentPhase,
|
phaseNumber: currentPhase,
|
||||||
startDate: new Date(),
|
startDate: new Date(),
|
||||||
endDate: new Date(),
|
endDate: new Date(),
|
||||||
daysInPhase: phaseDays,
|
daysInPhase: phaseDays,
|
||||||
networkContribution,
|
participatingContribution,
|
||||||
participatingBatches: [...participatingBatches],
|
participatingBatches: [...participatingBatches],
|
||||||
});
|
});
|
||||||
|
|
||||||
this.logger.log(`[buildMiningPhases] 阶段${currentPhase}: ${phaseDays}天, 批次[${participatingBatches.join(',')}], 参与算力=${participatingContribution.toFixed(2)}, 全网算力=${networkContribution.toFixed(2)}`);
|
this.logger.log(`[buildMiningPhases] 阶段${currentPhase}: ${phaseDays}天, 批次[${participatingBatches.join(',')}], 参与算力=${participatingContribution.toFixed(2)}`);
|
||||||
currentPhase++;
|
currentPhase++;
|
||||||
usedDays += phaseDays;
|
usedDays += phaseDays;
|
||||||
}
|
}
|
||||||
|
|
@ -399,19 +401,17 @@ export class BatchMiningService {
|
||||||
for (const batch of sortedBatches) {
|
for (const batch of sortedBatches) {
|
||||||
participatingContribution = participatingContribution.plus(batchContributions.get(batch) || 0);
|
participatingContribution = participatingContribution.plus(batchContributions.get(batch) || 0);
|
||||||
}
|
}
|
||||||
// 实际全网算力 = 参与用户算力 / 用户占比
|
|
||||||
const networkContribution = participatingContribution.dividedBy(USER_NETWORK_RATIO);
|
|
||||||
|
|
||||||
phases.push({
|
phases.push({
|
||||||
phaseNumber: currentPhase,
|
phaseNumber: currentPhase,
|
||||||
startDate: new Date(),
|
startDate: new Date(),
|
||||||
endDate: new Date(),
|
endDate: new Date(),
|
||||||
daysInPhase: remainingDays,
|
daysInPhase: remainingDays,
|
||||||
networkContribution,
|
participatingContribution,
|
||||||
participatingBatches: [...sortedBatches],
|
participatingBatches: [...sortedBatches],
|
||||||
});
|
});
|
||||||
|
|
||||||
this.logger.log(`[buildMiningPhases] 阶段${currentPhase}(最终): ${remainingDays}天, 所有批次[${sortedBatches.join(',')}], 参与算力=${participatingContribution.toFixed(2)}, 全网算力=${networkContribution.toFixed(2)}`);
|
this.logger.log(`[buildMiningPhases] 阶段${currentPhase}(最终): ${remainingDays}天, 所有批次[${sortedBatches.join(',')}], 参与算力=${participatingContribution.toFixed(2)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return phases;
|
return phases;
|
||||||
|
|
@ -447,7 +447,57 @@ export class BatchMiningService {
|
||||||
const batchGroups = this.groupByBatch(items);
|
const batchGroups = this.groupByBatch(items);
|
||||||
const sortedBatches = Array.from(batchGroups.keys()).sort((a, b) => a - b);
|
const sortedBatches = Array.from(batchGroups.keys()).sort((a, b) => a - b);
|
||||||
|
|
||||||
let cumulativeContribution = new Decimal(0);
|
// 计算每个批次的算力
|
||||||
|
const batchContributions = new Map<number, Decimal>();
|
||||||
|
for (const batchNum of sortedBatches) {
|
||||||
|
const batchItems = batchGroups.get(batchNum)!;
|
||||||
|
let batchTotal = new Decimal(0);
|
||||||
|
for (const item of batchItems) {
|
||||||
|
batchTotal = batchTotal.plus(this.calculateUserContribution(item.treeCount));
|
||||||
|
}
|
||||||
|
batchContributions.set(batchNum, batchTotal);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算每个用户的算力
|
||||||
|
const userContributions = new Map<string, Decimal>();
|
||||||
|
for (const item of items) {
|
||||||
|
userContributions.set(item.accountSequence, this.calculateUserContribution(item.treeCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建挖矿阶段
|
||||||
|
const phases = this.buildMiningPhases(items, sortedBatches, batchContributions);
|
||||||
|
|
||||||
|
// 每天补发额度 = 日产出 × 70%
|
||||||
|
const dailyDistribution = secondDistribution.times(SECONDS_PER_DAY);
|
||||||
|
const dailyAllocation = dailyDistribution.times(DAILY_DISTRIBUTION_RATIO);
|
||||||
|
|
||||||
|
// 计算每个用户在各阶段的收益
|
||||||
|
const userAmounts = new Map<string, Decimal>();
|
||||||
|
for (const item of items) {
|
||||||
|
userAmounts.set(item.accountSequence, new Decimal(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const phase of phases) {
|
||||||
|
const phaseAllocation = dailyAllocation.times(phase.daysInPhase);
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
|
if (phase.participatingBatches.includes(item.batch)) {
|
||||||
|
const userContribution = userContributions.get(item.accountSequence)!;
|
||||||
|
const ratio = userContribution.dividedBy(phase.participatingContribution);
|
||||||
|
const phaseAmount = phaseAllocation.times(ratio);
|
||||||
|
|
||||||
|
const currentAmount = userAmounts.get(item.accountSequence)!;
|
||||||
|
userAmounts.set(item.accountSequence, currentAmount.plus(phaseAmount));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算总用户算力(用于记录)
|
||||||
|
let totalUserContribution = new Decimal(0);
|
||||||
|
for (const contribution of batchContributions.values()) {
|
||||||
|
totalUserContribution = totalUserContribution.plus(contribution);
|
||||||
|
}
|
||||||
|
|
||||||
const results: BatchMiningItemResult[] = [];
|
const results: BatchMiningItemResult[] = [];
|
||||||
let successCount = 0;
|
let successCount = 0;
|
||||||
let failedCount = 0;
|
let failedCount = 0;
|
||||||
|
|
@ -467,156 +517,141 @@ export class BatchMiningService {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 2. 按批次处理
|
// 2. 处理每个用户
|
||||||
for (const batchNum of sortedBatches) {
|
for (const item of items) {
|
||||||
const batchItems = batchGroups.get(batchNum)!;
|
try {
|
||||||
|
const userContribution = userContributions.get(item.accountSequence)!;
|
||||||
|
const amount = userAmounts.get(item.accountSequence)!;
|
||||||
|
const ratio = userContribution.dividedBy(totalUserContribution);
|
||||||
|
const totalSeconds = BigInt(item.preMineDays * SECONDS_PER_DAY);
|
||||||
|
const manualAmount = new ShareAmount(amount);
|
||||||
|
|
||||||
// 计算当前批次的总算力
|
// 查找或创建挖矿账户
|
||||||
let batchTotalContribution = new Decimal(0);
|
let account = await tx.miningAccount.findUnique({
|
||||||
for (const item of batchItems) {
|
where: { accountSequence: item.accountSequence },
|
||||||
const userContribution = this.calculateUserContribution(item.treeCount);
|
});
|
||||||
batchTotalContribution = batchTotalContribution.plus(userContribution);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 当前批次的全网算力
|
if (!account) {
|
||||||
cumulativeContribution = cumulativeContribution.plus(batchTotalContribution);
|
// 创建新账户
|
||||||
|
account = await tx.miningAccount.create({
|
||||||
// 处理当前批次的每个用户
|
|
||||||
for (const item of batchItems) {
|
|
||||||
try {
|
|
||||||
const userContribution = this.calculateUserContribution(item.treeCount);
|
|
||||||
const ratio = userContribution.dividedBy(cumulativeContribution);
|
|
||||||
const totalSeconds = BigInt(item.preMineDays * SECONDS_PER_DAY);
|
|
||||||
const amount = secondDistribution.times(totalSeconds.toString()).times(ratio);
|
|
||||||
const manualAmount = new ShareAmount(amount);
|
|
||||||
|
|
||||||
// 查找或创建挖矿账户
|
|
||||||
let account = await tx.miningAccount.findUnique({
|
|
||||||
where: { accountSequence: item.accountSequence },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!account) {
|
|
||||||
// 创建新账户
|
|
||||||
account = await tx.miningAccount.create({
|
|
||||||
data: {
|
|
||||||
accountSequence: item.accountSequence,
|
|
||||||
totalMined: new Decimal(0),
|
|
||||||
availableBalance: new Decimal(0),
|
|
||||||
frozenBalance: new Decimal(0),
|
|
||||||
totalContribution: userContribution, // 设置初始算力
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const balanceBefore = new Decimal(account.availableBalance);
|
|
||||||
const balanceAfter = balanceBefore.plus(manualAmount.value);
|
|
||||||
const totalMinedAfter = new Decimal(account.totalMined).plus(manualAmount.value);
|
|
||||||
|
|
||||||
// 更新账户余额
|
|
||||||
await tx.miningAccount.update({
|
|
||||||
where: { accountSequence: item.accountSequence },
|
|
||||||
data: {
|
|
||||||
totalMined: totalMinedAfter,
|
|
||||||
availableBalance: balanceAfter,
|
|
||||||
totalContribution: userContribution, // 同时更新算力
|
|
||||||
updatedAt: now,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// 创建明细记录
|
|
||||||
const description = `批量补发挖矿收益 - 批次:${batchNum} - 认种棵数:${item.treeCount} - 提前挖${item.preMineDays}天 - 操作人:${operatorName} - ${reason}`;
|
|
||||||
|
|
||||||
await tx.miningTransaction.create({
|
|
||||||
data: {
|
data: {
|
||||||
accountSequence: item.accountSequence,
|
accountSequence: item.accountSequence,
|
||||||
type: 'BATCH_MINING',
|
totalMined: new Decimal(0),
|
||||||
amount: manualAmount.value,
|
availableBalance: new Decimal(0),
|
||||||
balanceBefore,
|
frozenBalance: new Decimal(0),
|
||||||
balanceAfter,
|
totalContribution: userContribution, // 设置初始算力
|
||||||
referenceId: execution.id,
|
|
||||||
referenceType: 'BATCH_MINING',
|
|
||||||
memo: description,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 创建批量补发明细记录
|
const balanceBefore = new Decimal(account.availableBalance);
|
||||||
await tx.batchMiningRecord.create({
|
const balanceAfter = balanceBefore.plus(manualAmount.value);
|
||||||
data: {
|
const totalMinedAfter = new Decimal(account.totalMined).plus(manualAmount.value);
|
||||||
|
|
||||||
|
// 更新账户余额
|
||||||
|
await tx.miningAccount.update({
|
||||||
|
where: { accountSequence: item.accountSequence },
|
||||||
|
data: {
|
||||||
|
totalMined: totalMinedAfter,
|
||||||
|
availableBalance: balanceAfter,
|
||||||
|
totalContribution: userContribution, // 同时更新算力
|
||||||
|
updatedAt: now,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 创建明细记录
|
||||||
|
const description = `批量补发挖矿收益 - 批次:${item.batch} - 认种棵数:${item.treeCount} - 提前挖${item.preMineDays}天 - 操作人:${operatorName} - ${reason}`;
|
||||||
|
|
||||||
|
await tx.miningTransaction.create({
|
||||||
|
data: {
|
||||||
|
accountSequence: item.accountSequence,
|
||||||
|
type: 'BATCH_MINING',
|
||||||
|
amount: manualAmount.value,
|
||||||
|
balanceBefore,
|
||||||
|
balanceAfter,
|
||||||
|
referenceId: execution.id,
|
||||||
|
referenceType: 'BATCH_MINING',
|
||||||
|
memo: description,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 创建批量补发明细记录
|
||||||
|
await tx.batchMiningRecord.create({
|
||||||
|
data: {
|
||||||
|
executionId: execution.id,
|
||||||
|
accountSequence: item.accountSequence,
|
||||||
|
batch: item.batch,
|
||||||
|
treeCount: item.treeCount,
|
||||||
|
preMineDays: item.preMineDays,
|
||||||
|
userContribution,
|
||||||
|
networkContribution: totalUserContribution,
|
||||||
|
contributionRatio: ratio,
|
||||||
|
totalSeconds,
|
||||||
|
amount: manualAmount.value,
|
||||||
|
remark: item.remark,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 发布事件到 Kafka
|
||||||
|
await tx.outboxEvent.create({
|
||||||
|
data: {
|
||||||
|
aggregateType: 'BatchMining',
|
||||||
|
aggregateId: execution.id,
|
||||||
|
eventType: 'BATCH_MINING_COMPLETED',
|
||||||
|
topic: 'mining.batch-mining.completed',
|
||||||
|
key: item.accountSequence,
|
||||||
|
payload: {
|
||||||
|
eventId: `${execution.id}-${item.accountSequence}`,
|
||||||
executionId: execution.id,
|
executionId: execution.id,
|
||||||
accountSequence: item.accountSequence,
|
accountSequence: item.accountSequence,
|
||||||
batch: batchNum,
|
batch: item.batch,
|
||||||
|
amount: manualAmount.value.toString(),
|
||||||
treeCount: item.treeCount,
|
treeCount: item.treeCount,
|
||||||
preMineDays: item.preMineDays,
|
preMineDays: item.preMineDays,
|
||||||
userContribution,
|
userContribution: userContribution.toString(),
|
||||||
networkContribution: cumulativeContribution,
|
networkContribution: totalUserContribution.toString(),
|
||||||
contributionRatio: ratio,
|
contributionRatio: ratio.toString(),
|
||||||
totalSeconds,
|
totalSeconds: totalSeconds.toString(),
|
||||||
amount: manualAmount.value,
|
operatorId,
|
||||||
remark: item.remark,
|
operatorName,
|
||||||
|
reason,
|
||||||
},
|
},
|
||||||
});
|
status: 'PENDING',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// 发布事件到 Kafka
|
results.push({
|
||||||
await tx.outboxEvent.create({
|
accountSequence: item.accountSequence,
|
||||||
data: {
|
batch: item.batch,
|
||||||
aggregateType: 'BatchMining',
|
treeCount: item.treeCount,
|
||||||
aggregateId: execution.id,
|
userContribution: userContribution.toFixed(10),
|
||||||
eventType: 'BATCH_MINING_COMPLETED',
|
networkContribution: totalUserContribution.toFixed(10),
|
||||||
topic: 'mining.batch-mining.completed',
|
contributionRatio: ratio.toFixed(18),
|
||||||
key: item.accountSequence,
|
preMineDays: item.preMineDays,
|
||||||
payload: {
|
totalSeconds: totalSeconds.toString(),
|
||||||
eventId: `${execution.id}-${item.accountSequence}`,
|
amount: manualAmount.value.toFixed(8),
|
||||||
executionId: execution.id,
|
success: true,
|
||||||
accountSequence: item.accountSequence,
|
});
|
||||||
batch: batchNum,
|
|
||||||
amount: manualAmount.value.toString(),
|
|
||||||
treeCount: item.treeCount,
|
|
||||||
preMineDays: item.preMineDays,
|
|
||||||
userContribution: userContribution.toString(),
|
|
||||||
networkContribution: cumulativeContribution.toString(),
|
|
||||||
contributionRatio: ratio.toString(),
|
|
||||||
totalSeconds: totalSeconds.toString(),
|
|
||||||
operatorId,
|
|
||||||
operatorName,
|
|
||||||
reason,
|
|
||||||
},
|
|
||||||
status: 'PENDING',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
results.push({
|
successCount++;
|
||||||
accountSequence: item.accountSequence,
|
totalAmount = totalAmount.plus(manualAmount.value);
|
||||||
batch: batchNum,
|
|
||||||
treeCount: item.treeCount,
|
|
||||||
userContribution: userContribution.toFixed(10),
|
|
||||||
networkContribution: cumulativeContribution.toFixed(10),
|
|
||||||
contributionRatio: ratio.toFixed(18),
|
|
||||||
preMineDays: item.preMineDays,
|
|
||||||
totalSeconds: totalSeconds.toString(),
|
|
||||||
amount: manualAmount.value.toFixed(8),
|
|
||||||
success: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
successCount++;
|
} catch (error: any) {
|
||||||
totalAmount = totalAmount.plus(manualAmount.value);
|
this.logger.error(`Failed to process ${item.accountSequence}: ${error.message}`);
|
||||||
|
results.push({
|
||||||
} catch (error: any) {
|
accountSequence: item.accountSequence,
|
||||||
this.logger.error(`Failed to process ${item.accountSequence}: ${error.message}`);
|
batch: item.batch,
|
||||||
results.push({
|
treeCount: item.treeCount,
|
||||||
accountSequence: item.accountSequence,
|
userContribution: '0',
|
||||||
batch: batchNum,
|
networkContribution: '0',
|
||||||
treeCount: item.treeCount,
|
contributionRatio: '0',
|
||||||
userContribution: '0',
|
preMineDays: item.preMineDays,
|
||||||
networkContribution: '0',
|
totalSeconds: '0',
|
||||||
contributionRatio: '0',
|
amount: '0',
|
||||||
preMineDays: item.preMineDays,
|
success: false,
|
||||||
totalSeconds: '0',
|
error: error.message,
|
||||||
amount: '0',
|
});
|
||||||
success: false,
|
failedCount++;
|
||||||
error: error.message,
|
|
||||||
});
|
|
||||||
failedCount++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue