diff --git a/src/jobs/jobs.js b/src/jobs/jobs.js index 08cd5c1..5341a28 100644 --- a/src/jobs/jobs.js +++ b/src/jobs/jobs.js @@ -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('挖矿程序执行完毕'); diff --git a/src/jobs/mine.js b/src/jobs/mine.js index 1a0a4c5..6321ccf 100644 --- a/src/jobs/mine.js +++ b/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, - remain: fund.asset - }).save(); + 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); diff --git a/src/modules/fund/fund.controller.js b/src/modules/fund/fund.controller.js index 9b580fa..34727de 100644 --- a/src/modules/fund/fund.controller.js +++ b/src/modules/fund/fund.controller.js @@ -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(); // 计算昨日收益 diff --git a/src/modules/fund/fund.model.js b/src/modules/fund/fund.model.js index 934528d..f9d2cd0 100644 --- a/src/modules/fund/fund.model.js +++ b/src/modules/fund/fund.model.js @@ -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; \ No newline at end of file