192 lines
6.2 KiB
TypeScript
192 lines
6.2 KiB
TypeScript
import { PrismaClient } from '@prisma/client';
|
||
import Decimal from 'decimal.js';
|
||
|
||
const prisma = new PrismaClient();
|
||
|
||
/**
|
||
* Mining Service 数据库初始化
|
||
*
|
||
* 根据需求文档:
|
||
* - 积分股共 100.02 亿
|
||
* - 其中 100 亿通过 4 年时间销毁至 0 (实际是10年,每年销毁10亿)
|
||
* - 其中 200 万原始积分股作为全网贡献值分配
|
||
* - 第一个两年分配 100 万积分股给全网
|
||
* - 第二个两年分配 50 万积分股给全网
|
||
* - 以此类推(减半机制)
|
||
*/
|
||
async function main() {
|
||
console.log('Starting mining-service seed...');
|
||
|
||
// ============================================================
|
||
// 1. 初始化挖矿配置 (MiningConfig)
|
||
// ============================================================
|
||
const existingConfig = await prisma.miningConfig.findFirst();
|
||
|
||
if (!existingConfig) {
|
||
// 总积分股: 100.02B (100,020,000,000)
|
||
const totalShares = new Decimal('100020000000');
|
||
|
||
// 分配池: 200M (200,000,000) - 用于挖矿分配
|
||
// 注意:需求说200万,但这里使用200万作为分配池
|
||
const distributionPool = new Decimal('2000000'); // 200万
|
||
|
||
// 第一纪元分配量: 100万 (第一个两年)
|
||
const era1Distribution = new Decimal('1000000');
|
||
|
||
// 每分钟分配量 = 100万 / (2年 * 365天 * 24小时 * 60分钟)
|
||
// = 1,000,000 / 1,051,200 = 0.95129375951...
|
||
const minutesIn2Years = 2 * 365 * 24 * 60; // 1,051,200 分钟
|
||
const minuteDistribution = era1Distribution.dividedBy(minutesIn2Years);
|
||
|
||
await prisma.miningConfig.create({
|
||
data: {
|
||
totalShares: totalShares,
|
||
distributionPool: distributionPool,
|
||
remainingDistribution: era1Distribution, // 第一纪元剩余分配量
|
||
halvingPeriodYears: 2,
|
||
currentEra: 1,
|
||
eraStartDate: new Date(), // 从现在开始
|
||
minuteDistribution: minuteDistribution,
|
||
isActive: false, // 需要手动激活
|
||
activatedAt: null,
|
||
},
|
||
});
|
||
|
||
console.log('✅ MiningConfig created:');
|
||
console.log(` - Total Shares: ${totalShares.toFixed(0)}`);
|
||
console.log(` - Distribution Pool: ${distributionPool.toFixed(0)}`);
|
||
console.log(` - Era 1 Distribution: ${era1Distribution.toFixed(0)}`);
|
||
console.log(` - Minute Distribution: ${minuteDistribution.toFixed(18)}`);
|
||
} else {
|
||
console.log('⏭️ MiningConfig already exists, skipping...');
|
||
}
|
||
|
||
// ============================================================
|
||
// 2. 初始化黑洞账户 (BlackHole)
|
||
// ============================================================
|
||
const existingBlackHole = await prisma.blackHole.findFirst();
|
||
|
||
if (!existingBlackHole) {
|
||
// 目标销毁量: 100亿 (100,000,000,000)
|
||
// 注意:需求说100亿通过4年销毁,但实际设计是10年
|
||
const targetBurn = new Decimal('10000000000'); // 100亿
|
||
|
||
await prisma.blackHole.create({
|
||
data: {
|
||
totalBurned: 0,
|
||
targetBurn: targetBurn,
|
||
remainingBurn: targetBurn,
|
||
lastBurnMinute: null,
|
||
},
|
||
});
|
||
|
||
console.log('✅ BlackHole created:');
|
||
console.log(` - Target Burn: ${targetBurn.toFixed(0)}`);
|
||
} else {
|
||
console.log('⏭️ BlackHole already exists, skipping...');
|
||
}
|
||
|
||
// ============================================================
|
||
// 3. 初始化第一纪元记录 (MiningEra)
|
||
// ============================================================
|
||
const existingEra = await prisma.miningEra.findUnique({
|
||
where: { eraNumber: 1 },
|
||
});
|
||
|
||
if (!existingEra) {
|
||
const era1Distribution = new Decimal('1000000');
|
||
const minutesIn2Years = 2 * 365 * 24 * 60;
|
||
const minuteDistribution = era1Distribution.dividedBy(minutesIn2Years);
|
||
|
||
await prisma.miningEra.create({
|
||
data: {
|
||
eraNumber: 1,
|
||
startDate: new Date(),
|
||
endDate: null,
|
||
initialDistribution: era1Distribution,
|
||
totalDistributed: 0,
|
||
minuteDistribution: minuteDistribution,
|
||
isActive: true,
|
||
},
|
||
});
|
||
|
||
console.log('✅ MiningEra 1 created');
|
||
} else {
|
||
console.log('⏭️ MiningEra 1 already exists, skipping...');
|
||
}
|
||
|
||
// ============================================================
|
||
// 4. 初始化池账户 (PoolAccount)
|
||
// ============================================================
|
||
const poolTypes = [
|
||
{
|
||
poolType: 'SHARE_POOL',
|
||
name: '积分股池',
|
||
balance: new Decimal('100020000000'), // 100.02B 初始
|
||
description: '总积分股池,认种产生的绿积分注入此池',
|
||
},
|
||
{
|
||
poolType: 'BLACK_HOLE_POOL',
|
||
name: '黑洞积分股池',
|
||
balance: new Decimal('0'),
|
||
description: '销毁池,积分股销毁后进入此池',
|
||
},
|
||
{
|
||
poolType: 'CIRCULATION_POOL',
|
||
name: '流通积分股池',
|
||
balance: new Decimal('0'),
|
||
description: '流通池,用户卖出的积分股进入此池',
|
||
},
|
||
];
|
||
|
||
for (const pool of poolTypes) {
|
||
const existing = await prisma.poolAccount.findUnique({
|
||
where: { poolType: pool.poolType as any },
|
||
});
|
||
|
||
if (!existing) {
|
||
await prisma.poolAccount.create({
|
||
data: {
|
||
poolType: pool.poolType as any,
|
||
name: pool.name,
|
||
balance: pool.balance,
|
||
totalInflow: pool.balance,
|
||
totalOutflow: 0,
|
||
isActive: true,
|
||
description: pool.description,
|
||
},
|
||
});
|
||
console.log(`✅ PoolAccount ${pool.poolType} created`);
|
||
} else {
|
||
console.log(`⏭️ PoolAccount ${pool.poolType} already exists, skipping...`);
|
||
}
|
||
}
|
||
|
||
console.log('\n🎉 Mining-service seed completed!');
|
||
|
||
// 输出当前状态
|
||
console.log('\n📊 Current Status:');
|
||
const config = await prisma.miningConfig.findFirst();
|
||
const blackHole = await prisma.blackHole.findFirst();
|
||
const pools = await prisma.poolAccount.findMany();
|
||
|
||
if (config) {
|
||
console.log(` Mining Active: ${config.isActive}`);
|
||
console.log(` Remaining Distribution: ${config.remainingDistribution}`);
|
||
}
|
||
if (blackHole) {
|
||
console.log(` Total Burned: ${blackHole.totalBurned}`);
|
||
console.log(` Remaining Burn: ${blackHole.remainingBurn}`);
|
||
}
|
||
console.log(` Pool Accounts: ${pools.length}`);
|
||
}
|
||
|
||
main()
|
||
.catch((e) => {
|
||
console.error('❌ Seed failed:', e);
|
||
process.exit(1);
|
||
})
|
||
.finally(async () => {
|
||
await prisma.$disconnect();
|
||
});
|