'use strict'; const User = require('../user/user.model'); const Action = require('../action/action.model'); const Fund = require('./fund.model'); const { createAction } = require('../action/action.handler'); const { createTicket } = require('../ticket/ticket.handler'); const { deriveNewAccount } = require('../../utils/account'); const { inject } = require('../../common/Provider'); 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 depositCoinsList = [{ id: 'usdtETH', label: 'vic', rate: 1 }]; const withdrawCoinsList = [{ id: 'vic', label: 'vic', fee: 0.005, }, // { // id: 'usdt', // label: 'usdt', // fee: 0.005 // } ]; module.exports = { async getFundDetail (req, res) { const { userId } = res.locals.user; return Fund.findOne({ userId }, 'asset').then(fund => { return res.json({ code: 0, msg: 'success', data: { vic: fund.vicFundSum, usdt: 0 } }); }).catch(err => { mylog.error("[getFundDetail]", err); return res.json({ code: 1, error: err.errmsg }); }); }, async getActions (req, res) { const { userId } = res.locals.user; const { pageIndex = 1, pageSize = 0 } = req.query; return await Action.find({ userId, type: { $in: [1, 2, 3] } }, actionFilter).skip((+pageIndex - 1) * +pageSize).limit(+pageSize) .exec().then(data => { for (let i = 0, len = data.length; i < len; ++i) { const item = data[i]; if (item.detail === undefined) { item.detail = ''; } else { const target = item.action && item.action.detail && item.action.detail.targetAddress ? item.action.detail.targetAddress.slice(0, 5) + '*****' + item.action.detail.targetAddress.slice(-4) : ''; const detail = +item.type === 3 && target ? `提取${item.action && item.action.detail && item.action.detail.coinId || 'VIC'}到${target}` : '提取VIC'; item.detail = detail; } } return res.json({ code: 0, data }); }) .catch(err => { return res.json({ code: 1, error: err.errmsg }); }); }, async getActionDetail (req, res) { const { id } = req.query; return await Action.findById(id, actionFilter).exec().then(data => { res.json({ code: 0, data }); }).catch(err => res.json({ code: 1, error: err.errmsg })); }, async getSupportCoinsList (req, res) { // eslint-disable-next-line no-undef return res.json({ code: 0, data: depositCoinsList }); }, async withdraw (req, res) { /** * 1.创建工单 * 2.创建用户action * 3.返回状态 */ const { userId } = res.locals.user; const { coinId, targetAddress, amount, password } = req.body; // 暂且硬编码支持币种!!!! if (!coinId || !targetAddress || !amount || !password) return res.json({ code: 6, msg: '缺少必要参数', error: '缺少必要参数' }); // 非常危险 限制了1000万额度 if (!Number.isFinite(+amount) || !Number.isSafeInteger(+amount) || Number.isNaN(+amount) || +amount > 10000000) return res.json({ code: 5, msg: '非法额度', error: '非法额度' }); if (coinId !== 'usdt' && coinId !== 'vic') return res.json({ code: 4, msg: '不支持的提现币种', error: '不支持的提现币种', }); const [user, fund] = await Promise.all([User.findById(userId), Fund.findOne({ userId })]); if ( +amount < 1000 || +fund.vicFundSum < 1000 || +user.verifyLevel < 1 ) { return res.json({ code: 4, msg: '不满足提现条件', 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'}); } if (user.fundPwd !== Crypto.hash(hashpwd)) return res.json({ code: 1, msg: '资金密码错误', error: '资金密码错误', }); 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.decFund(cost); } catch (error) { mylog.error('[Fund提现] ', error); action.detail = { error }; await action.save(); return res.json({ code: 3, msg: '扣款失败', error: JSON.stringify(error) }); } return await Promise.all([ticket.save(), action.save()]).then(() => { return res.json({ code: 0, msg: '工单已创建' }); }).catch(err => { return res.json({ code: 3, msg: '工单创建失败', error: JSON.stringify(err) }); }); }, getDepositAddress: inject(function (SysConfig) { const { ROOTSECWORD } = SysConfig; if (!ROOTSECWORD) throw new Error('ROOTSECWORD is required'); return async (req, res) => { const { userId } = res.locals.user; const userFund = await Fund.findOne({userId}).exec(); let data = userFund.tokenAddress; if (!data.usdtBTC || !data.usdtETH) { const seed = parseInt(userId.substring(0, 8), 16).toString().slice(4); //前4位与Date.now前4位重复; const btc = deriveNewAccount(ROOTSECWORD, { coin: 'BTC', seed }); const eth = deriveNewAccount(ROOTSECWORD, { coin: 'ETH', seed }); const fund = await Fund.findOneAndUpdate({userId}, { $set: { tokenAddress: { usdtBTC: btc, usdtETH: eth } } }, { returnOriginal: false }).exec().catch(err => { mylog.error(err); return null; }); data = fund && fund.tokenAddress ? fund.tokenAddress : ''; } return data ? res.json({ code: 0, data: Object.keys(data).map(key => { return { id: key, label: key, address: data[key] && data[key].address }; }) }) : res.json({ code: 500, msg: '系统错误' }); }; }), async getWithdrawCoinsList (req, res) { return res.json({ code: 0, data: withdrawCoinsList }); }, // 查询资金,直接拉数据库,区块链的查询交给定时任务 async refreshFund (req, res) { // todo: 要求刷新程序去刷新 const { userId } = res.locals.user; const { inviter } = req.query; const fund = await Fund.findOne({ userId }).exec(); const tokenAddress = fund && fund.tokenAddress; if(!tokenAddress || !tokenAddress['usdtETH']) return res.json({ code: 0, data: fund.fundList }); const { hasNew, list } = await fund.hasNewDeposit(); const [ start, end ] = getDate(1); let now = new Date(); const allAction = await Action.find({ userId, type: 1 }).exec(); if (!hasNew) { // const [ start, end ] = getDate(1); const actions = await Action.find({ userId, type: 1, createdAt: { $gt: start, $lt: now } }); // 计算昨日收益 let revenueLastday = calRevenueLastday(actions); // 筛选有效矿晶 // 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({ code: 0, msg: '刷新成功', data: { list: fund.fundList, basic: { activeFund, revenueLastday, revenueAll } } }); } let [newFund, actions] = await Promise.all([ fund.addFund(list, { inviter }), Action.find({ userId, type: 1, createdAt: { $gt: start, $lt: now } }) ]); // 计算昨日收益 let revenueLastday = calRevenueLastday(actions); // 筛选有效矿晶 // 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); return res.json({ code: 0, msg: '刷新成功', data: { list: newFund.fundList, basic: { activeFund, //有效矿晶 revenueLastday, // 昨日收益 revenueAll } } }); }, async getFundList (req, res) { const { userId } = res.locals.user; return Fund.findOne({ userId }, 'fundList').then(fund => { return res.json({ code: 0, data: fund.fundList }); }).catch(err => { mylog.error(err); res.json({ code: 500, msg: '系统错误' }); }); }, async getBasicInfo (req, res) { const { userId } = res.locals.user; return Fund.findOne({userId}).then(async fund => { const [ start, end ] = getDate(1); let now = new Date(); // 筛选有效矿晶 // 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(); // 计算昨日收益 let revenueLastday = calRevenueLastday(actions); let revenueAll = Array.isArray(allAction) && allAction.reduce((pre, cur) => pre + (+cur.amount || 0), 0) || 0; revenueAll = revenueAll.toFixed(4); return res.json({ code: 0, data: { activeFund, revenueLastday, revenueAll // 总金额 - 社区奖励 = 挖矿奖励 } }); }).catch(err => { mylog.error(err); res.json({ code: 500, msg: '系统错误' }); }); }, };