feat: 充值查询+刷新

This commit is contained in:
chaosBreaking
2019-09-08 17:24:36 +08:00
parent 8edcc85903
commit 383e24fbfa
9 changed files with 173 additions and 40 deletions

View File

@@ -1,5 +1,6 @@
'use strict'; 'use strict';
module.exports = { module.exports = {
USDTAddr: '0xdac17f958d2ee523a2206206994597c13d831ec7' USDTAddr: '0xdac17f958d2ee523a2206206994597c13d831ec7',
startBlock: 6327420
}; };

34
src/common/deposit.js Normal file
View File

@@ -0,0 +1,34 @@
'use strict';
const { ERC20 } = require('../utils/erc20');
const { USDTAddr, startBlock } = require('./constant');
const getUSDTTxList = async address => {
if (!address) return null;
const res = await ERC20.getActions(address, USDTAddr, startBlock).catch(err => {
if (err) return [];
});
return res;
};
const parseUsdtTx = txList => {
if (!txList || !Array.isArray(txList)) return [];
return txList.map(tx => {
return {
amount: +tx.value,
hash: tx.hash,
blockNumber: tx.blockNumber
};
});
};
const getNewDepositTx = (usdtTx = [], fundList = []) => {
if (fundList.length > usdtTx.length) return null;
// fundList的顺序应该与usdtTx的顺序一致所以只要截取新的
const newUsdtTxList = usdtTx.slice(fundList.length);
return parseUsdtTx(newUsdtTxList);
};
module.exports = {
getUSDTTxList,
getNewDepositTx
};

View File

@@ -10,6 +10,8 @@ const actionFilter = 'id type amount detail op createdAt';
const { inject } = require('../../common/Provider'); const { inject } = require('../../common/Provider');
const ETH = require('../../utils/erc20').ERC20; const ETH = require('../../utils/erc20').ERC20;
const { USDTAddr } = require('../../common/constant'); const { USDTAddr } = require('../../common/constant');
const { calRevenueLastday, getActiveFund } = require('./fund.handler');
const { getDate } = require('../../utils/date');
const depositCoinsList = [{ const depositCoinsList = [{
id: 'usdtBTC', id: 'usdtBTC',
@@ -191,14 +193,40 @@ module.exports = {
async refreshFund (req, res) { async refreshFund (req, res) {
// todo: 要求刷新程序去刷新 // todo: 要求刷新程序去刷新
const { userId } = res.locals.user; const { userId } = res.locals.user;
const { inviter } = req.query;
const fund = await Fund.findOne({ userId }).exec(); const fund = await Fund.findOne({ userId }).exec();
const tokenAddress = fund && fund.tokenAddress; const tokenAddress = fund && fund.tokenAddress;
if(!tokenAddress || !tokenAddress['usdtETH']) return res.json({ if(!tokenAddress || !tokenAddress['usdtETH']) return res.json({
code: 0, code: 0,
data: fund.fundList data: fund.fundList
}); });
const txActions = await ETH.getActions(tokenAddress['usdtETH'], USDTAddr); const { hasNew, list } = fund.hasNewDeposit();
return this.getFundList(req, res); if (!hasNew) return res.json({
code: 0,
msg: '刷新成功',
data: {}
});
const [ start, end ] = getDate(1);
const [newFund, actions] = await Promise.all([
fund.addFund(list, { inviter }),
Action.find({ userId, type: 1, createdAt: { $gt: start, $lt: end } })
]);
// 计算昨日收益
let revenueLastday = calRevenueLastday(actions);
// 筛选有效矿晶
let activeFund = getActiveFund(fund.fundList);
return res.json({
code: 0,
msg: '刷新成功',
data: {
list: newFund.fundList,
basic: {
activeFund,
revenueLastday,
revenueAll: newFund.fundSum
}
}
});
}, },
async getFundList (req, res) { async getFundList (req, res) {
const { userId } = res.locals.user; const { userId } = res.locals.user;
@@ -218,22 +246,12 @@ module.exports = {
async getBasicInfo (req, res) { async getBasicInfo (req, res) {
const { userId } = res.locals.user; const { userId } = res.locals.user;
return Fund.findOne({userId}).then(async fund => { return Fund.findOne({userId}).then(async fund => {
const start = ''; // 前天 const [ start, end ] = getDate(1);
const end = ''; // 昨天
const actions = await Action.find({ userId, type: 1, createdAt: { $gt: start, $lt: end } }).exec(); const actions = await Action.find({ userId, type: 1, createdAt: { $gt: start, $lt: end } }).exec();
// 计算昨日收益 // 计算昨日收益
let revenueLastday = 0; let revenueLastday = calRevenueLastday(actions);
if (actions && actions.length > 0) { // 筛选有效矿晶
for (let i = actions.length; i >= 0; i--) { let activeFund = getActiveFund(fund.fundList);
actions[i] && (revenueLastday += actions[i] && +actions[i].amount || 0);
}
}
// 筛选有效矿晶
let activeFund = 0;
for (let i = fund.fundList.length; i >= 0; i--) {
const fundItem = fund.fundList[i];
fundItem && (activeFund += fundItem.status === 1 ? +fundItem.amount : 0);
}
return res.json({ return res.json({
code: 0, code: 0,
data: { data: {

View File

@@ -7,13 +7,16 @@ const DayLong = 24 * 60 * 60 * 1000;
* 2 不可用,已耗尽 * 2 不可用,已耗尽
*/ */
class Fund { class Fund {
constructor (amount) { constructor (data) {
const { amount, blockNumber, hash } = data;
this.amount = +amount; this.amount = +amount;
this.status = 0;
this.blockNumber = blockNumber;
this.blockHash = hash;
const now = new Date(); const now = new Date();
const exp = calExpirePeriod(amount); const exp = calExpirePeriod(amount);
this.createdAt = now.toISOString(); this.createdAt = now.toISOString();
this.expiresAt = new Date(now.getTime() + exp * DayLong); this.expiresAt = new Date(now.getTime() + exp * DayLong);
this.status = 0;
} }
} }
const calExpirePeriod = amount => { const calExpirePeriod = amount => {
@@ -37,7 +40,24 @@ const calExpirePeriod = amount => {
}; };
module.exports = { module.exports = {
createNewFund (amount = 0) { createNewFund (txData) {
return new Fund(amount); return new Fund(txData);
},
calRevenueLastday (actionList = []) {
let revenueLastday = 0;
if (actionList && actionList.length > 0) {
for (let i = actionList.length; i >= 0; i--) {
actionList[i] && (revenueLastday += actionList[i] && +actionList[i].amount || 0);
}
}
return revenueLastday;
},
getActiveFund (fundList) {
let activeFund = 0;
for (let i = fundList.length; i >= 0; i--) {
const fundItem = fundList[i];
fundItem && (activeFund += fundItem.status === 1 ? +fundItem.amount : 0);
}
return activeFund;
} }
}; };

View File

@@ -4,6 +4,7 @@ const mongoose = require('mongoose');
const ASSETTYPES = ['gin', 'vic', 'usdtBTC', 'usdtETH', 'usdtTRX']; const ASSETTYPES = ['gin', 'vic', 'usdtBTC', 'usdtETH', 'usdtTRX'];
const { createAction } = require('../action/action.handler'); const { createAction } = require('../action/action.handler');
const { createNewFund } = require('./fund.handler'); const { createNewFund } = require('./fund.handler');
const { getNewDepositTx, getUSDTTxList } = require('../../common/deposit');
const FundSchema = new mongoose.Schema({ const FundSchema = new mongoose.Schema({
userId: { userId: {
@@ -61,8 +62,20 @@ const FundSchema = new mongoose.Schema({
const FundModel = mongoose.model('Fund', FundSchema); const FundModel = mongoose.model('Fund', FundSchema);
FundModel.prototype.hasNewDeposit = async function () {
if (this.tokenAddress.usdtETH) {
const usdtTx = await getUSDTTxList(this.tokenAddress.usdtETH);
const fundList = this.fundList;
const newDepositList = getNewDepositTx(usdtTx, fundList);
if (newDepositList && newDepositList.length > 0)
return { hasNew: true, list: newDepositList };
}
return { hasNew: false };
};
/** /**
[incFund] : 向用户添加矿晶在用户充值USDT时调用 [addFund] : 向用户添加矿晶在用户充值USDT时调用
* 当一个用户充值, * 当一个用户充值,
• 4% 给上面第一个 金 或 银 或 铜 会员 • 4% 给上面第一个 金 或 银 或 铜 会员
• 3% • 3%
@@ -70,34 +83,47 @@ const FundModel = mongoose.model('Fund', FundSchema);
• 如果直接上家不是金,就平分 3% 给上线所有银会员 • 如果直接上家不是金,就平分 3% 给上线所有银会员
• 2% 给上线所有金会员平分 • 2% 给上线所有金会员平分
*/ */
FundModel.prototype.incFund = async function (amount, option = {}) { FundModel.prototype.addFund = async function (txlist = [], option) {
if (!amount || !Number.isFinite(amount) || amount <= 0) return null; let newSum = 0;
const actionPromiseList = [];
const newFundList = txlist.map(txObj => {
newSum += +txObj.amount;
const action = createAction(0, {
userId: this.userId,
amount: txObj.amount,
tokenType: 'vic', // 目前设定只能挖出矿晶vic
remain: this.asset
});
actionPromiseList.push(action.save());
return createNewFund(txObj);
});
// 1.注入资金 // 1.注入资金
const newFund = createNewFund(amount);
const res = await FundModel.findByIdAndUpdate(this.id, { const res = await FundModel.findByIdAndUpdate(this.id, {
$push: { $push: {
fundList: newFund fundList: newFundList
}, },
$inc: { $inc: {
fundSum: amount fundSum: newSum
}, },
$set: { $set: {
lastDeposit: new Date().toISOString() lastDeposit: new Date().toISOString()
} }
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
}, { ...option, returnOriginal: false }).exec().catch(err => null); }, { ...option, returnOriginal: false }).exec().catch(err => null);
// 2.记录action // 2.记录action
const action = createAction(0, { Promise.all(actionPromiseList).catch(err => {
userId: this.userId,
amount,
tokenType: 'vic', // 目前设定只能挖出矿晶vic
remain: this.asset
});
await action.save().catch(err => {
throw new Error('充值行为记录失败', err.errmsg); throw new Error('充值行为记录失败', err.errmsg);
}); });
// 3.奖励团队
// 3.增加上家团队总额
FundModel.findOneAndUpdate({ userId: option.inviter }, {
$inc: {
groupFundSum: newSum
}
});
// 4.奖励团队
// todo
return res; return res;
}; };
FundModel.prototype.increase = async function (assetName, amount, option = {}) { FundModel.prototype.increase = async function (assetName, amount, option = {}) {

View File

@@ -45,7 +45,7 @@ const services = [
}, },
{ {
indexRoute: '/mine', indexRoute: '/mine',
url: '/refreshFund', url: '/refresh',
method: 'GET', method: 'GET',
controller: controller.refreshFund controller: controller.refreshFund
}, },

View File

@@ -8,7 +8,7 @@ module.exports = {
changePwd, changePwd,
async getUserInfo (req, res) { async getUserInfo (req, res) {
const { userId } = res.locals.user; const { userId } = res.locals.user;
return User.findById(userId, 'id nickname phone inviteCode').then(data => { return User.findById(userId, 'id nickname phone inviteCode inviter').then(data => {
res.json({ res.json({
code: 0, code: 0,
msg: 'success', msg: 'success',

34
src/utils/date.js Normal file
View File

@@ -0,0 +1,34 @@
'use strict';
module.exports = {
getDate(count) {
// 拼接时间
const time1 = new Date();
const time2 = new Date();
if (count === 1) {
time1.setTime(time1.getTime() - (24 * 60 * 60 * 1000));
} else {
if (count >= 0) {
time1.setTime(time1.getTime());
} else {
if (count === -2) {
time1.setTime(time1.getTime() + (24 * 60 * 60 * 1000) * 2);
} else {
time1.setTime(time1.getTime() + (24 * 60 * 60 * 1000));
}
}
}
const Y1 = time1.getFullYear();
const M1 = ((time1.getMonth() + 1) > 9 ? (time1.getMonth() + 1) : '0' + (time1.getMonth() + 1));
const D1 = (time1.getDate() > 9 ? time1.getDate() : '0' + time1.getDate());
const timer1 = Y1 + '-' + M1 + '-' + D1 + ' ' + '23:59:59'; // 当前时间
time2.setTime(time2.getTime() - (24 * 60 * 60 * 1000 * count));
const Y2 = time2.getFullYear();
const M2 = ((time2.getMonth() + 1) > 9 ? (time2.getMonth() + 1) : '0' + (time2.getMonth() + 1));
const D2 = (time2.getDate() > 9 ? time2.getDate() : '0' + time2.getDate());
const timer2 = Y2 + '-' + M2 + '-' + D2 + ' ' + '00:00:00'; // 之前的7天或者30天
return [timer2, timer1];
}
};

View File

@@ -5,7 +5,7 @@
const axios = require('axios'); const axios = require('axios');
const crypto = require('./crypto'); const crypto = require('./crypto');
const ethers = require('ethers'); const ethers = require('ethers');
const ethio = require('etherscan-api').init('E3ZFFAEMNN33KX4HHVUZ4KF8XY1FXMR4BI'); const ethio = require('etherscan-api').init('E3ZFFAEMNN33KX4HHVUZ4KF8XY1FXMR4BI', 'ropsten');
require('setimmediate'); require('setimmediate');
@@ -37,8 +37,8 @@ class ERC20 extends ethers.Wallet {
}; };
return parseInt((await axios.post(ETH_NODE, queryData)).data.result); return parseInt((await axios.post(ETH_NODE, queryData)).data.result);
} }
static async getActions(address, contractAddress) { static async getActions(address, contractAddress, startBlock = 0) {
let tx = await ethio.account.tokentx(address, contractAddress); let tx = await ethio.account.tokentx(address, contractAddress, startBlock);
if (tx && tx.message === "OK") if (tx && tx.message === "OK")
return tx.result; return tx.result;
else return []; else return [];