feat: reward
This commit is contained in:
@@ -39,7 +39,7 @@ watcher.on('startMine', () => {
|
||||
mylog.info('挖矿程序执行完毕');
|
||||
});
|
||||
rl.on('message', function (msg) {
|
||||
mylog.info('MineInfo', msg)
|
||||
mylog.info('MineInfo', msg);
|
||||
});
|
||||
rl.on('exit', function () {
|
||||
mylog.info('挖矿程序执行完毕');
|
||||
|
||||
106
src/jobs/mine.js
106
src/jobs/mine.js
@@ -38,81 +38,71 @@ const Fund = require('../modules/fund/fund.model');
|
||||
const system = require('../modules/system/system.model');
|
||||
const { createAction } = require('../modules/action/action.handler');
|
||||
|
||||
const tokenReleaseRate = 0.02;
|
||||
const inviteReward = 2.5;
|
||||
const getProfitRate = base => {
|
||||
if (base > 0 && base <= 10000) {
|
||||
return 0.0002;
|
||||
} else if (base > 10000 && base <= 50000) {
|
||||
return 0.0005;
|
||||
} else if (base > 50000 && base <= 100000) {
|
||||
return 0.0008;
|
||||
} else if (base > 100000 && base <= 200000) {
|
||||
return 0.0010;
|
||||
} else if (base > 200000 && base <= 500000) {
|
||||
return 0.0015;
|
||||
} else if (base > 500000 && base <= 1000000) {
|
||||
return 0.0020;
|
||||
} else if (base > 1000000 && base <= 10000000) {
|
||||
return 0.0030;
|
||||
} else return 0;
|
||||
};
|
||||
|
||||
async function awardMine(user, fund) {
|
||||
if (!user || !fund || fund.fundList.length === 0) return 0;
|
||||
let sum = 0;
|
||||
for (let i = 0, len = fund.fundList.length; i < len; ++i) {
|
||||
const released = fund.releasedAmout || 0;
|
||||
if (released === fund.releasedAmout) {
|
||||
mylog.info('矿晶失效,开始标记');
|
||||
await Fund.findByIdAndUpdate(fund.id, {
|
||||
$set: {
|
||||
[`fundList.${i}.status`]: 2 //标记失效
|
||||
}
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
const profit = +fund.fundList[i].amount * tokenReleaseRate;
|
||||
await Fund.findByIdAndUpdate(fund.id, {
|
||||
$inc: {
|
||||
[`fundList.${i}.mineCount`]: 1,
|
||||
[`fundList.${i}.releasedAmout`]: profit,
|
||||
},
|
||||
});
|
||||
sum += profit;
|
||||
}
|
||||
return sum.toFixed(2);
|
||||
}
|
||||
function awardInvite(user, fund) {
|
||||
const follerNum = user.group.length || 0;
|
||||
const hasAwardFoller = fund.option && fund.option.usedGroupReward / 10 || 0; // 求增量: 总额 - 已领取总额(fundSum)
|
||||
const newFoller = follerNum - hasAwardFoller;
|
||||
if (newFoller < 0) return 0;
|
||||
// 挖矿奖励 = 充值金额奖励 + 社区奖励
|
||||
return (newFoller * inviteReward).toFixed(2);
|
||||
function awardMine(user, fund) {
|
||||
if (!user || !fund || fund.vicFundSum === 0) return 0;
|
||||
const base = +fund.vicFundSum;
|
||||
const rate = getProfitRate(base);
|
||||
return base * rate;
|
||||
}
|
||||
|
||||
// fund.option.usedGroupReward : 已领取的社群奖励总额
|
||||
const doReward = async (user, fund) => {
|
||||
// 1.对于充值的fundList的每一项,按照2%进行发放,累加到asset.vic,添加action,类型为1
|
||||
// 2.对于社团成员进行人头数目,按照10vic/人进行奖励,累加到asset.vic,添加action,类型为2
|
||||
if (!user || !fund) return 0;
|
||||
const rewardMine = await awardMine(user, fund);
|
||||
// const rewardInvite = awardInvite(user, fund);
|
||||
const rewardInvite = 0;
|
||||
const reward = +rewardMine + rewardInvite;
|
||||
const rewardMine = awardMine(user, fund);
|
||||
if (rewardMine === 0) return 0;
|
||||
const rewardInviter = +user.vicFundSum > 10000 ? rewardMine * 0.04 : 0;
|
||||
mylog.info('挖矿奖励: ', rewardMine);
|
||||
mylog.info('社群奖励: ', rewardInvite);
|
||||
reward && await Fund.findByIdAndUpdate(fund.id, {
|
||||
rewardMine && await Fund.findByIdAndUpdate(fund.id, {
|
||||
$inc: {
|
||||
'asset.vic': reward,
|
||||
'asset.usdt': rewardInvite, // 用来记录所有社群奖励总额
|
||||
vicFundSum: rewardMine,
|
||||
},
|
||||
$set: {
|
||||
'option.newFoller': rewardInvite / 5,
|
||||
'option.usedGroupReward': rewardInvite, // 本次的奖励值累加到已领取团队奖励总和内
|
||||
'lastMine': new Date().toISOString()
|
||||
lastMine: new Date().toISOString()
|
||||
}
|
||||
}).then(() => {
|
||||
rewardMine > 0 && createAction(1, {
|
||||
userId: user.id,
|
||||
tokenType: 'vic',
|
||||
tokenType: 'vic2vic', // 新模式标记
|
||||
amount: rewardMine,
|
||||
remain: fund.asset
|
||||
}).save();
|
||||
rewardInvite > 0 && createAction(2, {
|
||||
userId: user.id,
|
||||
tokenType: 'vic',
|
||||
amount: rewardInvite,
|
||||
if (rewardInviter > 0) {
|
||||
User.findByIdAndUpdate(user.inviter, {
|
||||
$inc: {
|
||||
vicFundSum: rewardInviter
|
||||
}
|
||||
}).then(() => {
|
||||
createAction(2, {
|
||||
userId: user.inviter,
|
||||
tokenType: 'vic2vic', // 新模式标记
|
||||
amount: rewardInviter,
|
||||
remain: fund.asset
|
||||
}).save();
|
||||
}).catch(() => null);
|
||||
}
|
||||
});
|
||||
};
|
||||
const mock = {
|
||||
touch: () => {mylog.info('-----------------\n');},
|
||||
done: () => {mylog.info('done');},
|
||||
touch: () => { mylog.info('-----------------\n'); },
|
||||
done: () => { mylog.info('done'); },
|
||||
};
|
||||
|
||||
async function mine (job = mock, done = mock) {
|
||||
@@ -142,10 +132,10 @@ async function mine (job = mock, done = mock) {
|
||||
if (!userFundList || !Array.isArray(userFundList)) return 0;
|
||||
for (let i = 0, len = userFundList.length; i < len; ++i) {
|
||||
const fund = userFundList[i]; // 一条数据库fund表记录
|
||||
// if (fund.lastMine && new Date(fund.lastMine).getDate() === new Date().getDate()) {
|
||||
// mylog.info('已经计算过...跳过');
|
||||
// continue;
|
||||
// }
|
||||
if (fund.lastMine && new Date(fund.lastMine).getDate() === new Date().getDate()) {
|
||||
mylog.info('已经计算过...跳过');
|
||||
continue;
|
||||
}
|
||||
const user = await User.findById(fund.userId).exec();
|
||||
mylog.info('No. ', currentIndex, ' - ', i);
|
||||
mylog.info('开始更新用户: ', user.id);
|
||||
|
||||
@@ -11,12 +11,11 @@ const { calRevenueLastday, getActiveFund } = require('./fund.handler');
|
||||
const { getDate } = require('../../utils/date');
|
||||
const Crypto = require('../../utils/crypto');
|
||||
const actionFilter = 'id type amount detail op createdAt tokenType';
|
||||
const { USDT2VIC_RATE } = require('./constant');
|
||||
|
||||
const depositCoinsList = [{
|
||||
id: 'usdtETH',
|
||||
label: 'usdt',
|
||||
rate: USDT2VIC_RATE
|
||||
label: 'vic',
|
||||
rate: 1
|
||||
}];
|
||||
const withdrawCoinsList = [{
|
||||
id: 'vic',
|
||||
@@ -37,7 +36,7 @@ module.exports = {
|
||||
return res.json({
|
||||
code: 0,
|
||||
msg: 'success',
|
||||
data: fund && fund.asset
|
||||
data: { vic: fund.vicFundSum, usdt: 0 }
|
||||
});
|
||||
}).catch(err => {
|
||||
mylog.error("[getFundDetail]", err);
|
||||
@@ -123,9 +122,9 @@ module.exports = {
|
||||
});
|
||||
const [user, fund] = await Promise.all([User.findById(userId), Fund.findOne({ userId })]);
|
||||
if (
|
||||
(coinId === 'vic' && +amount < 30)
|
||||
+amount < 1000
|
||||
||
|
||||
+fund.fundSum < 500
|
||||
+fund.vicFundSum < 1000
|
||||
||
|
||||
+user.verifyLevel < 1
|
||||
) {
|
||||
@@ -135,6 +134,12 @@ module.exports = {
|
||||
error: '不满足提现条件',
|
||||
});
|
||||
}
|
||||
const cost = +amount * 1.005;
|
||||
if (fund.asset && +fund.asset[coinId] < cost) return res.json({
|
||||
code: 2,
|
||||
msg: '资金不足',
|
||||
error: 'insufficient fund'
|
||||
});
|
||||
let hashpwd = password;
|
||||
if (hashpwd.length < 30) {
|
||||
hashpwd = Crypto.hash(password, {hasher: 'md5'});
|
||||
@@ -144,16 +149,10 @@ module.exports = {
|
||||
msg: '资金密码错误',
|
||||
error: '资金密码错误',
|
||||
});
|
||||
const cost = +amount * 1.005;
|
||||
if (fund.asset && +fund.asset[coinId] < cost) return res.json({
|
||||
code: 2,
|
||||
msg: '资金不足',
|
||||
error: 'insufficient fund'
|
||||
});
|
||||
const action = createAction(3, { userId, amount, remain: fund.asset, op: 0, detail: { targetAddress, coinId } });
|
||||
const ticket = createTicket('withdraw', { userId, amount: +amount, action, targetAddress, coinId });
|
||||
try {
|
||||
await fund.decrease(coinId, cost);
|
||||
await fund.decFund(cost);
|
||||
} catch (error) {
|
||||
mylog.error('[Fund提现] ', error);
|
||||
action.detail = { error };
|
||||
@@ -217,12 +216,6 @@ module.exports = {
|
||||
};
|
||||
}),
|
||||
async getWithdrawCoinsList (req, res) {
|
||||
// const { userId } = res.locals.user;
|
||||
// const userFund = await Fund.findOne({userId}).exec();
|
||||
// const asset = userFund.asset;
|
||||
// const list = [];
|
||||
// (asset['vic'] >= 1000) && list.push(withdrawCoinsList[0]);
|
||||
// (asset['usdt'] > 0 && (!userFund.lastWithdraw.usdt || (new Date() - new Date(userFund.lastWithdraw.usdt)) / (1000 * 3600 * 24 * 7) >= 1)) && list.push(withdrawCoinsList[1]);
|
||||
return res.json({
|
||||
code: 0,
|
||||
data: withdrawCoinsList
|
||||
@@ -249,7 +242,8 @@ module.exports = {
|
||||
// 计算昨日收益
|
||||
let revenueLastday = calRevenueLastday(actions);
|
||||
// 筛选有效矿晶
|
||||
let activeFund = getActiveFund(fund.fundList);
|
||||
// let activeFund = getActiveFund(fund.fundList);
|
||||
let activeFund = fund.fundList;
|
||||
let revenueAll = Array.isArray(allAction) && allAction.reduce((pre, cur) => pre + (+cur.amount || 0), 0) || 0;
|
||||
revenueAll = revenueAll.toFixed(4);
|
||||
return res.json({
|
||||
@@ -272,7 +266,8 @@ module.exports = {
|
||||
// 计算昨日收益
|
||||
let revenueLastday = calRevenueLastday(actions);
|
||||
// 筛选有效矿晶
|
||||
let activeFund = getActiveFund(fund.fundList);
|
||||
// let activeFund = getActiveFund(fund.fundList);
|
||||
let activeFund = fund.fundList;
|
||||
if (!newFund || !newFund.fundList) newFund = fund;
|
||||
let revenueAll = Array.isArray(allAction) && allAction.reduce((pre, cur) => pre + (+cur.amount || 0), 0) || 0;
|
||||
revenueAll = revenueAll.toFixed(4);
|
||||
@@ -291,7 +286,7 @@ module.exports = {
|
||||
},
|
||||
async getFundList (req, res) {
|
||||
const { userId } = res.locals.user;
|
||||
return Fund.findOne({userId}, 'fundList').then(fund => {
|
||||
return Fund.findOne({ userId }, 'fundList').then(fund => {
|
||||
return res.json({
|
||||
code: 0,
|
||||
data: fund.fundList
|
||||
@@ -310,7 +305,8 @@ module.exports = {
|
||||
const [ start, end ] = getDate(1);
|
||||
let now = new Date();
|
||||
// 筛选有效矿晶
|
||||
let activeFund = getActiveFund(fund.fundList);
|
||||
// let activeFund = getActiveFund(fund.fundList);
|
||||
let activeFund = fund.fundList;
|
||||
const actions = await Action.find({ userId, type: 1, createdAt: { $gt: start, $lt: now } }).exec();
|
||||
const allAction = await Action.find({ userId, type: 1 }).exec();
|
||||
// 计算昨日收益
|
||||
|
||||
@@ -33,6 +33,7 @@ const FundSchema = new mongoose.Schema({
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
// vic兑换的基金
|
||||
vicFundSum: {
|
||||
type: Number,
|
||||
default: 0
|
||||
@@ -48,6 +49,10 @@ const FundSchema = new mongoose.Schema({
|
||||
}
|
||||
},
|
||||
// 团队总充值资产
|
||||
groupVicFundSum: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
groupFundSum: {
|
||||
type: Number,
|
||||
default: 0
|
||||
@@ -93,20 +98,17 @@ FundModel.prototype.hasNewDeposit = async function () {
|
||||
}
|
||||
return { hasNew: false };
|
||||
};
|
||||
|
||||
/**
|
||||
[addFund] : 向用户添加矿晶,在用户充值USDT时调用!!!!
|
||||
、 */
|
||||
const DEFAULT_RATE = 1;
|
||||
FundModel.prototype.addFund = async function (txlist = [], option) {
|
||||
let newSum = 0;
|
||||
const VIC_RATE = (await System.findOne({ key: 'VIC_RATE' }).exec().catch(() => {
|
||||
mylog.error('没有获取到vic兑换比例');
|
||||
return 1;
|
||||
})) || 1;
|
||||
return DEFAULT_RATE;
|
||||
})) || DEFAULT_RATE;
|
||||
const actionPromiseList = [];
|
||||
const newFundList = txlist.map(txObj => {
|
||||
txObj.rawAmount = txObj.amount; // tx.amout是区块链交易的数值,已经除了精度
|
||||
const depositAmount = +txObj.amount * VIC_RATE;
|
||||
const depositAmount = +txObj.amount * (Number.isSafeInteger(VIC_RATE) ? VIC_RATE : DEFAULT_RATE);
|
||||
newSum += depositAmount;
|
||||
const action = createAction(0, {
|
||||
userId: this.userId,
|
||||
@@ -116,6 +118,7 @@ FundModel.prototype.addFund = async function (txlist = [], option) {
|
||||
});
|
||||
typeof action.save === 'function' && actionPromiseList.push(action.save());
|
||||
txObj.amount = depositAmount; // 之后返回fundList里的数值需要把区块链的数值乘以比率 !!!!
|
||||
txObj.type = 'vic2fund';
|
||||
return createNewFund({...txObj});
|
||||
});
|
||||
// 1.注入资金
|
||||
@@ -129,8 +132,7 @@ FundModel.prototype.addFund = async function (txlist = [], option) {
|
||||
$set: {
|
||||
lastDeposit: new Date().toISOString()
|
||||
}
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
}, { ...option, returnOriginal: false }).exec().catch(err => null);
|
||||
}, { ...option, returnOriginal: false }).exec().catch(err => mylog.error(err.errmsg));
|
||||
|
||||
// 2.记录action
|
||||
Promise.all(actionPromiseList).catch(err => {
|
||||
@@ -139,41 +141,12 @@ FundModel.prototype.addFund = async function (txlist = [], option) {
|
||||
// 3.增加上家团队总额
|
||||
option.inviter && FundModel.findOneAndUpdate({ userId: option.inviter }, {
|
||||
$inc: {
|
||||
groupFundSum: newSum
|
||||
groupVicFundSum: newSum
|
||||
}
|
||||
}).exec();
|
||||
// 3.对于自己的邀请者进行奖励,按照自己充值金额的十分之一,累加到邀请人的fundList里,类型为1
|
||||
const myId = this.userId;
|
||||
User.findById(myId).then(async user => {
|
||||
if (!user && !user.inviter) return 0;
|
||||
const award = +newSum * 0.1;
|
||||
const inviteFund = createNewFund({
|
||||
type: 'inviteAward',
|
||||
amount: award,
|
||||
blockNumber: 'followerReward',
|
||||
hash: myId
|
||||
});
|
||||
User.findByIdAndUpdate(user.inviter, {
|
||||
$push: {
|
||||
vicFundSum: inviteFund
|
||||
}
|
||||
});
|
||||
createAction(4, {
|
||||
userId: user.inviter,
|
||||
amount: award, // 充值记录的数值仍然是区块链的数值
|
||||
tokenType: 'vic', // 目前设定只能挖出矿晶vic
|
||||
remain: this.asset,
|
||||
detail: {
|
||||
desc: `${user.id}购买${newSum} 奖励其推荐人${user.inviter}: ${award}矿晶`,
|
||||
from: myId,
|
||||
to: user.inviter
|
||||
}
|
||||
}).save();
|
||||
}).catch(err => {
|
||||
mylog.error(`${myId}充值奖励其推荐人时出错 `, JSON.stringify(err));
|
||||
});
|
||||
return res;
|
||||
};
|
||||
|
||||
FundModel.prototype.increase = async function (assetName, amount, option = {}) {
|
||||
if (!assetName || !amount || amount <= 0 || !Number.isFinite(amount) || !ASSETTYPES.includes(assetName)) return null;
|
||||
const asset = 'asset.' + assetName;
|
||||
@@ -187,6 +160,7 @@ FundModel.prototype.increase = async function (assetName, amount, option = {}) {
|
||||
if (res.asset[assetName] < 0) throw new Error('Insufficient funds');
|
||||
return res;
|
||||
};
|
||||
|
||||
FundModel.prototype.decrease = async function (assetName, amount, option) {
|
||||
// 传入的amount应该是大于0的正数
|
||||
if (!assetName || !amount || amount <= 0 || !Number.isFinite(amount) || !ASSETTYPES.includes(assetName)) return null;
|
||||
@@ -203,4 +177,30 @@ FundModel.prototype.decrease = async function (assetName, amount, option) {
|
||||
return res;
|
||||
};
|
||||
|
||||
FundModel.prototype.incFund = async function (amount, option = {}) {
|
||||
if (!amount || amount <= 0 || !Number.isFinite(amount)) return null;
|
||||
const asset = 'vicFundSum';
|
||||
const res = await FundModel.findByIdAndUpdate(this.id, {
|
||||
$inc: {
|
||||
[asset]: amount
|
||||
}
|
||||
}, { ...option, returnOriginal: false }).exec().catch(err => mylog.error(err));
|
||||
if (!res || !res.asset) throw new Error('用户资产修改[increase]失败!');
|
||||
return res;
|
||||
};
|
||||
|
||||
FundModel.prototype.decFund = async function (amount, option) {
|
||||
// 传入的amount应该是大于0的正数
|
||||
if (!amount || amount <= 0 || !Number.isFinite(amount)) return null;
|
||||
amount = 0 - amount;
|
||||
const asset = 'vicFundSum';
|
||||
const res = await FundModel.findByIdAndUpdate(this.id, {
|
||||
$inc: {
|
||||
[asset]: amount
|
||||
}
|
||||
}, { ...option, returnOriginal: false }).exec().catch(err => mylog.error(err));
|
||||
if (!res || !res.asset) throw new Error('用户资产修改[decrease]失败!');
|
||||
return res;
|
||||
};
|
||||
|
||||
module.exports = FundModel;
|
||||
Reference in New Issue
Block a user