Commit d819e3c4 authored by 1486327116's avatar 1486327116

Merge remote-tracking branch 'origin/master'

parents cb3a4b54 86856f1d
{ {
"customBaseDir" :"/var/tmp/mytoken/", "customBaseDir" :"/var/tmp/madex/backend/",
"customDefaultAtt" :{ "customDefaultAtt" :{
"type": "file", "type": "file",
"maxLogSize": "10M", "maxLogSize": "10M",
......
/**
* 原文件:b024-spot.rpc.utils.js
*/
import {
ormDB,
userInfo,
coinType,
mainUserAsset,
userInfoSon,
feeRateSpotLog,
feeRateContractLog,
commonUserFeeSetting,
feeRateBaseCoinContractLog, spotPairs, contractPairs
} from "@madex/ex-ts-dao";
import { FEE_RATE_LOG_STATUS } from "../../src/constant/feeRateLogConst";
import { changeTradingFee, getPairFromCore } from "../../src/utils/coreSystemUtils";
let BigNumber = require('bignumber.js');
const logger = require('@madex/ex-js-public').logger;
let user_info = userInfo.prototype;
let coin_type = coinType.prototype;
let fee_rate_spot_log = feeRateSpotLog.prototype;
let feeRateCheckStatus = FEE_RATE_LOG_STATUS;
let WHITE_LIST: any = [];
const sleep = ms => new Promise((res) => setTimeout(res, ms));
/**
* 检查交易对是否存在
* @param pair
* @param type 1 现货 2 U本位合约 3 币本位合约
*/
let checkPair = async function (pair: string, type: number) {
let _func_name_ = 'task.fee.rate.log.model.checkPair';
if (!pair || !type) {
throw '3000';
}
let dbPair: any;
if (type == 1) {//现货
dbPair = await spotPairs.prototype.findOne({
attributes: ['id'],
where: {
symbol: String(pair),
status: 2,//提交成功
},
raw: true,
});
}
else {//U、币本位合约
dbPair = await contractPairs.prototype.findOne({
attributes: ['id'],
where: {
symbol: String(pair),
status: 2,//提交成功
},
raw: true,
})
}
if (!dbPair) {
logger.warn(_func_name_, `spot_pairs or contract_pairs no found ${pair} or no push core`);
throw '3000';
}
return dbPair;
};
let checkUser = async function (user_id) {
let _func_name_ = 'task.fee.rate.log.model.checkUser';
if (!user_id || isNaN(user_id)) {
throw '3000';
}
let dbinfo = await user_info.findOne({
attributes: ['user_id'],
where: {
user_id: Number(user_id),
},
raw: true,
});
if (!dbinfo) {
logger.warn(_func_name_, `user_info no found ${user_id}`);
throw '3000';
}
return dbinfo;
};
let checkFeeModel = async function (fee_model) {
let _func_name_ = 'task.fee.rate.log.model.checkFeeModel';
let validFeeModel = {
fixed: 1,
fixedingain: 1,
tered: 1,
tieredingain: 1,
fixedingainuser: 1,
};
if (!validFeeModel[fee_model]) {
logger.warn(_func_name_, `fee_model error ${fee_model}`);
throw '3000';
}
};
let checkFeeRate = async function (fee_rate) {
let _func_name_ = 'spotRpcUtils.checkFeeRate';
if (isNaN(fee_rate) || Math.abs(Number(fee_rate)) > 0.005 || fee_rate < 0) {
logger.warn(_func_name_, `fee_rate error ${fee_rate}`);
throw '3000';
}
};
export const changeUserSpotFee = async function (user_id, symbol, fee_model, maker_fee, taker_fee, logId) {
let is_success = true;
await checkFeeModel(fee_model);
let asset = await mainUserAsset.prototype.findOne({
where: {
user_id
},
raw: true
})
if (!asset) {
return is_success;
}
if (isNaN(maker_fee) || Math.abs(Number(maker_fee)) > 0.005) { // maker (-0.005, 0.005); // 正负千五
logger.warn(' task.fee.rate.log.model.changeUserSpotFee ', ` maker_fee fee_rate error ${maker_fee}`);
throw '3000';
}
if (isNaN(taker_fee) || taker_fee < 0 || taker_fee > 0.005) { // taker 最小为0
logger.warn(' task.fee.rate.log.model.changeUserSpotFee ', ` taker_fee fee_rate error ${taker_fee}`);
throw '3000';
}
await checkPair(symbol, 1);
await checkUser(user_id);
await sleep(1000);
//请求撮合 修改费率
let res = await changeTradingFee(symbol, user_id, maker_fee, taker_fee);
return res.is_success;
};
export const changeUserContractFee = async function (user_id, symbol, fee_model, maker_fee, taker_fee, logId) {
let _func_name_ = 'task.fee.rate.log.model.changeUserContractFee';
let is_success = true;
await checkPair(symbol, 2);
let asset = await mainUserAsset.prototype.findOne({
where: {
user_id
},
raw: true
})
if (!asset) {
return is_success;
}
if (maker_fee < -0.0003) { // 最大返0.0003
logger.warn(_func_name_, `fee_rate error ${maker_fee}`);
throw '3000';
}
if (taker_fee < 0 || taker_fee > 0.005) {
logger.warn(_func_name_, `fee_rate error ${taker_fee}`);
throw '3000';
}
maker_fee = new BigNumber(String(maker_fee)).toFixed(7);
taker_fee = new BigNumber(String(taker_fee)).toFixed(7);
await checkUser(user_id);
await sleep(1000);
//请求撮合 修改费率
let res = await changeTradingFee(symbol, user_id, maker_fee, taker_fee);
return res.is_success;
};
export const isWhiteListUser = async function (user_id: number) {
let father_id = await getMainAccountUserId(user_id);
if (WHITE_LIST.includes(father_id) || Number(father_id) < 100000) {
return true;
}
return false;
}
async function getMainAccountUserId(user_id: number) {
let dbSon = await userInfoSon.prototype.findOne({
where: {
user_id: Number(user_id)
}
});
let father_id = dbSon ? dbSon.father_id : user_id;
return father_id;
}
import { ormDB, feeRateSpotLog, feeRateContractLog, commonUserFeeSetting, feeRateBaseCoinContractLog } from "@madex/ex-ts-dao";
import { FEE_STATUS } from "../../src/constant/marketMakerConst";
const logger = require('@bibox/bibox_public').logger;
import * as RobotUtil from "../../src/utils/robotUtils";
let OP = ormDB.Op;
let fee_rate_spot_log = feeRateSpotLog.prototype;
let fee_rate_contract_log = feeRateContractLog.prototype;
let fee_rate_base_coin_contract_log = feeRateBaseCoinContractLog.prototype;
let common_user_fee_setting = commonUserFeeSetting.prototype;
/**
* 根据id获取币币手续费设置纪录。
* @param id
* @returns {Promise<Model>}
*/
export const spotFeeStatusCheck = async function (id) {
return await fee_rate_spot_log.findOne({
attributes: ['id', 'is_check'],
where: {
id: id,
},
raw: true,
});
};
/**
* 根据id获取合约手续费设置纪录。
* @param id
* @returns {Promise<Model>}
*/
export const contractFeeStatusCheck = async function (id) {
return await fee_rate_contract_log.findOne({
attributes: ['id', 'is_check'],
where: {
id: id,
},
raw: true,
});
};
export const baseCoinContractFeeStatusCheck = async function (id) {
return await fee_rate_base_coin_contract_log.findOne({
attributes: ['id', 'is_check'],
where: {
id: id,
},
raw: true,
});
};
/****************************************** 普通用户费率设置状态更新相关操作。 **********************************************/
/**
* 获取已提交且到开始时间的的记录。
*
* @returns {Promise<Model>}
*/
export const findUserFeeDataNeed2Active = async function () {
return await common_user_fee_setting.findAll({
where: {
begin_time: { [OP.lte]: new Date() },
status: FEE_STATUS.STATUS_FEE_SETTING_SUBMIT,
},
raw: true,
});
};
/**
* 获取已生效且到过期时间的。
*
* @returns {Promise<Model>}
*/
export const findUserFeeDataNeed2Expire = async function () {
return await common_user_fee_setting.findAll({
where: {
expire_time: { [OP.lt]: new Date() },
status: FEE_STATUS.STATUS_FEE_SETTING_EFFECTED,
},
raw: true,
});
};
/**
* 更新手续费设置纪录的状态。
* @returns {Promise<void>}
*/
export const userFeeSettingStatusUpdate = async function (id, status) {
try {
let toUpdate = {
status: status,
update_time: new Date()
};
let condition = {
id: id,
};
await common_user_fee_setting.update(toUpdate, {
where: condition
});
logger.warn("task.fee.setting.status.update.model.userFeeSettingStatusUpdate data update success.");
}
catch (e) {
let msg = `task.fee.setting.status.update.model.userFeeSettingStatusUpdate data update fail! id: ${id}, status: ${status}`;
logger.error(msg);
RobotUtil.sendRobotMessage(RobotUtil.ROBOT_KEYS.COMMON_KEY, msg);
}
};
import { FEE_STATUS, FEE_TYPE } from "../../src/constant/marketMakerConst";
let { logger } = require('@madex/ex-js-public');
let {
spotFeeStatusCheck, contractFeeStatusCheck, baseCoinContractFeeStatusCheck,
findUserFeeDataNeed2Active, findUserFeeDataNeed2Expire, userFeeSettingStatusUpdate
} = require('../model/task.fee.setting.status.update.model');
/**
* 币币、合约费率设置记录状态。
*/
import { FEE_RATE_LOG_STATUS } from "../../src/constant/feeRateLogConst";
/****************************************** 普通用户费率设置状态更新相关操作。 **********************************************/
/**
* 市商、普通用户、KOL 费率状态更新。
* @returns {Promise<void>}
*/
export const commonUserFeeSettingStatusUpdateService = async function (ctime = new Date()) {
try {
await commonUserStatusUpdate();
}
catch (error) {
logger.error(' commonUserFeeSettingStatusUpdate error ', error);
}
logger.warn(' commonUserFeeSettingStatusUpdate ', ctime, ' stat over ');
};
/**
* 状态扫描和更新。
* @returns {Promise<void>}
*/
async function commonUserStatusUpdate() {
let [data2Submit, data2Expire] = await Promise.all([findUserFeeDataNeed2Active(), findUserFeeDataNeed2Expire()]);
await userDataCheckAndUpdate(data2Submit);
await userDataCheckAndUpdate(data2Expire);
}
/**
* 检查数据情况并更新状态。
* @param data
* @returns {Promise<void>}
*/
async function userDataCheckAndUpdate(data) {
if (data === null || data.length === 0) {
return;
}
for (let i = 0, len = data.length; i < len; i++) {
let item = data[i];
let id = item.id;
let logIds = item.fee_log_ids;
let idArr = logIds.split(",");
if (idArr === null || idArr.length === 0) {
logger.error("commonUserFeeSettingStatusUpdate.userDataCheckAndUpdate log id parse fail! id: %s", id);
continue;
}
// 根据记录id确定该设置项的状态。
let logId = idArr[0];
let feeStatusData;
if (Number(item.type) === FEE_TYPE.FEE_TYPE_SPOT) {
feeStatusData = await spotFeeStatusCheck(logId);
}
else if (Number(item.type) === FEE_TYPE.FEE_TYPE_CONTRACT) {
feeStatusData = await contractFeeStatusCheck(logId);
}
else if (Number(item.type) === FEE_TYPE.FEE_TYPE_BASE_COIN_CONTRACT) {
feeStatusData = await baseCoinContractFeeStatusCheck(logId);
}
if (feeStatusData === null) {
logger.error("commonUserFeeSettingStatusUpdate.userDataCheckAndUpdate fee setting record miss! " +
"id: %s, logId: %s", id, logId);
continue;
}
let status = item.status;
let statusNew = status;
let feeStatus = Number(feeStatusData.is_check);
switch (feeStatus) {
case FEE_RATE_LOG_STATUS.CHECK_STATUS_ACTIVE:
statusNew = FEE_STATUS.STATUS_FEE_SETTING_EFFECTED;
break;
case FEE_RATE_LOG_STATUS.CHECK_STATUS_ACTIVE_OVER:
statusNew = FEE_STATUS.STATUS_FEE_SETTING_EXPIRE;
break;
case FEE_RATE_LOG_STATUS.CHECK_STATUS_DELETED:
statusNew = FEE_STATUS.STATUS_FEE_SETTING_DELETED;
break;
default:
continue;
}
if (statusNew !== status) {
await userFeeSettingStatusUpdate(id, statusNew);
logger.info("commonUserFeeSettingStatusUpdate.userDataCheckAndUpdate log(%s) status updated. %s -> %s",
id, status, statusNew);
}
}
}
\ No newline at end of file
// 每日定时统计项目方 指定交易对做市信息, 并根据成交量信息进行费率分档优惠;
import { ormDB, commonUserFeeSetting, feeRateSpotLog, userInfoSon, spotPairs, contractPairs, userInfo } from "@madex/ex-ts-dao";
import { FEE_RATE_LOG_STATUS } from "../../src/constant/feeRateLogConst";
let Op = ormDB.Op;
let { tickerUtils, redisUtilsCommon } = require('@madex/ex-js-common');
let user_info_son = userInfoSon.prototype;
let user_info = userInfo.prototype;
const SonStatus = userInfoSon.STATUS;
const logger = require('@madex/ex-js-public').logger;
let feeRateCheckStatus = FEE_RATE_LOG_STATUS;
//对btc价格,缓存 {coinSymbol: priceInfo}
var price2BTC = {};
//价格缓存时间 2分钟
const CACHE_TIMEOUT = 2 * 60 * 1000;
const DAY = 24 * 3600 * 1000;
const FEE_MODEL = {
"fixedingain": "fixedingain"
}
const BTC_AMOUNT = {
"BTC30": 30,
"BTC5": 5,
"BTC0": 0,
},
FEE_RATE = {
"Wan1": 0.0001,
"Wan2": 0.0002,
"Default": 0.001,
"maker_default": 0.0008,
"Free": 0,
},
Market_Maker_FEE = {
init_taker: 0.0002,
init_maker: 0,
}
async function delayPromise(time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
export const statisProjectMakerDeals = async function (now = Date.now()) {
try {
//TODO:按之前代码来看,只有现货相关的,这里怎么做
let users = await projectMaker();
let startTime = now - now % DAY - DAY;// 当前统计昨天的成交数据
let btc2usdt = await getDealOneDayInUSDT(startTime, startTime + DAY);
let fatherFeeObj = {}; // { fatherid_pair: {maker, taker}}
for (let i = 0; i < users.length; i++) {
let { user_id, pair, status, statis_period, amount_require_usdt, type } = users[i]; //status 2 生效时才统计
let pairs = pair == 'all' ? await getPairsByType(type) : [pair];
for (let onePair of pairs) {
if (user_id && onePair) {
let redisKey = user_id + "_" + onePair + "_projectMaker_FeeRate";
await delayPromise(100);
let [statis, statisUsdt] = await statisUserPairSpot(user_id, onePair, startTime, btc2usdt);
let feeObjBtc = getUserFeeRateFromStatis(statis); // old
let feeObjUsdt = getUserFeeRateFromUsdtStatis(statisUsdt, statis_period, amount_require_usdt)
await adjustMakerFeeRate(now, user_id, onePair, status, feeObjBtc, feeObjUsdt, fatherFeeObj);
redisUtilsCommon.write(redisKey, JSON.stringify(Object.assign({}, feeObjUsdt, feeObjBtc)), 0, () => {
});
}
}
}
now = Date.now();
let expired = now + DAY - 30000;
for (let key in fatherFeeObj) {
let [user_id, pair] = key.split('@');
let faterFee = fatherFeeObj[key];
if (faterFee) {
let { maker_fee, taker_fee } = faterFee;
await setExpiredFeeSettingActiveOver(user_id, pair);
await addFeeRate(user_id, pair, FEE_MODEL.fixedingain, maker_fee, taker_fee, now, expired, Market_Maker_FEE.init_maker, Market_Maker_FEE.init_taker, "项目方做市商策略根据子账户交易量设置父账户费率");
}
}
}
catch (error) {
logger.warn(' statisProjectMakerDeals error ', error);
}
}
// 统计 项目方 7日, 15日 指定币种对 做市
async function projectMaker() {
let res: any = [];
try {
res = await commonUserFeeSetting.prototype.findAll({
where: {
user_channel: 2,
type: 1,
},
order: [['id', 'asc']],
raw:
true,
})
;
}
catch (error) {
logger.warn(' 获取项目方做市商 projectMaker error', error);
}
return res;
}
// 获取交易对USDT交易量
async function getDealOneDayInUSDT(startTime, endTime) {
let price = await tickerUtils.rateCoin2USDT('BTC');
//TODO:查询交易数据
/*let priceRes = await ex_kline.find({
attributes: [[ormDBSpot.literal('AVG(close)'), 'closePrice']],
where: {
pair: "BTC_USDT",
period: '1hour',
createdAt: {
[Op.gte]: new Date(startTime),
[Op.lt]: new Date(endTime),
}
},
raw: true,
});
if(priceRes && Number(priceRes.closePrice) > 0) {
price = Number(priceRes.closePrice).toFixed(4);
}*/
return Number(price);
}
// 统计币币成交量信息
async function statisUserPairSpot(user_id, pair, timestamp, btc2usdt) {
let redisKey = user_id + "_" + pair + '_projectMaker_spot';
let redisKeyUsdt = user_id + "_" + pair + '_projectMaker_spot_usdt';
let resultCache = {}, resultCacheInUsdt = {};
try {
[resultCache, resultCacheInUsdt] = await Promise.all([redisUtilsCommon.getSync(redisKey), redisUtilsCommon.getSync(redisKeyUsdt)]);
let userDeals = await getDealOneDay(pair, new Date(timestamp), timestamp + DAY);
resultCache = updateCache(resultCache, timestamp, userDeals);
let usdtAmount = Number(userDeals) * btc2usdt
resultCacheInUsdt = updateCache(resultCacheInUsdt, timestamp, usdtAmount);
redisUtilsCommon.write(redisKey, JSON.stringify(resultCache), 0, () => {
});
redisUtilsCommon.write(redisKeyUsdt, JSON.stringify(resultCacheInUsdt), 0, () => {
});
}
catch (error) {
logger.warn(' 统计项目做市上成交总和 error ', error);
}
return [resultCache, resultCacheInUsdt];
}
// 获取昨天一天的的统计交易量
// 该交易对对所有交易量都归该做市帐号
async function getDealOneDay(pair, startTime, endTime) {
let resCountInBTC = 0;
try {
//查哪里
/*let tradeDetail = await ex_trade_detail_spot.find({
attributes: ['currency_symbol', [ormDBSpot.literal('SUM(deal_money)'), 'deal_money']],
where: {
pair: pair,
createdAt: {
[Op.gte]: startTime,
[Op.lt]: endTime,
}
},
group: ['currency_symbol'],
raw: true,
});
if (tradeDetail && tradeDetail.deal_money > 0.00000001) {
let currencySymbol = tradeDetail.currency_symbol;
let currencyAmount = tradeDetail.deal_money;
let price = await coinPriceInBTC(currencySymbol, startTime, endTime);
let equalBTC = currencyAmount * price;
// let equalBTC = currencyAmount * 0.001;
if (equalBTC >= 0.00000001) {
resCountInBTC = equalBTC;
}
}*/
}
catch (error) {
logger.error(" 查询用户每天做市量出错 ", error);
}
return resCountInBTC;
}
async function coinPriceInBTC(coinSymbol, startTime, endTime) {
let time = Date.now();
if (!coinSymbol) {
logger.error(' coinSymbol illegal, coinSymbol is: ', coinSymbol);
}
let priceInfo = price2BTC[coinSymbol];
if (coinSymbol === 'BTC') {
//BTC无转换
return 1;
}
else if (priceInfo && (time - priceInfo.updatedTime) <= CACHE_TIMEOUT) {
return priceInfo.price;
}
else {
//拉取24小时平均价格
let tickerPair, lastPrice = 0;
if (coinSymbol === 'USDT' || coinSymbol === 'DAI' || coinSymbol === 'GUSD') {
tickerPair = 'BTC_' + coinSymbol;
}
else {
tickerPair = coinSymbol + '_BTC';
}
try {
//TODO:查哪里
/*let priceRes = await ex_kline.find({
attributes: [[ormDBSpot.literal('AVG(close)'), 'closePrice']],
where: {
pair: tickerPair,
period: '1hour',
createdAt: {
[Op.gte]: startTime,
[Op.lt]: endTime,
}
},
raw: true,
});
if (priceRes && priceRes.closePrice > 0) {
if (coinSymbol === 'USDT' || coinSymbol === 'DAI' || coinSymbol === 'GUSD') {
lastPrice = 1 / priceRes.closePrice;
} else {
lastPrice = priceRes.closePrice;
}
price2BTC[coinSymbol] = { updatedTime: Date.now(), price: lastPrice };
} else {
logger.warn(` 未查询到交易对${tickerPair} 24hour均值`, priceRes);
}*/
return lastPrice;
}
catch (error) {
logger.warn(` 查询到交易对${tickerPair} 24hour均值出错 `, error);
price2BTC[coinSymbol] = { updatedTime: Date.now(), price: 0 };
return 0;
}
}
}
function updateCache(resultCache, timestamp, userDeals) {
if (resultCache) {
let timesArr = Object.keys(resultCache);
if (!timesArr.includes(String(timestamp)) && userDeals > 0) {//是否存在今天的数据
resultCache[timestamp] = userDeals;
}
if (timesArr.length > 31) {
for (let i = 0, len = timesArr.length - 31; i < len; i++) {
if (timestamp - Number(timesArr[i]) > 31 * DAY) { // 删除超过30天的缓存数据
delete resultCache[timesArr[i]];
}
}
}
}
else { // 无缓存数据
if (userDeals > 0) {
resultCache = {
[timestamp]: userDeals
}
}
}
return Object.assign({}, resultCache);
}
// 从统计结果中获取用户费率, 旧btc交易量统计会逐渐改为usdt统计
function getUserFeeRateFromStatis(dealAmountCache) {
let feeRate = FEE_RATE.Default, avg7 = 0, avg15 = 0, canAjustFeeRateBTC = false;
try {
const day7 = 7, day15 = 15;
let timeArr = Object.keys(dealAmountCache), len = timeArr.length, sum;
let feeRate7 = FEE_RATE.Default, feeRate15 = FEE_RATE.Default;
if (len > 0 && len < day7) {// 低于 7 天
sum = 0;
for (let i = 0; i < len; i++) {
let ts = timeArr[i];
sum += Number(dealAmountCache[ts]) || 0;
}
avg7 = sum / len;
}
if (len >= day7) {
canAjustFeeRateBTC = true;
sum = 0;
for (let i = len - 1, stopIndex = len - day7; i >= stopIndex; i--) {
let ts = timeArr[i];
sum += Number(dealAmountCache[ts]) || 0;
}
avg7 = sum / day7;
if (avg7 >= BTC_AMOUNT.BTC30) {
feeRate7 = FEE_RATE.Wan1;
}
else if (avg7 >= BTC_AMOUNT.BTC5) {
feeRate7 = FEE_RATE.Wan2;
}
else if (avg7 > BTC_AMOUNT.BTC0) {
feeRate7 = FEE_RATE.Default;
}
}
if (len >= day15) {
sum = 0;
for (let i = len - 1, stopIndex = len - day15; i >= stopIndex; i--) {
let ts = timeArr[i];
sum += Number(dealAmountCache[ts]) || 0;
}
avg15 = sum / day15;
if (avg15 >= BTC_AMOUNT.BTC30) {
feeRate15 = FEE_RATE.Free;
}
else if (avg15 >= BTC_AMOUNT.BTC5) {
feeRate15 = FEE_RATE.Wan2;
}
else if (avg15 > BTC_AMOUNT.BTC0) {
feeRate15 = FEE_RATE.Default;
}
}
feeRate = Math.min(feeRate7, feeRate15);
}
catch (error) {
logger.warn(' getUserFeeRateFromStatis error', error);
}
return { feeRate, avg7, avg15, canAjustFeeRateBTC };
}
// 增加usdt统计需求,
function getUserFeeRateFromUsdtStatis(dealAmount, statis_period, requireAmount = 100000) {
let timeArr = Object.keys(dealAmount), len = timeArr.length, canAjustFeeRateUsdt = false, sum = 0, avg = 0;
let taker_rate = 0.0002, maker_rate = 0; // 新项目做市商需求,如果<100K, taker 0.02%, maker = 0;
if (len > 0 && len < statis_period) {
for (let i = 0; i < len; i++) {
let ts = timeArr[i];
sum += Number(dealAmount[ts]) || 0;
}
avg = sum / len;
}
else if (len >= statis_period) {
canAjustFeeRateUsdt = true;
sum = 0;
for (let i = len - 1, stopIndex = len - statis_period; i >= stopIndex; i--) {
let ts = timeArr[i];
sum += Number(dealAmount[ts]) || 0;
}
avg = sum / statis_period;
if (avg >= requireAmount) {
taker_rate = 0;
}
}
return { taker_rate, maker_rate, avg_usdt: avg, canAjustFeeRateUsdt };
}
// 调整做市商费率最佳
async function adjustMakerFeeRate(now, user_id, pair, enableAjustFee, feeObjBtc: any = {}, feeObjUsdt: any = {}, fatherFeeObj: any = {}) {
// let now = Date.now();
let expired = new Date(now).getTime() + DAY - 30000; // 有效期提前30s,早于新费率开始时间
console.error(' 执行项目做市商 uid %s , %s 费率调整 ', user_id, pair);
let maker_fee = Market_Maker_FEE.init_maker, taker_fee = Market_Maker_FEE.init_taker;
let { maker, taker } = await getProjectSpotFeeRate(user_id, pair, now - 3600000);// 查询费率变更前的费率 0 则继续免费
if (enableAjustFee) {
if (feeObjUsdt && feeObjUsdt.canAjustFeeRateUsdt) { // 新版usdt计量策略优先
console.error(' 新做市策略 ', JSON.stringify(feeObjUsdt));
if (taker_fee > feeObjUsdt.taker_rate) { // taker_rate, maker_rate,
taker_fee = feeObjUsdt.taker_rate;
}
if (maker_fee > feeObjUsdt.maker_rate) {
maker_fee = feeObjUsdt.maker_rate;
}
await storeFatherFeeSet(user_id, pair, maker_fee, taker_fee, fatherFeeObj);
await setExpiredFeeSettingActiveOver(user_id, pair);
return await addFeeRate(user_id, pair, FEE_MODEL.fixedingain, maker_fee, taker_fee, now, expired, Market_Maker_FEE.init_maker, Market_Maker_FEE.init_taker, "项目方做市商根据usdt成交量自动调整");
}
else if (feeObjBtc && feeObjBtc.canAjustFeeRateBTC) { // 执行老版 btc 计量策略
console.error(' 早期做市策略 ', JSON.stringify(feeObjBtc));
if (maker == FEE_RATE.Free && taker == FEE_RATE.Free && feeObjBtc.feeRate == FEE_RATE.Wan1) {//手动设置,默认免手续费;若项目单个交易对连续7天日均交易量达到30BTC以上,该交易对手续费保持免费;(运营加需求)
await storeFatherFeeSet(user_id, pair, FEE_RATE.Free, FEE_RATE.Free, fatherFeeObj);
await setExpiredFeeSettingActiveOver(user_id, pair);
return await addFeeRate(user_id, pair, FEE_MODEL.fixedingain, FEE_RATE.Free, FEE_RATE.Free, now, expired, Market_Maker_FEE.init_maker, Market_Maker_FEE.init_taker, "项目方做市商根据btc成交量自动调整");
}
else {
console.error(' 早期做市策略 ', JSON.stringify(feeObjBtc));
// maker_fee = feeObjBtc.feeRate, taker_fee = feeObjBtc.feeRate;
maker_fee = Math.min(maker_fee, feeObjBtc.feeRate), taker_fee = Math.min(taker_fee, feeObjBtc.feeRate);
await storeFatherFeeSet(user_id, pair, maker_fee, taker_fee, fatherFeeObj);
await setExpiredFeeSettingActiveOver(user_id, pair);
return await addFeeRate(user_id, pair, FEE_MODEL.fixedingain, maker_fee, taker_fee, now, expired, Market_Maker_FEE.init_maker, Market_Maker_FEE.init_taker, "项目方做市商策略根据btc成交量自动调整");
}
}
}
}
/**
* 如果用户设置前7日>30BTC并且享受免费, 则一直为免费
* @param {*} user_id
* @param {*} pair
* @param {*} time
*/
async function getProjectSpotFeeRate(user_id, pair, time) {
let maker = FEE_RATE.maker_default, taker = FEE_RATE.Default;
try {
let res = await feeRateSpotLog.prototype.findOne({
attributes: ['maker_fee', 'taker_fee'],
where: {
user_id: user_id,
pair: pair,
is_check: 1,
beginAt: { [Op.lt]: new Date(time), },
expireAt: { [Op.gte]: new Date(time), }
},
raw: true,
});
if (res && Number(res.maker_fee) >= 0 && Number(res.taker_fee) >= 0) {
maker = Number(res.maker_fee);
taker = Number(res.taker_fee);
}
}
catch (error) {
logger.warn(' marketMarkerMgr.service ', error);
}
return {
taker,
maker,
}
}
async function storeFatherFeeSet(user_id, pair, maker_fee, taker_fee, fatherFeeObj = {}) {
let faterObj = await getFaterUID(user_id);
if (faterObj && faterObj.father_id) {
let key = faterObj.father_id + "@" + pair;
if (!fatherFeeObj[key]) {
fatherFeeObj[key] = {
pair,
maker_fee,
taker_fee
}
}
else {
fatherFeeObj[key] = {
pair,
maker_fee: Math.min(maker_fee, fatherFeeObj[key].maker_fee),
taker_fee: Math.min(taker_fee, fatherFeeObj[key].taker_fee),
}
}
}
logger.info(' father fee setting ', JSON.stringify(fatherFeeObj));
}
// 获取某个子账户的父账户
async function getFaterUID(user_id) {
return user_info_son.findOne({
attributes: ['father_id'],
where: {
user_id,
status: SonStatus.NORMAL,
},
raw: true,
});
}
// 将即过期默认为生效的置为生效完成, 防止覆盖新的费率
async function setExpiredFeeSettingActiveOver(user_id, pair) {
try {
let now = new Date();
// console.log(' 更新做市商即将到期生效的费率', user_id, pair);
let res = await feeRateSpotLog.prototype.update({
is_check: feeRateSpotLog.IS_CHECK.ActiveOver,
}, {
where: {
user_id: user_id,
pair: pair,
is_check: feeRateSpotLog.IS_CHECK.Uncheck,
beginAt: {
[Op.gte]: now,
[Op.lt]: new Date(now.getTime() + 3600 * 1000)
},
}
});
// console.error(' 使当前未生效过期 res ', JSON.stringify(res));
}
catch (error) {
logger.error(' make expried fee setting active_over: error ', error);
}
}
async function getPairsByType(type: number) {
let dbList: any;
//现货
if (type == 1) {
dbList = await spotPairs.prototype.findAll({
where: { status: 2 },
raw: true
});
}
else {
dbList = await contractPairs.prototype.findAll({
where: { status: 2 },
raw: true
});
}
return dbList.map(item => item.symbol);
}
async function addFeeRate(user_id, pair, fee_model, maker_fee, taker_fee, beginAt, expireAt, maker_fee_late, taker_fee_late, comment = '') {
if (comment && String(comment).length > 512) {
throw '3000';
}
let dbinfo = await user_info.findOne({
where: {
user_id: Number(user_id),
},
raw: true,
});
if (!dbinfo) {
throw '3000';
}
let insertOne = {
user_id, pair, fee_model, maker_fee, taker_fee, beginAt, expireAt,
is_check: feeRateCheckStatus.CHECK_STATUS_UNCHECK,
comment: String(comment),
}
await feeRateSpotLog.prototype.create(insertOne);
}
\ No newline at end of file
'use strict';
import { ormDB, coinType, systemTrigger } from "@madex/ex-ts-dao";
let { redisUtilsCommon } = require('@madex/ex-js-common')
const TRIGGER_TYPE_COIN = 1;
const TRIGGER_TYPE_EX_PAIR = 2;
const TRIGGER_STATUS_CANCEL = -1;
const TRIGGER_STATUS_UN_TRIGGER = 0;
const TRIGGER_STATUS_SUCCESS = 1;
const TRIGGER_STATUS_FAIL = 2;
const TRIGGER_ACTION_COIN_TYPE = {
dis_active: 1010,
active: 1011,
unable_deposit: 1020,
enable_deposit: 1021,
unable_withdraw: 1030,
enable_withdraw: 1031,
unable_transfer: 1040,
enable_transfer: 1041,
};
const TRIGGER_ACTION_PAIR = {
dis_active: 2010,
active: 2011,
no_hide: 2020,
hide: 2021,
}
const TRIGGER_ACTION_PAIR_ACTIVE_DIS = 2010;
const TRIGGER_ACTION_PAIR_ACTIVE = 2011;
const TRIGGER_ACTION_PAIR_HIDE_DIS = 2020;
const TRIGGER_ACTION_PAIR_HIDE = 2021;
const KEY_PAIR_LIST = 'active_pairList';
export const getCoinTypeUnTriggers = async function () {
let unTriggeredList: any = [];
try {
unTriggeredList = await systemTrigger.prototype.findAll({
where: {
trigger_type: TRIGGER_TYPE_COIN,
status: TRIGGER_STATUS_UN_TRIGGER,
},
raw: true,
});
}
catch (e) {
console.log('get coin_type unTrigger items fail:', e);
}
return unTriggeredList;
}
export const getExPairUnTriggers = async function () {
let unTriggeredList: any = [];
try {
unTriggeredList = await systemTrigger.prototype.findAll({
where: {
trigger_type: TRIGGER_TYPE_EX_PAIR,
status: TRIGGER_STATUS_UN_TRIGGER,
},
raw: true,
});
}
catch (e) {
console.log('get ex_pair unTrigger items fail:', e);
}
return unTriggeredList;
}
export const doExPairTrigger = async function (trigId: any, ex_pair: any, action: any) {
let rtn:any = false;
try {
//TODO:目前交易对 没有激活 隐藏相关字段了 之后有的话 再补充
//let pair = await exPair.prototype.findOne({ where: { pair: ex_pair }, raw: true });
let pair = null;
if (!pair) {
//交易对不存在,标记触发失败
await systemTrigger.prototype.update({ status: TRIGGER_STATUS_FAIL }, { where: { id: trigId, status: 0 } });
rtn = false;
}
else {
let target_value = {};
switch (action) {
case TRIGGER_ACTION_PAIR.dis_active:
target_value = { is_active: 0 };
break;
case TRIGGER_ACTION_PAIR.active:
target_value = { is_active: 1 };
break;
case TRIGGER_ACTION_PAIR.no_hide:
target_value = { is_hide: 0 };
break;
case TRIGGER_ACTION_PAIR.hide:
target_value = { is_hide: 1 };
break
default:
await systemTrigger.prototype.update({ status: TRIGGER_STATUS_FAIL }, { where: { id: trigId, status: 0 } });
rtn = false;
return rtn;
}
//操作ex_pair 和 system_trigger
let t;
try {
console.log('start transaction');
t = await ormDB.transaction();
//TODO: 目前交易对 没有激活 隐藏相关字段了 之后有的话 再补充
//await exPair.prototype.update(target_value, { where: { pair: ex_pair }, transaction: t });
await systemTrigger.prototype.update({ status: TRIGGER_STATUS_SUCCESS }, { where: { id: trigId, status: 0 }, transaction: t });
await t.commit();
rtn = true;
}
catch (e) {
console.log('transaction fail', e);
if (t) {
t.rollback();
}
rtn = false;
}
}
}
catch (e) {
console.error('doExPairTrigger:', e);
}
return rtn;
}
export const doCoinTypeTrigger = async function (trigId: any, coinSymbol: any, action: any) {
let rtn = false;
try {
let symbol = await coinType.prototype.findOne({ where: { symbol: coinSymbol }, raw: true });
if (!symbol) {
//币种不存在
await systemTrigger.prototype.update({ status: TRIGGER_STATUS_FAIL }, { where: { id: trigId, status: 0 } });
rtn = false;
}
else {
let target_value = {};
switch (action) {
case TRIGGER_ACTION_COIN_TYPE.dis_active:
target_value = { is_active: 0 };
break;
case TRIGGER_ACTION_COIN_TYPE.active:
target_value = { is_active: 1 };
break;
case TRIGGER_ACTION_COIN_TYPE.unable_deposit:
target_value = { enable_deposit: 0 };
break;
case TRIGGER_ACTION_COIN_TYPE.enable_deposit:
target_value = { enable_deposit: 1 };
break;
case TRIGGER_ACTION_COIN_TYPE.unable_withdraw:
target_value = { enable_withdraw: 0 };
break;
case TRIGGER_ACTION_COIN_TYPE.enable_withdraw:
target_value = { enable_withdraw: 1 };
break;
case TRIGGER_ACTION_COIN_TYPE.unable_transfer:
target_value = { enable_transfer: 0 };
break;
case TRIGGER_ACTION_COIN_TYPE.enable_transfer:
target_value = { enable_transfer: 1 };
break;
}
//操作ex_pair 和 system_trigger
let t;
try {
console.log('start transaction');
t = await ormDB.transaction();
await coinType.prototype.update(target_value, { where: { symbol: coinSymbol }, transaction: t });
await systemTrigger.prototype.update({ status: TRIGGER_STATUS_SUCCESS }, { where: { id: trigId, status: 0 }, transaction: t });
await t.commit();
rtn = true;
}
catch (e) {
console.log('transaction fail', e);
if (t) {
t.rollback();
}
rtn = false;
}
}
}
catch (e) {
console.error('doCoinTypeTrigger fail:', e);
}
return rtn;
}
/**
* 更新redis active_pairList
*/
export const updateRedisPairs = async function () {
console.log('updateRedisPairs');
try {
//TODO:没有了
//let list = await exPair.prototype.findAll({ where: { is_active: 1 } });
// redisUtilsCommon.writeSync(KEY_PAIR_LIST, JSON.stringify(list));
}
catch (e) {
console.error(e);
}
}
...@@ -5,7 +5,7 @@ const schedule = require('node-schedule'); ...@@ -5,7 +5,7 @@ const schedule = require('node-schedule');
let { logger, datetimeUtils } = require('@madex/ex-js-public'); let { logger, datetimeUtils } = require('@madex/ex-js-public');
import { spotPairs, ormDB, coinType,contractPairs } from "@madex/ex-ts-dao"; import { spotPairs, ormDB, coinType,contractPairs } from "@madex/ex-ts-dao";
import { getPairFromCore, getCoinFromCore } from '../src/utils/coreSystemUtils' import { getPairFromCore, getCoinFromCore } from '../../src/utils/coreSystemUtils'
let running = false; let running = false;
......
import {
ormDB,
userInfoSon,
feeRateBaseCoinContractLog,
contractPairs
} from "@madex/ex-ts-dao";
import { FEE_RATE_LOG_STATUS } from "../../src/constant/feeRateLogConst";
import { changeUserContractFee, isWhiteListUser } from "../model/task.fee.rate.log.model";
const schedule = require('node-schedule');
const { logger, daoType } = require('@madex/ex-js-public');
let fee_rate_base_coin_contract_log = feeRateBaseCoinContractLog.prototype;
let feeRateCheckStatus = FEE_RATE_LOG_STATUS;
let user_info_son = userInfoSon.prototype;
let Op = ormDB.Op;
const oneHour = 1000 * 60 * 60;
const oneDay = oneHour * 24;
const oneMonth = oneDay * 30;
let inJob = false;
let limit = 3000;
/**
* 注意:
* fee_rate_spot_log
* fee_rate_contract_log
* fee_rate_base_coin_contract_log
* 相关表中不支持 all 或 ALL 交易对
* 管理后台配置用户费率的 all 交易对也是分多个交易对来处理的
* 即(common_user_fee_setting 中的 all 分多个交易对 设置到 fee_rate_log 表中)
*/
let setFeeRateJob = schedule.scheduleJob('*/30 * * * * *', function () {
if (inJob) {
return;
}
inJob = true;
doJob().catch(err => {
logger.warn('setFeeRateJob', err);
}).then(() => {
inJob = false;
});
});
let setDefaultRun = false;
let setExpiredDefaultJob = schedule.scheduleJob('*/5 * * * *', function () {
logger.info(' base coin contract setExpiredDefaultJob run ', new Date().toISOString());
if (setDefaultRun) {
return;
}
setDefaultRun = true;
setExpiredDefault().then(res => {
setDefaultRun = false;
}).catch(err => {
setDefaultRun = false;
logger.warn('base coin contract setFeeRateJob', err);
})
});
let doJob = async function () {
let ctm = new Date();
let dblogs = await fee_rate_base_coin_contract_log.findAll({
where: {
is_check: 0,
beginAt: { [Op.lte]: ctm },
expireAt: { [Op.gte]: ctm },
taker_fee: { [Op.gte]: 0.0002 },
},
limit: limit,
raw: true,
});
for (let i = 0; i < dblogs.length; i++) {
if (await isWhiteListUser(dblogs[i].user_id) && dblogs[i].comment && dblogs[i].comment.indexOf('到期') != -1) {
continue;
}
if (Number(dblogs[i].maker_fee) < 0 && (Math.abs(Number(dblogs[i].maker_fee)) > Math.abs(Number(dblogs[i].taker_fee)))) {
continue;
}
await changeOneFee(dblogs[i]);
}
await removeOldLog();
};
let changeOneFee = async function (dblog) {
let transaction;
return changeUserContractFee(dblog.user_id, dblog.pair, dblog.fee_model, dblog.maker_fee, dblog.taker_fee, dblog.id
).then(async res => {
if (!res) {
throw 'changeUserFee fail';
}
let dbsons = await user_info_son.findAll({
attributes: ['user_id', 'type'],
where: {
father_id: dblog.user_id,
// status: userInfoSon.STATUS.NORMAL, // 量化交易内部创建的账号需要变更手续费;
},
raw: true,
});
let son_fee_rate: any = [];
for (let i = 0; i < dbsons.length; i++) {
let son = dbsons[i];
son_fee_rate.push({
user_id: son.user_id,
pair: dblog.pair,
fee_model: dblog.fee_model,
maker_fee: dblog.maker_fee,
taker_fee: dblog.taker_fee,
beginAt: new Date(),
expireAt: dblog.expireAt,
is_check: feeRateCheckStatus.CHECK_STATUS_UNCHECK,
comment: '继承父账户费率',
});
}
transaction = await ormDB.transaction();
await fee_rate_base_coin_contract_log.update({ // 将当前生效中的值置为过期
is_check: feeRateCheckStatus.CHECK_STATUS_ACTIVE_OVER,
}, {
where: {
user_id: dblog.user_id,
pair: dblog.pair,
is_check: feeRateCheckStatus.CHECK_STATUS_ACTIVE,
},
transaction: transaction,
});
await fee_rate_base_coin_contract_log.update({
is_check: feeRateCheckStatus.CHECK_STATUS_ACTIVE,
}, {
where: {
id: dblog.id,
user_id: dblog.user_id,
pair: dblog.pair,
is_check: feeRateCheckStatus.CHECK_STATUS_UNCHECK,
},
transaction: transaction,
});
if (son_fee_rate.length > 0) {
await fee_rate_base_coin_contract_log.bulkCreate(son_fee_rate, {
transaction: transaction,
});
}
await transaction.commit();
transaction = null;
}).catch(async err => {
if (transaction) {
await transaction.rollback();
transaction = null;
}
logger.warn('base.coin.setFeeRateJob.changeOneFee', dblog, err);
});
};
let removeOldLog = async function () {
let ctm = Date.now();
let etm = new Date(ctm - 1000 * 60 * 60 * 24 * 31);
await fee_rate_base_coin_contract_log.destroy({
where: {
is_check: {
[Op.in]: [
feeRateCheckStatus.CHECK_STATUS_ACTIVE_OVER,
feeRateCheckStatus.CHECK_STATUS_DELETED,
]
},
updatedAt: { [Op.lt]: etm },
}
});
};
// 过期费率处理
async function setExpiredDefault() {
let comment = '费率到期系统自动调整为基础费率';
let ctm = new Date(Date.now() - oneDay); // 已经过期;
let expirdFees = await fee_rate_base_coin_contract_log.findAll({
attributes: ['user_id', 'pair', 'fee_model', 'maker_fee', 'taker_fee'],
where: {
is_check: feeRateCheckStatus.CHECK_STATUS_ACTIVE, // 正在生效中的
expireAt: { [Op.lte]: ctm },
},
limit: 500, // 后边处理插入时可以单次插入
raw: true,
});
if (expirdFees.length == 0) return;
let expiredUsers: any = [];
for (let i = 0; i < expirdFees.length; i++) {
expiredUsers.push(expirdFees[i].user_id);
}
let uncheckCounts = await fee_rate_base_coin_contract_log.findAll({
attributes: [[ormDB.literal('count(1)'), 'amount'], 'user_id'],
where: {
user_id: expiredUsers,
is_check: feeRateCheckStatus.CHECK_STATUS_UNCHECK,
beginAt: { [Op.lte]: new Date() },
comment,
},
raw: true,
group: ['user_id'],
});
let unCheckCountObj = {};
for (let i = 0; i < uncheckCounts.length; i++) {
let { user_id, amount } = uncheckCounts[i];
unCheckCountObj[user_id] = amount;
}
let defaultPairFee = await contractPairs.prototype.findAll({
attributes: ['taker_fee', 'maker_fee', 'symbol'],
where: {
status: 2
},
raw: true,
});
let defaultFeeObj = {}, max_maker_rate = 0.0004, max_taker_rate = 0.0006; // 2020.5.9
for (let i = 0; i < defaultPairFee.length; i++) {
let { symbol, maker_fee, taker_fee } = defaultPairFee[i];
defaultFeeObj[symbol] = defaultPairFee[i];
if (max_maker_rate < maker_fee) {
max_maker_rate = maker_fee;
}
if (max_taker_rate < taker_fee) {
max_taker_rate = taker_fee;
}
}
let newFeeArr: any = [];
let beginAt = new Date();
for (let i = 0; i < expirdFees.length; i++) {
let { pair, fee_model, user_id, maker_fee: before_maker_fee, taker_fee: before_taker_fee } = expirdFees[i];
if (await isWhiteListUser(user_id)) {
continue;
}
let new_maker_fee = max_maker_rate, new_taker_fee = max_taker_rate;
if (unCheckCountObj[user_id] > 0) { // 已经存在
continue;
}
if (defaultFeeObj[pair]) {
let { maker_fee, taker_fee } = defaultFeeObj[pair];
new_maker_fee = maker_fee;
new_taker_fee = taker_fee;
if (new_maker_fee === before_maker_fee && new_taker_fee === before_taker_fee) {
continue
}
}
newFeeArr.push({
user_id,
pair: pair,
fee_model,
maker_fee: new_maker_fee,
taker_fee: new_taker_fee,
beginAt: beginAt,
expireAt: new Date(beginAt.getTime() + oneMonth),
is_check: feeRateCheckStatus.CHECK_STATUS_UNCHECK,
comment,
});
}
// 如果有活动,采用活动的费率
if (newFeeArr.length > 0) {
let trans: any;
try {
trans = await ormDB.transaction();
await fee_rate_base_coin_contract_log.update({
is_check: feeRateCheckStatus.CHECK_STATUS_ACTIVE_OVER,
}, {
where: {
user_id: expiredUsers,
is_check: feeRateCheckStatus.CHECK_STATUS_ACTIVE, // 正在生效中的
expireAt: { [Op.lte]: ctm },
},
transaction: trans,
});
await fee_rate_base_coin_contract_log.bulkCreate(newFeeArr, {
transaction: trans,
});
await trans.commit();
trans = null;
}
catch (error) {
if (trans) {
trans.rollback();
}
}
}
}
import {
ormDB,
userInfoSon,
feeRateContractLog,
contractPairs
} from "@madex/ex-ts-dao";
import { FEE_RATE_LOG_STATUS } from "../../src/constant/feeRateLogConst";
import { changeUserContractFee, isWhiteListUser } from "../model/task.fee.rate.log.model";
const schedule = require('node-schedule');
const { logger, daoType } = require('@madex/ex-js-public');
let fee_rate_contract_log = feeRateContractLog.prototype;
let feeRateCheckStatus = FEE_RATE_LOG_STATUS;
let user_info_son = userInfoSon.prototype;
let Op = ormDB.Op;
const oneHour = 1000 * 60 * 60;
const oneDay = oneHour * 24;
const oneMonth = oneDay * 30;
let inJob = false;
let limit = 3000;
/**
* 注意:
* fee_rate_spot_log
* fee_rate_contract_log
* fee_rate_base_coin_contract_log
* 相关表中不支持 all 或 ALL 交易对
* 管理后台配置用户费率的 all 交易对也是分多个交易对来处理的
* 即(common_user_fee_setting 中的 all 分多个交易对 设置到 fee_rate_log 表中)
*/
let setFeeRateJob = schedule.scheduleJob('*/30 * * * * *', function () {
if (inJob) {
return;
}
inJob = true;
doJob().catch(err => {
logger.warn('setFeeRateJob', err);
}).then(() => {
inJob = false;
});
});
let setDefaultRun = false;
let setExpiredDefaultJob = schedule.scheduleJob('*/5 * * * *', function () {
logger.info(' contract setExpiredDefaultJob run ', new Date().toISOString());
if (setDefaultRun) {
return;
}
setDefaultRun = true;
setExpiredDefault().then(res => {
setDefaultRun = false;
}).catch(err => {
setDefaultRun = false;
logger.warn('contract setFeeRateJob', err);
})
});
let doJob = async function () {
let ctm = new Date();
let dblogs = await fee_rate_contract_log.findAll({
where: {
is_check: 0,
beginAt: { [Op.lte]: ctm },
expireAt: { [Op.gte]: ctm },
},
limit: limit,
raw: true,
});
for (let i = 0; i < dblogs.length; i++) {
if (await isWhiteListUser(dblogs[i].user_id) && dblogs[i].comment && dblogs[i].comment.indexOf('到期') != -1) {
continue;
}
if (Number(dblogs[i].maker_fee) < 0 && (Math.abs(Number(dblogs[i].maker_fee)) > Math.abs(Number(dblogs[i].taker_fee)))) {
continue;
}
await changeOneFee(dblogs[i]);
}
await removeOldLog();
};
let changeOneFee = async function (dblog) {
let transaction;
return changeUserContractFee(dblog.user_id, dblog.pair, dblog.fee_model, dblog.maker_fee, dblog.taker_fee, dblog.id
).then(async res => {
if (!res) {
throw 'changeUserFee fail';
}
let dbsons = await user_info_son.findAll({
attributes: ['user_id', 'type'],
where: {
father_id: dblog.user_id,
// status: userInfoSon.STATUS.NORMAL, // 量化交易内部创建的账号需要变更手续费;
},
raw: true,
});
let son_fee_rate: any = [];
for (let i = 0; i < dbsons.length; i++) {
let son = dbsons[i];
son_fee_rate.push({
user_id: son.user_id,
pair: dblog.pair,
fee_model: dblog.fee_model,
maker_fee: dblog.maker_fee,
taker_fee: dblog.taker_fee,
beginAt: new Date(),
expireAt: dblog.expireAt,
is_check: feeRateCheckStatus.CHECK_STATUS_UNCHECK,
comment: '继承父账户费率',
});
}
transaction = await ormDB.transaction();
await fee_rate_contract_log.update({ // 将当前生效中的值置为过期
is_check: feeRateCheckStatus.CHECK_STATUS_ACTIVE_OVER,
}, {
where: {
user_id: dblog.user_id,
pair: dblog.pair,
is_check: feeRateCheckStatus.CHECK_STATUS_ACTIVE,
},
transaction: transaction,
});
await fee_rate_contract_log.update({
is_check: feeRateCheckStatus.CHECK_STATUS_ACTIVE,
}, {
where: {
id: dblog.id,
user_id: dblog.user_id,
pair: dblog.pair,
is_check: feeRateCheckStatus.CHECK_STATUS_UNCHECK,
},
transaction: transaction,
});
if (son_fee_rate.length > 0) {
await fee_rate_contract_log.bulkCreate(son_fee_rate, {
transaction: transaction,
});
}
await transaction.commit();
transaction = null;
}).catch(async err => {
if (transaction) {
await transaction.rollback();
transaction = null;
}
logger.warn('setFeeRateJob.changeOneFee', dblog, err);
});
};
let removeOldLog = async function () {
let ctm = Date.now();
let etm = new Date(ctm - 1000 * 60 * 60 * 24 * 31);
await fee_rate_contract_log.destroy({
where: {
is_check: {
[Op.in]: [
feeRateCheckStatus.CHECK_STATUS_ACTIVE_OVER,
feeRateCheckStatus.CHECK_STATUS_DELETED,
]
},
updatedAt: { [Op.lt]: etm },
}
});
};
// 过期费率处理
async function setExpiredDefault() {
let comment = '费率到期系统自动调整为基础费率';
let ctm = new Date(Date.now() - oneDay); // 已经过期;
let expirdFees = await fee_rate_contract_log.findAll({
attributes: ['user_id', 'pair', 'fee_model', 'maker_fee', 'taker_fee'],
where: {
is_check: feeRateCheckStatus.CHECK_STATUS_ACTIVE, // 正在生效中的
expireAt: { [Op.lte]: ctm },
},
limit: 500, // 后边处理插入时可以单次插入
raw: true,
});
if (expirdFees.length == 0) return;
let expiredUsers: any = [];
for (let i = 0; i < expirdFees.length; i++) {
expiredUsers.push(expirdFees[i].user_id);
}
let uncheckCounts = await fee_rate_contract_log.findAll({
attributes: [[ormDB.literal('count(1)'), 'amount'], 'user_id'],
where: {
user_id: expiredUsers,
is_check: feeRateCheckStatus.CHECK_STATUS_UNCHECK,
beginAt: { [Op.lte]: new Date() },
comment,
},
raw: true,
group: ['user_id'],
});
let unCheckCountObj = {};
for (let i = 0; i < uncheckCounts.length; i++) {
let { user_id, amount } = uncheckCounts[i];
unCheckCountObj[user_id] = amount;
}
let defaultPairFee = await contractPairs.prototype.findAll({
attributes: ['taker_fee', 'maker_fee', 'symbol'],
where: {
status: 2
},
raw: true,
});
let defaultFeeObj = {}, max_maker_rate = 0.0004, max_taker_rate = 0.0006; // 2020.5.9
for (let i = 0; i < defaultPairFee.length; i++) {
let { symbol, maker_fee, taker_fee } = defaultPairFee[i];
defaultFeeObj[symbol] = defaultPairFee[i];
if (max_maker_rate < maker_fee) {
max_maker_rate = maker_fee;
}
if (max_taker_rate < taker_fee) {
max_taker_rate = taker_fee;
}
}
let newFeeArr: any = [];
let beginAt = new Date();
for (let i = 0; i < expirdFees.length; i++) {
let { pair, fee_model, user_id, maker_fee: before_maker_fee, taker_fee: before_taker_fee } = expirdFees[i];
let new_maker_fee = max_maker_rate, new_taker_fee = max_taker_rate;
if (await isWhiteListUser(user_id)) {
continue;
}
if (unCheckCountObj[user_id] > 0) { // 已经存在
continue;
}
if (defaultFeeObj[pair]) {
let { maker_fee, taker_fee } = defaultFeeObj[pair];
new_maker_fee = maker_fee;
new_taker_fee = taker_fee;
if (new_maker_fee === before_maker_fee && new_taker_fee === before_taker_fee) {
continue
}
}
newFeeArr.push({
user_id,
pair: pair,
fee_model,
maker_fee: new_maker_fee,
taker_fee: new_taker_fee,
beginAt: beginAt,
expireAt: new Date(beginAt.getTime() + oneMonth),
is_check: feeRateCheckStatus.CHECK_STATUS_UNCHECK,
comment,
});
}
// 如果有活动,采用活动的费率
if (newFeeArr.length > 0) {
let trans: any;
try {
trans = await ormDB.transaction();
await fee_rate_contract_log.update({
is_check: feeRateCheckStatus.CHECK_STATUS_ACTIVE_OVER,
}, {
where: {
user_id: expiredUsers,
is_check: feeRateCheckStatus.CHECK_STATUS_ACTIVE, // 正在生效中的
expireAt: { [Op.lte]: ctm },
},
transaction: trans,
});
await fee_rate_contract_log.bulkCreate(newFeeArr, {
transaction: trans,
});
await trans.commit();
trans = null;
}
catch (error) {
if (trans) {
trans.rollback();
}
}
}
}
/**
* 原文件:b024 - task_fee_rate_spot_log.js
*/
import { ormDB, userInfoSon, feeRateSpotLog, spotPairs } from "@madex/ex-ts-dao";
import { FEE_RATE_LOG_STATUS } from "../../src/constant/feeRateLogConst";
import { changeUserSpotFee, isWhiteListUser } from "../model/task.fee.rate.log.model";
let { redisUtilsCommon: RedisClient, } = require('@madex/ex-js-common');
const schedule = require('node-schedule');
const logger = require('@madex/ex-js-public').logger;
let user_info_son = userInfoSon.prototype;
let fee_rate_spot_log = feeRateSpotLog.prototype;
let feeRateCheckStatus = FEE_RATE_LOG_STATUS;
let Op = ormDB.Op;
const oneHour = 1000 * 60 * 60;
const oneDay = oneHour * 24;
const oneMonth = oneDay * 30;
let inJob = false;
let limit = 3000;
/**
* 注意:
* fee_rate_spot_log
* fee_rate_contract_log
* fee_rate_base_coin_contract_log
* 相关表中不支持all 或 ALL 交易对
* 管理后台配置用户费率的 all 交易对也是分多个交易对来处理的
* 即(common_user_fee_setting 中的 all 分多个交易对 设置到 fee_rate_log 表中)
*/
let setFeeRateJob = schedule.scheduleJob('*/30 * * * * *', function () {
if (inJob) {
return;
}
inJob = true;
doJob().catch(err => {
logger.warn('setFeeRateJob', err);
}).then(() => {
inJob = false;
});
});
let setDefaultRun = false;
let setExpiredDefaultJob = schedule.scheduleJob('*/5 * * * *', function () {
logger.info(' spot setExpiredDefaultJob run ', new Date().toISOString());
if (setDefaultRun) {
return;
}
setDefaultRun = true;
setExpiredDefault().then(res => {
setDefaultRun = false;
}).catch(err => {
setDefaultRun = false;
logger.warn('spot setFeeRateJob', err);
})
});
let doJob = async function () {
let ctm = new Date();
let dblogs = await fee_rate_spot_log.findAll({
where: {
is_check: 0,
beginAt: { [Op.lte]: ctm },
expireAt: { [Op.gte]: ctm },
taker_fee: { [Op.gte]: 0 },
},
limit: limit,
raw: true,
});
for (let i = 0; i < dblogs.length; i++) {
if (Number(dblogs[i].maker_fee) < 0 && (Math.abs(Number(dblogs[i].maker_fee)) > Math.abs(Number(dblogs[i].taker_fee)))) {
continue;
}
await changeOneFee(dblogs[i]);
}
await removeOldLog();
};
let changeOneFee = async function (dblog) {
let transaction;
return changeUserSpotFee(
dblog.user_id, dblog.pair, dblog.fee_model, dblog.maker_fee, dblog.taker_fee, dblog.id
).then(async res => {
if (!res) {
throw 'changeUserFee fail';
}
let dbsons = await user_info_son.findAll({
attributes: ['user_id'],
where: {
father_id: dblog.user_id,
},
raw: true,
});
let son_fee_rate: any = [];
for (let i = 0; i < dbsons.length; i++) {
let son = dbsons[i];
son_fee_rate.push({
user_id: son.user_id,
pair: dblog.pair,
fee_model: dblog.fee_model,
maker_fee: dblog.maker_fee,
taker_fee: dblog.taker_fee,
beginAt: new Date(),
expireAt: dblog.expireAt,
is_check: feeRateCheckStatus.CHECK_STATUS_UNCHECK,
comment: '继承父账户费率',
});
}
await storeUserSpotFeeRedis(dblog.user_id, dblog.pair, dblog.taker_fee, dblog.maker_fee);
transaction = await ormDB.transaction();
await fee_rate_spot_log.update({ // 将当前生效中的值置为过期
is_check: feeRateCheckStatus.CHECK_STATUS_ACTIVE_OVER,
}, {
where: {
user_id: dblog.user_id,
pair: dblog.pair,
is_check: feeRateCheckStatus.CHECK_STATUS_ACTIVE,
},
transaction: transaction,
});
await fee_rate_spot_log.update({
is_check: feeRateCheckStatus.CHECK_STATUS_ACTIVE,
}, {
where: {
id: dblog.id,
user_id: dblog.user_id,
pair: dblog.pair,
is_check: feeRateCheckStatus.CHECK_STATUS_UNCHECK,
},
transaction: transaction,
});
if (son_fee_rate.length > 0) {
await fee_rate_spot_log.bulkCreate(son_fee_rate, {
transaction: transaction,
});
}
await transaction.commit();
transaction = null;
}).catch(async err => {
if (transaction) {
await transaction.rollback();
transaction = null;
}
if (err == 3000) {
await fee_rate_spot_log.update({
is_check: feeRateCheckStatus.CHECK_STATUS_ACTIVE_OVER,
}, {
where: {
id: dblog.id,
user_id: dblog.user_id,
pair: dblog.pair,
is_check: feeRateCheckStatus.CHECK_STATUS_UNCHECK,
},
});
}
logger.warn('setFeeRateJob.changeOneFee', dblog, err);
});
};
let removeOldLog = async function () {
let ctm = Date.now();
let etm = new Date(ctm - 1000 * 60 * 60 * 24 * 31);
await fee_rate_spot_log.destroy({
where: {
is_check: {
[Op.in]: [
feeRateCheckStatus.CHECK_STATUS_ACTIVE_OVER,
feeRateCheckStatus.CHECK_STATUS_DELETED,
]
},
updatedAt: { [Op.lt]: etm },
}
});
};
async function storeUserSpotFeeRedis(user_id, pair, taker_fee, maker_fee) {
let redisKey = 'user_spot_fee_rate_' + user_id;
let res = await RedisClient.getSync(redisKey);
if (!res) {
res = {};
}
res[pair] = {
taker: taker_fee,
maker: maker_fee
}
await RedisClient.writeSync(redisKey, JSON.stringify(res));
}
// 过期费率处理
async function setExpiredDefault() {
let comment = '费率到期系统自动调整为基础费率';
let ctm = new Date(Date.now() - oneDay); // 已经过期一段时间;
let expirdFees = await fee_rate_spot_log.findAll({
attributes: ['user_id', 'pair', 'fee_model', 'maker_fee', 'taker_fee'],
where: {
is_check: feeRateCheckStatus.CHECK_STATUS_ACTIVE, // 正在生效中的
expireAt: { [Op.lte]: ctm },
},
limit: 500, // 后边处理插入时可以单次插入
raw: true,
});
if (expirdFees.length == 0) return;
let expiredUsers: any = [];
for (let i = 0; i < expirdFees.length; i++) {
expiredUsers.push(expirdFees[i].user_id);
}
let uncheckCounts = await fee_rate_spot_log.findAll({
attributes: [[ormDB.literal('count(1)'), 'amount'], 'user_id'],
where: {
user_id: expiredUsers,
is_check: feeRateCheckStatus.CHECK_STATUS_UNCHECK,
beginAt: { [Op.lte]: new Date() },
comment,
},
raw: true,
group: ['user_id'],
});
let unCheckCountObj = {};
for (let i = 0; i < uncheckCounts.length; i++) {
let { user_id, amount } = uncheckCounts[i];
unCheckCountObj[user_id] = amount;
}
let defaultPairFee = await spotPairs.prototype.findAll({
attributes: ['maker_rate', 'taker_rate', 'symbol'],
where: {
status: 2
},
raw: true,
});
let defaultFeeObj = {}, max_maker_rate = 0.001, max_taker_rate = 0.002; // 2020.5.9
let activePairs: any = [];
for (let i = 0; i < defaultPairFee.length; i++) {
let { symbol, maker_fee, taker_fee } = defaultPairFee[i];
activePairs.push(symbol);
defaultFeeObj[symbol] = defaultPairFee[i];
if (max_maker_rate < maker_fee) {
max_maker_rate = maker_fee;
}
if (max_taker_rate < taker_fee) {
max_taker_rate = taker_fee;
}
}
let newFeeArr: any = [];
let beginAt = new Date();
let expiredPairs: any = [];
for (let i = 0; i < expirdFees.length; i++) {
let { pair, fee_model, user_id, maker_fee: before_maker_fee, taker_fee: before_taker_fee } = expirdFees[i];
if (await isWhiteListUser(user_id)) {
continue;
}
if (!activePairs.includes(pair)) {
expiredPairs.push(pair);
continue;
}
if (unCheckCountObj[user_id] > 0) { // 已经存在
continue;
}
let new_maker_fee = max_maker_rate, new_taker_fee = max_taker_rate;
if (defaultFeeObj[pair]) {
let { maker_rate, taker_rate } = defaultFeeObj[pair];
new_maker_fee = maker_rate;
new_taker_fee = taker_rate;
if (new_maker_fee === before_maker_fee && new_taker_fee === before_taker_fee) {
continue
}
}
newFeeArr.push({
user_id,
pair: pair,
fee_model,
maker_fee: new_maker_fee,
taker_fee: new_taker_fee,
beginAt: beginAt,
expireAt: new Date(beginAt.getTime() + oneMonth),
is_check: feeRateCheckStatus.CHECK_STATUS_UNCHECK,
comment: comment,
});
}
if (expiredPairs.length > 0) { // 下线交易对处理
await fee_rate_spot_log.update({
is_check: feeRateCheckStatus.CHECK_STATUS_ACTIVE_OVER,
}, {
where: {
pair: expiredPairs,
}
})
}
if (newFeeArr.length > 0) {
let trans: any;
try {
trans = await ormDB.transaction();
await fee_rate_spot_log.update({
is_check: feeRateCheckStatus.CHECK_STATUS_ACTIVE_OVER,
}, {
where: {
user_id: expiredUsers,
is_check: feeRateCheckStatus.CHECK_STATUS_ACTIVE, // 正在生效中的
expireAt: { [Op.lte]: ctm },
},
transaction: trans,
});
await fee_rate_spot_log.bulkCreate(newFeeArr, {
transaction: trans,
});
await trans.commit();
trans = null;
}
catch (error) {
if (trans) {
trans.rollback();
}
}
}
}
/* ======================================================================
* 市商、普通用户、KOL费率设置纪录状态更新。
* ====================================================================== */
import { commonUserFeeSettingStatusUpdateService } from "../service/task.fee.setting.status.update.service";
let schedule = require('node-schedule');
let { logger } = require('@madex/ex-js-public');
let userSettingUpdateRunning = false;
/**
* 市商、普通用户、KOL 费率设置纪录状态更新。
* 每10分钟更新一次。
*/
let userSettingStatusUpdate = schedule.scheduleJob('0 */10 * * * *', async function () {
try {
logger.info('task_fee_setting_status_update userSettingStatusUpdate start');
if (!userSettingUpdateRunning) {
userSettingUpdateRunning = true;
await commonUserFeeSettingStatusUpdateService();
userSettingUpdateRunning = false;
}
}
catch (error) {
userSettingUpdateRunning = false;
logger.warn('task_fee_setting_status_update userSettingStatusUpdate error', error);
}
});
\ No newline at end of file
import { statisProjectMakerDeals } from "../service/task.market.maker.statis.service";
const schedule = require('node-schedule');
const logger = require('@madex/ex-js-public').logger;
let subModel = {};
module.exports = subModel;
// 统计项目方做市商成交量信息,并设置费率,
let inJob = false;
let setFeeRateJob = schedule.scheduleJob('0 10 0 * * *', async function () {
if (inJob) {
return;
}
inJob = true;
try {
await statisProjectMakerDeals();
inJob = false;
} catch (error) {
inJob = false;
logger.warn(' 统计项目方做市商成交量 error', error);
}
});
'use strict';
const schedule = require('node-schedule');
const config = require('../../config');
import * as triggerSvr from "../service/task.system.trigger.service";
const AHEAD_TIME_ALLOWED = 2000; //允许提前时间
import * as RobotUtil from "../../src/utils/robotUtils";
/**
* 每5秒监控一次交易对设置变化
*/
let jobTrigger = function () {
schedule.scheduleJob('*/2 * * * * *', async function () {
try {
let triggerList = await triggerSvr.getExPairUnTriggers();
let nowTime = new Date();
console.log('jobExPairTrigger trigger at ', nowTime);
let hasTriggered: any = false;
for (let item of triggerList) {
if (new Date(item.trigger_time).getTime() - AHEAD_TIME_ALLOWED <= nowTime.getTime()) {
let rtn = await triggerSvr.doExPairTrigger(item.id, item.trigger_symbol, item.trigger_action);
hasTriggered |= rtn;
RobotUtil.sendRobotMessage(RobotUtil.ROBOT_KEYS.COMMON_KEY,
`${config.env} 触发交易对更新-${item.trigger_symbol}:${item.trigger_action}--${rtn}`);
}
}
//更新redis交易对信息
if (hasTriggered) {
triggerSvr.updateRedisPairs();
}
}
catch (e) {
console.error('jobExPairTrigger fail:', e);
}
});
/**
* 币种表触发 每分钟触发
*/
schedule.scheduleJob('*/1 * * * *', async function () {
try {
let triggerList = await triggerSvr.getCoinTypeUnTriggers();
let nowTime = new Date();
console.log('jobExPairTrigger trigger at ', nowTime);
for (let item of triggerList) {
if (new Date(item.trigger_time).getTime() - AHEAD_TIME_ALLOWED <= nowTime.getTime()) {
let rtn = await triggerSvr.doCoinTypeTrigger(item.id, item.trigger_symbol, item.trigger_action);
RobotUtil.sendRobotMessage(RobotUtil.ROBOT_KEYS.COMMON_KEY,
`${config.env} 触发币种更新-${item.trigger_symbol}:${item.trigger_action}--${rtn}`);
}
}
}
catch (e) {
console.error('jobExPairTrigger fail:', e);
}
});
}
jobTrigger();
\ No newline at end of file
...@@ -33,3 +33,14 @@ export const ADDRESS_INFO_REDIS_KEY_OBJ = "b029.addressInfo.service.get.obj"; ...@@ -33,3 +33,14 @@ export const ADDRESS_INFO_REDIS_KEY_OBJ = "b029.addressInfo.service.get.obj";
export const APP_SPECIAL_MODEL_REDIS_KEY = "b029.app.sepecial.model.redis.key"; export const APP_SPECIAL_MODEL_REDIS_KEY = "b029.app.sepecial.model.redis.key";
/**
* 返佣时间周期配置
*/
export const REWARD_TIME_PERIOD_REDIS_KEY = "bk_reward_time_period_config";
/**
* Madex 用户的SessionId集合
*/
export const M_SESSION_ID_PREFIX = "session_id.list."
...@@ -202,9 +202,11 @@ async function paramCheck(beginTime: any, expireTime: any, type: number, userId: ...@@ -202,9 +202,11 @@ async function paramCheck(beginTime: any, expireTime: any, type: number, userId:
} }
} }
else if (type == FEE_TYPE.FEE_TYPE_BASE_COIN_CONTRACT) { else if (type == FEE_TYPE.FEE_TYPE_BASE_COIN_CONTRACT) {
if (!await baseCoinCheck(userId)) { //TODO:暂不支持币本位的 因为不知道怎么区分交易对,之后需要再放开即可
throw ErrorCode.PARAM_MISS;
/*if (!await baseCoinCheck(userId)) {
throw ErrorCode.COIN_NO_ASSETS; throw ErrorCode.COIN_NO_ASSETS;
} }*/
} }
} }
...@@ -216,7 +218,6 @@ async function checkMaker(commonUserFeeVO: CommonUserFeeVO) { ...@@ -216,7 +218,6 @@ async function checkMaker(commonUserFeeVO: CommonUserFeeVO) {
} }
//项目方 //项目方
if (userChannel == 2) { if (userChannel == 2) {
//TODO:校验该用户是不是市商
let statisPeriod = commonUserFeeVO.statis_period; let statisPeriod = commonUserFeeVO.statis_period;
let amount_require_usdt = commonUserFeeVO.amount_require_usdt; let amount_require_usdt = commonUserFeeVO.amount_require_usdt;
if (!statisPeriod || Number(statisPeriod) < 0 || Number(statisPeriod) > 30) { if (!statisPeriod || Number(statisPeriod) < 0 || Number(statisPeriod) > 30) {
......
...@@ -90,7 +90,6 @@ export const updateUserEmail = async (req: any, queryVO: QueryVO) => { ...@@ -90,7 +90,6 @@ export const updateUserEmail = async (req: any, queryVO: QueryVO) => {
* @param req * @param req
* @param queryVO * @param queryVO
*/ */
//TODO: 前端需要弹窗选择锁定当前账户 还是 当前账户及其所有子账户
export const lockAccount = async (req: any, queryVO: QueryVO) => { export const lockAccount = async (req: any, queryVO: QueryVO) => {
let func_name = "mUserManageCtrl.lockAccount"; let func_name = "mUserManageCtrl.lockAccount";
try { try {
...@@ -119,7 +118,6 @@ export const lockAccount = async (req: any, queryVO: QueryVO) => { ...@@ -119,7 +118,6 @@ export const lockAccount = async (req: any, queryVO: QueryVO) => {
* @param req * @param req
* @param queryVO * @param queryVO
*/ */
//TODO: 前端需要弹窗选择锁定当前账户 还是 当前账户及其所有子账户
export const unlockAccount = async (req: any, queryVO: QueryVO) => { export const unlockAccount = async (req: any, queryVO: QueryVO) => {
let func_name = "mUserManageCtrl.unlockAccount"; let func_name = "mUserManageCtrl.unlockAccount";
try { try {
......
...@@ -27,7 +27,7 @@ export const list = async (req: any, pageVO: PairApplyPageVO) => { ...@@ -27,7 +27,7 @@ export const list = async (req: any, pageVO: PairApplyPageVO) => {
}; };
/** /**
* TODO:现在查询的是spot_pairs 原来是ex_pair 后期是否需要调整? * TODO:现在没用 之后需要 再确认 现在查询的是spot_pairs 原来是ex_pair 后期是否需要调整?
* 技术部-交易上下线管理-已有交易对列表 * 技术部-交易上下线管理-已有交易对列表
* @param req * @param req
* @param infoVO * @param infoVO
......
import { AppVersionPageVO } from "../service/appVersion.service";
let { logger, Res3Utils, optionalUtils: Optional, apiAssertUtils: ApiAssert, datetimeUtils } = require('@madex/ex-js-public');
import { ErrorCode } from "../../../constant/errorCode";
import { getCurrentUserId } from "../../../utils/aclUserUtils";
import { APP_VERSION_KEY, REWARD_TIME_PERIOD_REDIS_KEY } from "../../../constant/redis-val";
import { addOptLog } from "../service/userOptLog.service";
let { authCommon: AuthCommon, redisUtilsCommon: RedisClient, } = require('@madex/ex-js-common');
let isIp = require('is-ip');
export interface ParamVO {
period_type?: number;// 1:半年;2:一年;3:2年;4:永久;
}
/**
* 时间周期设置
* @param req
* @param authConfigVO
*/
export const set = async (req: any, paramVO: ParamVO) => {
let func_name = "rewardTimePeriod.control.set";
try {
let ip = isIp(req.ip) ? req.ip : '*.*.*.*';
let currentUserId = await getCurrentUserId(req.cookies.session_id);
if (!paramVO.period_type || ![1,2,3,4].includes(Number(paramVO.period_type))) {
throw ErrorCode.PARAM_MISS
}
let key = REWARD_TIME_PERIOD_REDIS_KEY;
await RedisClient.writeSync(key, paramVO.period_type);
//管理后台操作日志
addOptLog(currentUserId, 0, '返佣时间周期设置', ip, `key:${key},value:${paramVO.period_type}`, '返佣时间周期设置');
return Res3Utils.result('ok');
}
catch (e) {
logger.error(`${func_name} error:${e}`);
return Res3Utils.getErrorResult(e);
}
};
/**
* 时间周期配置查询
* @param req
* @param authConfigVO
*/
export const get = async (req: any, paramVO: ParamVO) => {
let func_name = "rewardTimePeriod.control.get";
try {
let key = REWARD_TIME_PERIOD_REDIS_KEY;
let period_type = await RedisClient.getSync(key);
//管理后台操作日志
return Res3Utils.result({
period_type: period_type ? period_type : ""
});
}
catch (e) {
logger.error(`${func_name} error:${e}`);
return Res3Utils.getErrorResult(e);
}
};
...@@ -114,7 +114,10 @@ async function paramValid(systemTriggerVO: SystemTriggerVO) { ...@@ -114,7 +114,10 @@ async function paramValid(systemTriggerVO: SystemTriggerVO) {
} }
} }
else { else {
//TODO:之前查的 ex_pair 现在查询的是 spot_pairs 是否需要补充别的查询合约交易对的逻辑??? //TODO: 这个需要确定下 之前的有 激活 隐藏 开启/关闭充值 开启/关闭提现 开启/关闭划转 现在没有对应的 激活 隐藏对应的字段了
// 之前的 只有 ex_pair 现在现货和合约是分开的 查询的是 spot_pairs 是否需要补充别的查询合约交易对的逻辑???
// 触发活动(coin_type:1xxx -- is_active=0 : 1010,is_active=1 :1011 ,enable_deposit=0:1020,enable_deposit=1:1021, enable_withdraw=0:1030,enable_withdraw=1:1031,enable_transfer=0:1040,enable_transfer=1:1041;
// ex_pair:2xxx -- is_active=0:2010,is_active=1:2011, is_hide=0:2020,is_hide=1:2021)
let dbInfo = await spotPairs.prototype.findOne({ let dbInfo = await spotPairs.prototype.findOne({
where: { where: {
symbol: symbolOrPair symbol: symbolOrPair
......
...@@ -317,7 +317,6 @@ export const saveRole = async (aclRoleVO: AclRoleVO) => { ...@@ -317,7 +317,6 @@ export const saveRole = async (aclRoleVO: AclRoleVO) => {
export const delRole = async (id: number | any, currentUserId: number) => { export const delRole = async (id: number | any, currentUserId: number) => {
//TODO: 此逻辑要不要加
/*if ([1, 2, 3, 4].includes(Number(id))) { /*if ([1, 2, 3, 4].includes(Number(id))) {
throw 'err:固有角色,无法删除' throw 'err:固有角色,无法删除'
}*/ }*/
......
...@@ -7,6 +7,7 @@ import { addCoin2Core } from "../../../utils/coreSystemUtils"; ...@@ -7,6 +7,7 @@ import { addCoin2Core } from "../../../utils/coreSystemUtils";
let _ = require('lodash'); let _ = require('lodash');
let { logger, datetimeUtils } = require('@madex/ex-js-public'); let { logger, datetimeUtils } = require('@madex/ex-js-public');
import * as RobotUtil from "../../../utils/robotUtils";
export interface CoinTypeApplyVO { export interface CoinTypeApplyVO {
...@@ -391,7 +392,6 @@ async function updateApply(id: number, status: number, checker: string, reason: ...@@ -391,7 +392,6 @@ async function updateApply(id: number, status: number, checker: string, reason:
sendMsg(status, symbol); sendMsg(status, symbol);
} }
//TODO:发送lark消息
async function sendMsg(status: number, symbol: string) { async function sendMsg(status: number, symbol: string) {
let content = ""; let content = "";
if (status == APPLY_STATUS.RE_WRITE) { if (status == APPLY_STATUS.RE_WRITE) {
...@@ -420,7 +420,7 @@ async function sendMsg(status: number, symbol: string) { ...@@ -420,7 +420,7 @@ async function sendMsg(status: number, symbol: string) {
} }
if (content) { if (content) {
//TODO:发lark RobotUtil.sendRobotMessage(RobotUtil.ROBOT_KEYS.COMMON_KEY, content);
} }
} }
...@@ -153,31 +153,32 @@ export async function add(commonUserFeeVO: CommonUserFeeVO, currentUserId: any, ...@@ -153,31 +153,32 @@ export async function add(commonUserFeeVO: CommonUserFeeVO, currentUserId: any,
let pair = dbInfo.pair; let pair = dbInfo.pair;
let type = dbInfo.type; let type = dbInfo.type;
let now = new Date(); let now = new Date();
let insertDbOne: any = []; let insertDbList: any = [];
let rateLog = buildSubmitItem(pair, dbInfo, now, dbInfo.user_channel);
let rateLogs = await buildSubmitItems(pair, dbInfo, now, dbInfo.user_channel, type);
//提交到log表 //提交到log表
if (type == FEE_TYPE.FEE_TYPE_SPOT) { if (type == FEE_TYPE.FEE_TYPE_SPOT) {
insertDbOne = await feeRateSpotLog.prototype.create(rateLog, { insertDbList = await feeRateSpotLog.prototype.bulkCreate(rateLogs, {
transaction: tx transaction: tx
}); });
} }
else if (type == FEE_TYPE.FEE_TYPE_BASE_COIN_CONTRACT) {//币本位 else if (type == FEE_TYPE.FEE_TYPE_BASE_COIN_CONTRACT) {//币本位
insertDbOne = await feeRateBaseCoinContractLog.prototype.create(rateLog, { insertDbList = await feeRateBaseCoinContractLog.prototype.bulkCreate(rateLogs, {
transaction: tx transaction: tx
}); });
} }
else {//U本位 else {//U本位
insertDbOne = await feeRateContractLog.prototype.create(rateLog, { insertDbList = await feeRateContractLog.prototype.bulkCreate(rateLogs, {
transaction: tx transaction: tx
}); });
} }
let feeLogId = insertDbOne.id; let ids = insertDbList.map(item => item.id);
await commonUserFeeSetting.prototype.update({ await commonUserFeeSetting.prototype.update({
fee_log_ids: feeLogId, fee_log_ids: ids.toString(),
update_time: new Date() update_time: new Date()
}, { }, {
where: { where: {
...@@ -224,34 +225,34 @@ export async function update(commonUserFeeVO: CommonUserFeeVO, currentUserId: an ...@@ -224,34 +225,34 @@ export async function update(commonUserFeeVO: CommonUserFeeVO, currentUserId: an
let tx; let tx;
try { try {
tx = await ormDB.transaction(); tx = await ormDB.transaction();
let feeLogId: any; let feeLogIds: any;
//这四项修改需要 重新写入 rate_log //这四项修改需要 重新写入 rate_log
if (commonUserFeeVO.maker_fee != dbInfo.maker_fee || commonUserFeeVO.taker_fee != dbInfo.taker_fee if (commonUserFeeVO.maker_fee != dbInfo.maker_fee || commonUserFeeVO.taker_fee != dbInfo.taker_fee
|| commonUserFeeVO.begin_time != dbInfo.begin_time || commonUserFeeVO.expire_time != dbInfo.expire_time) { || commonUserFeeVO.begin_time != dbInfo.begin_time || commonUserFeeVO.expire_time != dbInfo.expire_time) {
let insertDbOne: any; let insertDbList: any;
let rateLog = buildSubmitItem(pair, commonUserFeeVO, new Date(), Number(commonUserFeeVO.user_channel)); let rateLogs = await buildSubmitItems(pair, commonUserFeeVO, new Date(), Number(commonUserFeeVO.user_channel), type);
//提交到log表 //提交到log表
if (type == FEE_TYPE.FEE_TYPE_SPOT) { if (type == FEE_TYPE.FEE_TYPE_SPOT) {
insertDbOne = await feeRateSpotLog.prototype.create(rateLog, { insertDbList = await feeRateSpotLog.prototype.bulkCreate(rateLogs, {
transaction: tx transaction: tx
}); });
} }
else if (type == FEE_TYPE.FEE_TYPE_BASE_COIN_CONTRACT) {//币本位 else if (type == FEE_TYPE.FEE_TYPE_BASE_COIN_CONTRACT) {//币本位
insertDbOne = await feeRateBaseCoinContractLog.prototype.create(rateLog, { insertDbList = await feeRateBaseCoinContractLog.prototype.bulkCreate(rateLogs, {
transaction: tx transaction: tx
}); });
} }
else {//U本位 else {//U本位
insertDbOne = await feeRateContractLog.prototype.create(rateLog, { insertDbList = await feeRateContractLog.prototype.bulkCreate(rateLogs, {
transaction: tx transaction: tx
}); });
} }
feeLogId = insertDbOne.id;
feeLogIds = insertDbList.map(item => item.id);
} }
let dbFeeLogIdsArr = dbInfo.fee_log_ids.split(",");
dbFeeLogIdsArr.push(String(feeLogId));
await commonUserFeeSetting.prototype.update({ await commonUserFeeSetting.prototype.update({
maker_fee: Number(commonUserFeeVO.maker_fee), maker_fee: Number(commonUserFeeVO.maker_fee),
taker_fee: Number(commonUserFeeVO.taker_fee), taker_fee: Number(commonUserFeeVO.taker_fee),
...@@ -263,7 +264,7 @@ export async function update(commonUserFeeVO: CommonUserFeeVO, currentUserId: an ...@@ -263,7 +264,7 @@ export async function update(commonUserFeeVO: CommonUserFeeVO, currentUserId: an
amount_require_usdt: commonUserFeeVO.amount_require_usdt, amount_require_usdt: commonUserFeeVO.amount_require_usdt,
applicant: commonUserFeeVO.applicant, applicant: commonUserFeeVO.applicant,
update_time: new Date(), update_time: new Date(),
fee_log_ids: feeLogId ? dbFeeLogIdsArr.toString() : dbInfo.fee_log_ids, fee_log_ids: feeLogIds ? feeLogIds.toString() : dbInfo.fee_log_ids,
}, { }, {
where: { where: {
id: Number(commonUserFeeVO.id) id: Number(commonUserFeeVO.id)
...@@ -460,32 +461,51 @@ async function getDbFeeSetting(user_id: number | any, type: number | any, user_c ...@@ -460,32 +461,51 @@ async function getDbFeeSetting(user_id: number | any, type: number | any, user_c
return dbInfo; return dbInfo;
} }
function buildSubmitItem(pair: string, dbInfo: any, now: Date, user_channel: number) { async function buildSubmitItems(pair: string, dbInfo: any, now: Date, user_channel: number, type: number) {
let item = {
user_id: dbInfo.user_id, let pairList: any;
pair: pair, if (pair == 'all') {
fee_model: FEE_MODEL_SPOT_DEFAULT, if (type == FEE_TYPE.FEE_TYPE_SPOT) {
maker_fee: dbInfo.maker_fee, pairList = await getAllSpotPairs();
taker_fee: dbInfo.taker_fee, }
beginAt: dbInfo.begin_time, else {
expireAt: dbInfo.expire_time, //TODO:币本位和U本位的交易对怎么区分?
is_check: FEE_RATE_LOG_STATUS.CHECK_STATUS_UNCHECK, pairList = await getAllContractPairs();
comment: "", }
createdAt: now,
updatedAt: now
}
//项目方
if (user_channel == 2) {
item.comment = COMMENT_MAKER_FEE_SUBMIT
}
else if (user_channel == 3) {
item.comment = COMMENT_KOL_FEE_SUBMIT
} }
else { else {
item.comment = COMMENT_USER_FEE_SUBMIT pairList = [pair]
} }
let itemList: any = [];
for (let onePair of pairList) {
let item = {
user_id: dbInfo.user_id,
pair: onePair,
fee_model: FEE_MODEL_SPOT_DEFAULT,
maker_fee: dbInfo.maker_fee,
taker_fee: dbInfo.taker_fee,
beginAt: dbInfo.begin_time,
expireAt: dbInfo.expire_time,
is_check: FEE_RATE_LOG_STATUS.CHECK_STATUS_UNCHECK,
comment: "",
createdAt: now,
updatedAt: now
}
//项目方
if (user_channel == 2) {
item.comment = COMMENT_MAKER_FEE_SUBMIT
}
else if (user_channel == 3) {
item.comment = COMMENT_KOL_FEE_SUBMIT
}
else {
item.comment = COMMENT_USER_FEE_SUBMIT
}
itemList.push(item);
}
return item; return itemList;
} }
async function checkSpotPair(pair: string) { async function checkSpotPair(pair: string) {
...@@ -537,3 +557,34 @@ async function getProjectMakerTradeStat(user_id: number, pair: string) { ...@@ -537,3 +557,34 @@ async function getProjectMakerTradeStat(user_id: number, pair: string) {
return res; return res;
} }
async function getAllSpotPairs() {
let dbPairs = await spotPairs.prototype.findAll(
{
attributes: ['symbol'],
where: {
status: 2
},
raw: true
}
);
return dbPairs.map(item => item.symbol);
}
async function getAllContractPairs() {
let dbPairs = await contractPairs.prototype.findAll(
{
attributes: ['symbol'],
where: {
status: 2
},
raw: true
}
);
return dbPairs.map(item => item.symbol);
}
...@@ -284,7 +284,7 @@ export async function tradeAssetByUids(uids: number[]) { ...@@ -284,7 +284,7 @@ export async function tradeAssetByUids(uids: number[]) {
} }
catch (e) { catch (e) {
logger.error('tradeAssetByUids.error:' + e); logger.error('tradeAssetByUids.error:' + e);
throw e; return [];
} }
} }
......
import { coinAddress, coinWithdraw, ormDB, userAccountChangeLog, userInfo, userProfile } from "@madex/ex-ts-dao"; import { coinAddress, coinWithdraw, ormDB, userAccountChangeLog, userInfo } from "@madex/ex-ts-dao";
import { ErrorCode } from "../../../constant/errorCode"; import { ErrorCode } from "../../../constant/errorCode";
import { getProfileByUserIds } from "./mUserProfile.service"; import { getRealNameByUserId, getRealNameMapByUserIds } from "./mUserRealName.service";
import { getRealNameMapByUserIds, getRealNameByUserId } from "./mUserRealName.service";
import { MUserRedisKey } from "../../../constant/mUserRedisKey"; import { MUserRedisKey } from "../../../constant/mUserRedisKey";
import { getMUserInfoByEmail, getMUserInfoByUid, getUserInfoMapByUids, sendEmail, updateMUserInfo } from "../../../utils/mUserUtils"; import { getMUserInfoByEmail, getMUserInfoByUid, getUserInfoMapByUids, sendEmail, updateMUserInfo } from "../../../utils/mUserUtils";
import { existEmail, getProcessingEmailListByMUserId } from "./mUserAccountChangeLog.service"; import { existEmail, getProcessingEmailListByMUserId } from "./mUserAccountChangeLog.service";
...@@ -15,6 +14,7 @@ import { tradeAsset2USDTByUids, walletAsset2USDTByUids } from "./mUserAssets.ser ...@@ -15,6 +14,7 @@ import { tradeAsset2USDTByUids, walletAsset2USDTByUids } from "./mUserAssets.ser
import BigNumber from "bignumber.js"; import BigNumber from "bignumber.js";
import { getCoinWithdrawMapByUids } from "./coinWithdraw.service"; import { getCoinWithdrawMapByUids } from "./coinWithdraw.service";
import { getCoinAddressMapByUids } from "./coinAddress.service"; import { getCoinAddressMapByUids } from "./coinAddress.service";
import { M_SESSION_ID_PREFIX } from "../../../constant/redis-val";
let _ = require('lodash'); let _ = require('lodash');
let { logger, datetimeUtils } = require('@madex/ex-js-public'); let { logger, datetimeUtils } = require('@madex/ex-js-public');
...@@ -131,7 +131,7 @@ export async function oneUserDetail(m_user_id: number) { ...@@ -131,7 +131,7 @@ export async function oneUserDetail(m_user_id: number) {
throw ErrorCode.DATA_NOT_EXIST; throw ErrorCode.DATA_NOT_EXIST;
} }
let oneRealName = await getRealNameByUserId(m_user_id); let oneRealName = await getRealNameByUserId(m_user_id);
let isLoginLock = await redisUtilsCommon.getSync(m_user_id + MUserRedisKey.USER_LOCK_SUFFIX); let isLoginLock = await getLoginLimit(m_user_id);
//24小时提现限制 //24小时提现限制
let dead_line = datetimeUtils.add(oneUser.secure_modifiedAt, datetimeUtils.DAY); let dead_line = datetimeUtils.add(oneUser.secure_modifiedAt, datetimeUtils.DAY);
let is_withdraw = datetimeUtils.between(new Date(), dead_line); let is_withdraw = datetimeUtils.between(new Date(), dead_line);
...@@ -145,7 +145,7 @@ export async function oneUserDetail(m_user_id: number) { ...@@ -145,7 +145,7 @@ export async function oneUserDetail(m_user_id: number) {
kyc_identity: oneRealName ? oneRealName.identity : 0,//证件号 kyc_identity: oneRealName ? oneRealName.identity : 0,//证件号
is_bind_totp: oneUser.totp_encrypt ? 1 : 0, is_bind_totp: oneUser.totp_encrypt ? 1 : 0,
lock_status: oneUser.is_lock, //0 否 1 是 lock_status: oneUser.is_lock, //0 否 1 是
login_lock: isLoginLock ? 1 : 0,//登陆锁定 0 否 1 是 login_lock: isLoginLock.is_limit ? 1 : 0,//登陆锁定 0 否 1 是
withdraw_limit_24: is_withdraw > 0 ? 0 : 1,//24小时提现限制 withdraw_limit_24: is_withdraw > 0 ? 0 : 1,//24小时提现限制
} }
return res; return res;
...@@ -183,7 +183,7 @@ export async function updateUserEmail(currentUserId: number, m_user_id: any, ema ...@@ -183,7 +183,7 @@ export async function updateUserEmail(currentUserId: number, m_user_id: any, ema
await modifyUserEmail(m_user_id, email, dbEmail); await modifyUserEmail(m_user_id, email, dbEmail);
//踢出登陆 //踢出登陆
authCommon.delSessionIdList(m_user_id); killAllLogin(m_user_id);
//新邮箱发邮件 //新邮箱发邮件
sendEmail(email, m_user_id, EMAIL_FORBID_TEMPLATE); sendEmail(email, m_user_id, EMAIL_FORBID_TEMPLATE);
//旧邮箱发送邮件 //旧邮箱发送邮件
...@@ -212,33 +212,34 @@ export async function lockAccount(currentUserId: number, m_user_id: any, ip: any ...@@ -212,33 +212,34 @@ export async function lockAccount(currentUserId: number, m_user_id: any, ip: any
if (lock_type == 1) { if (lock_type == 1) {
await updateMUserInfo(m_user_id, { is_lock: 1 }); await updateMUserInfo(m_user_id, { is_lock: 1 });
//踢出登陆 //踢出登陆
authCommon.delSessionIdList(m_user_id); killAllLogin(m_user_id);
comment = `ip:${ip},锁定用户:${fatherUserId}`; comment = `ip:${ip},锁定用户:${fatherUserId}`;
} }
else { else {
if (dnUidUserInfo.user_type == userInfo.USER_TYPE.SON) { let sonType = userInfo.USER_TYPE.SON;
if (dnUidUserInfo.user_type == sonType) {
let temp = await getFatherUserId(m_user_id); let temp = await getFatherUserId(m_user_id);
if (!temp) { if (!temp) {
throw ErrorCode.DAD_ACCOUNT_NOT_EXIST; throw ErrorCode.DAD_ACCOUNT_NOT_EXIST;
} }
fatherUserId = temp; fatherUserId = temp;
let uids = await getUidsByFatherUid(fatherUserId); }
uids.push(fatherUserId); let uids = await getUidsByFatherUid(fatherUserId);
//更新主账户及其子账户 uids.push(fatherUserId);
await userInfo.prototype.update({ //更新主账户及其子账户
is_lock: 1, await userInfo.prototype.update({
updatedAt: new Date() is_lock: 1,
}, { updatedAt: new Date()
where: { }, {
user_id: { [ormDB.Op.in]: uids } where: {
} user_id: { [ormDB.Op.in]: uids }
});
//踢出登陆
for (let uid of uids) {
authCommon.delSessionIdList(uid);
} }
comment = `ip:${ip},锁定用户:${uids}`; });
//踢出登陆
for (let uid of uids) {
killAllLogin(uid);
} }
comment = `ip:${ip},锁定用户:${uids}`;
} }
//管理后台操作日志 //管理后台操作日志
...@@ -275,27 +276,28 @@ export async function unlockAccount(currentUserId: number, m_user_id: any, ip: a ...@@ -275,27 +276,28 @@ export async function unlockAccount(currentUserId: number, m_user_id: any, ip: a
comment = `ip:${ip},解锁用户:${fatherUserId}`; comment = `ip:${ip},解锁用户:${fatherUserId}`;
} }
else { else {
if (dnUidUserInfo.user_type == userInfo.USER_TYPE.SON) { let sonType = userInfo.USER_TYPE.SON;
if (dnUidUserInfo.user_type == sonType) {
let temp = await getFatherUserId(m_user_id); let temp = await getFatherUserId(m_user_id);
if (!temp) { if (!temp) {
throw ErrorCode.DAD_ACCOUNT_NOT_EXIST; throw ErrorCode.DAD_ACCOUNT_NOT_EXIST;
} }
fatherUserId = temp; fatherUserId = temp;
let uids = await getUidsByFatherUid(fatherUserId);
uids.push(fatherUserId);
//更新主账户及其子账户
await userInfo.prototype.update({
is_lock: 0,
login_error_times: 0,
updatedAt: new Date()
}, {
where: {
user_id: { [ormDB.Op.in]: uids }
}
});
comment = `ip:${ip},解锁用户:${uids}`;
} }
let uids = await getUidsByFatherUid(fatherUserId);
uids.push(fatherUserId);
//更新主账户及其子账户
await userInfo.prototype.update({
is_lock: 0,
login_error_times: 0,
updatedAt: new Date()
}, {
where: {
user_id: { [ormDB.Op.in]: uids }
}
});
comment = `ip:${ip},解锁用户:${uids}`;
} }
//管理后台操作日志 //管理后台操作日志
...@@ -310,7 +312,8 @@ export async function unlockAccount(currentUserId: number, m_user_id: any, ip: a ...@@ -310,7 +312,8 @@ export async function unlockAccount(currentUserId: number, m_user_id: any, ip: a
export async function clearLoginLimit(currentUserId: number, m_user_id: any, ip: any, totp_code: any) { export async function clearLoginLimit(currentUserId: number, m_user_id: any, ip: any, totp_code: any) {
//校验谷歌 //校验谷歌
await checkTotp(currentUserId, totp_code); await checkTotp(currentUserId, totp_code);
await redisUtilsCommon.delSync(m_user_id + MUserRedisKey.USER_LOCK_SUFFIX);
await delLoginLimit(m_user_id);
//管理后台操作日志 //管理后台操作日志
addOptLog(currentUserId, Number(m_user_id), '清除用户登陆限制', ip, "", '用户管理'); addOptLog(currentUserId, Number(m_user_id), '清除用户登陆限制', ip, "", '用户管理');
...@@ -461,6 +464,93 @@ async function buildReturnData(pageData: any, fill_user_info: boolean, fill_coin ...@@ -461,6 +464,93 @@ async function buildReturnData(pageData: any, fill_user_info: boolean, fill_coin
} }
} }
/**
* 查询登陆是否被限制 以及限制次数
* @param user_id
*/
async function getLoginLimit(user_id: number) {
let res = {
is_limit: 0,//是否被限制 1 登陆密码限制 2 谷歌验证码限制 3 验证码限制
times: 0
}
let [totpCodeErrKey, verifyCodeErrKey,
totpCodeErrTimesKey, verifyCodeErrTimesKey,
loginPwdErrKey] = getLoginLimitKeys(user_id);
let loginPwdErrKeyData = await redisUtilsCommon.getSync(loginPwdErrKey);
if (loginPwdErrKeyData) {
res.is_limit = 1;
res.times = loginPwdErrKeyData;
return res;
}
let totpCodeErrKeyData = await redisUtilsCommon.getSync(totpCodeErrKey);
if (totpCodeErrKeyData) {
res.is_limit = 2;
res.times = await redisUtilsCommon.getSync(totpCodeErrTimesKey);
return res;
}
let verifyCodeErrKeyData = await redisUtilsCommon.getSync(verifyCodeErrKey);
if (verifyCodeErrKeyData) {
res.is_limit = 3;
res.times = await redisUtilsCommon.getSync(verifyCodeErrTimesKey);
return res;
}
return res;
}
/**
* 清除登陆限制
* @param user_id
*/
async function delLoginLimit(user_id: number) {
let [totpCodeErrKey, verifyCodeErrKey,
totpCodeErrTimesKey, verifyCodeErrTimesKey,
loginPwdErrKey] = getLoginLimitKeys(user_id);
redisUtilsCommon.delSync(loginPwdErrKey);
redisUtilsCommon.delSync(totpCodeErrKey);
redisUtilsCommon.delSync(verifyCodeErrKey);
redisUtilsCommon.writeSync(totpCodeErrTimesKey, 0);
redisUtilsCommon.writeSync(verifyCodeErrTimesKey, 0);
}
/**
* 获取登陆限制的redis key
* @param user_id
*/
function getLoginLimitKeys(user_id: number) {
//谷歌验证码错误
let totpCodeErr = '2015';
//验证码错误
let verifyCodeErr = '2018';
//谷歌验证码错误 锁2小时 的key
let totpCodeErrKey = "lock2hourExpiredKey.userId." + user_id + ".errorCode." + totpCodeErr;
//验证码错误 锁2小时 的key
let verifyCodeErrKey = "lock2hourExpiredKey.userId." + user_id + ".errorCode." + verifyCodeErr;
//谷歌验证码错误次数 的key
let totpCodeErrTimesKey = "errorTimesWithCode.userId." + user_id + ".errorCode." + totpCodeErr;
//验证码错误 次数 的key
let verifyCodeErrTimesKey = "errorTimesWithCode.userId." + user_id + ".errorCode." + verifyCodeErr;
//登陆密码错误 的key
let loginPwdErrKey = user_id + MUserRedisKey.USER_LOCK_SUFFIX;
return [totpCodeErrKey, verifyCodeErrKey, totpCodeErrTimesKey, verifyCodeErrTimesKey, loginPwdErrKey];
}
async function killAllLogin(user_id: number) {
let key = M_SESSION_ID_PREFIX + user_id;
let sessionList = await redisUtilsCommon.getSync(key);
if (sessionList && sessionList.length){
sessionList.push(key);
for (let item of sessionList) {
await redisUtilsCommon.delSync(item);
}
}
}
......
...@@ -298,8 +298,8 @@ async function updateImageUrl(dbRealNameInfo: any) { ...@@ -298,8 +298,8 @@ async function updateImageUrl(dbRealNameInfo: any) {
let identityFrondSide = dbRealNameInfo.identity_frond_side; let identityFrondSide = dbRealNameInfo.identity_frond_side;
if (identityFrondSide) { if (identityFrondSide) {
if (!identityFrondSide.includes("http")) { if (!identityFrondSide.includes("http")) {
dbRealNameInfo.identity_frond_side_small = ossUtils.resizeWithWaterMark(identityFrondSide, "Madex", 300); dbRealNameInfo.identity_frond_side_small = await ossUtils.resizeWithWaterMark(identityFrondSide, "Madex", 300);
dbRealNameInfo.identity_frond_side = ossUtils.withWaterMark(identityFrondSide, "Madex"); dbRealNameInfo.identity_frond_side = await ossUtils.withWaterMark(identityFrondSide, "Madex");
} }
else { else {
dbRealNameInfo.identity_frond_side_small = identityFrondSide dbRealNameInfo.identity_frond_side_small = identityFrondSide
...@@ -313,8 +313,8 @@ async function updateImageUrl(dbRealNameInfo: any) { ...@@ -313,8 +313,8 @@ async function updateImageUrl(dbRealNameInfo: any) {
let identityOtherSide = dbRealNameInfo.identity_other_side; let identityOtherSide = dbRealNameInfo.identity_other_side;
if (identityOtherSide) { if (identityOtherSide) {
if (!identityOtherSide.includes("http")) { if (!identityOtherSide.includes("http")) {
dbRealNameInfo.identity_other_side_small = ossUtils.resizeWithWaterMark(identityOtherSide, "Madex", 300); dbRealNameInfo.identity_other_side_small = await ossUtils.resizeWithWaterMark(identityOtherSide, "Madex", 300);
dbRealNameInfo.identity_other_side = ossUtils.withWaterMark(identityOtherSide, "Madex"); dbRealNameInfo.identity_other_side = await ossUtils.withWaterMark(identityOtherSide, "Madex");
} }
else { else {
dbRealNameInfo.identity_other_side_small = identityOtherSide dbRealNameInfo.identity_other_side_small = identityOtherSide
...@@ -329,8 +329,8 @@ async function updateImageUrl(dbRealNameInfo: any) { ...@@ -329,8 +329,8 @@ async function updateImageUrl(dbRealNameInfo: any) {
let identityInHand = dbRealNameInfo.identity_in_hand; let identityInHand = dbRealNameInfo.identity_in_hand;
if (identityInHand) { if (identityInHand) {
if (!identityInHand.includes("http")) { if (!identityInHand.includes("http")) {
dbRealNameInfo.identity_in_hand_small = ossUtils.resizeWithWaterMark(identityInHand, "Madex", 300); dbRealNameInfo.identity_in_hand_small = await ossUtils.resizeWithWaterMark(identityInHand, "Madex", 300);
dbRealNameInfo.identity_in_hand = ossUtils.withWaterMark(identityInHand, "Madex"); dbRealNameInfo.identity_in_hand = await ossUtils.withWaterMark(identityInHand, "Madex");
} }
else { else {
dbRealNameInfo.identity_in_hand_small = identityInHand dbRealNameInfo.identity_in_hand_small = identityInHand
...@@ -345,8 +345,8 @@ async function updateImageUrl(dbRealNameInfo: any) { ...@@ -345,8 +345,8 @@ async function updateImageUrl(dbRealNameInfo: any) {
let latestPhoto = dbRealNameInfo.latest_photo; let latestPhoto = dbRealNameInfo.latest_photo;
if (latestPhoto) { if (latestPhoto) {
if (!latestPhoto.includes("http")) { if (!latestPhoto.includes("http")) {
dbRealNameInfo.latest_photo_small = ossUtils.resizeWithWaterMark(latestPhoto, "Madex", 300); dbRealNameInfo.latest_photo_small = await ossUtils.resizeWithWaterMark(latestPhoto, "Madex", 300);
dbRealNameInfo.latest_photo = ossUtils.withWaterMark(latestPhoto, "Madex"); dbRealNameInfo.latest_photo = await ossUtils.withWaterMark(latestPhoto, "Madex");
} }
else { else {
dbRealNameInfo.latest_photo_small = latestPhoto dbRealNameInfo.latest_photo_small = latestPhoto
......
...@@ -41,10 +41,11 @@ export interface NoticePageVO extends NoticeVO { ...@@ -41,10 +41,11 @@ export interface NoticePageVO extends NoticeVO {
export async function list(noticePageVO: NoticePageVO) { export async function list(noticePageVO: NoticePageVO) {
let where = Object.create(null); let where = Object.create(null);
where.del_sign = 0;
if (noticePageVO.publish_flag) { if (noticePageVO.publish_flag) {
where.publish_flag = noticePageVO.publish_flag; where.publish_flag = noticePageVO.publish_flag;
} }
if (Number(noticePageVO.user_id) >= 0) { if (noticePageVO.user_id && Number(noticePageVO.user_id) >= 0) {
where.user_id = noticePageVO.user_id; where.user_id = noticePageVO.user_id;
} }
if (noticePageVO.notice_type) { if (noticePageVO.notice_type) {
...@@ -57,9 +58,6 @@ export async function list(noticePageVO: NoticePageVO) { ...@@ -57,9 +58,6 @@ export async function list(noticePageVO: NoticePageVO) {
let date = datetimeUtils.trim(noticePageVO.push_time, 's'); let date = datetimeUtils.trim(noticePageVO.push_time, 's');
where.push_time = { [ormDB.Op.gte]: date }; where.push_time = { [ormDB.Op.gte]: date };
} }
if (noticePageVO.del_sign || noticePageVO.del_sign === 0) {
where.del_sign = noticePageVO.del_sign;
}
if (noticePageVO.status) { if (noticePageVO.status) {
where.status = noticePageVO.status; where.status = noticePageVO.status;
} }
......
...@@ -5,6 +5,7 @@ import { addCoin2Core, addPairToCore } from "../../../utils/coreSystemUtils"; ...@@ -5,6 +5,7 @@ import { addCoin2Core, addPairToCore } from "../../../utils/coreSystemUtils";
import { PAIR_APPLY_STATUS } from "../../../constant/pairApplyConst"; import { PAIR_APPLY_STATUS } from "../../../constant/pairApplyConst";
import { checkPairInCoinType } from "../../../utils/coinTypeUtils"; import { checkPairInCoinType } from "../../../utils/coinTypeUtils";
import { pairs } from "rxjs"; import { pairs } from "rxjs";
import * as RobotUtil from "../../../utils/robotUtils";
let _ = require('lodash'); let _ = require('lodash');
...@@ -392,11 +393,6 @@ export async function review(id: any, currentUser: any, ip: string | undefined) ...@@ -392,11 +393,6 @@ export async function review(id: any, currentUser: any, ip: string | undefined)
//检查交易对是否存在 //检查交易对是否存在
await checkPairExist(pair, type); await checkPairExist(pair, type);
//TODO:新撮合是否需要此操作 初始化
/*String errStr = spotRpcService.initPair1(dbpair);
if (errStr != null) {
return ResponseResult.failure("admin rpc fail: " + errStr);
}*/
reason = "发布交易对到撮合完成"; reason = "发布交易对到撮合完成";
await updateApply(Number(id), PAIR_APPLY_STATUS.ADMIN_ISSUE_PAIR, currentUser.account, reason, pair); await updateApply(Number(id), PAIR_APPLY_STATUS.ADMIN_ISSUE_PAIR, currentUser.account, reason, pair);
} }
...@@ -409,6 +405,7 @@ export async function review(id: any, currentUser: any, ip: string | undefined) ...@@ -409,6 +405,7 @@ export async function review(id: any, currentUser: any, ip: string | undefined)
throw ErrorCode.ACTIVE_TM_EXPIRE; throw ErrorCode.ACTIVE_TM_EXPIRE;
} }
//TODO:需要确认 trigger_type 等字段 //TODO:需要确认 trigger_type 等字段
/*
await systemTrigger.prototype.create({ await systemTrigger.prototype.create({
trigger_symbol: pair, trigger_symbol: pair,
trigger_type: 2, trigger_type: 2,
...@@ -418,6 +415,7 @@ export async function review(id: any, currentUser: any, ip: string | undefined) ...@@ -418,6 +415,7 @@ export async function review(id: any, currentUser: any, ip: string | undefined)
createdAt: new Date(), createdAt: new Date(),
updatedAt: new Date(), updatedAt: new Date(),
}); });
*/
reason = "交易对激活定时器完成"; reason = "交易对激活定时器完成";
await updateApply(Number(id), PAIR_APPLY_STATUS.TIMER_ACTIVE, currentUser.account, reason, pair); await updateApply(Number(id), PAIR_APPLY_STATUS.TIMER_ACTIVE, currentUser.account, reason, pair);
} }
...@@ -445,7 +443,6 @@ async function updateApply(id: number, status: number, checker: string, reason: ...@@ -445,7 +443,6 @@ async function updateApply(id: number, status: number, checker: string, reason:
sendMsg(status, symbol); sendMsg(status, symbol);
} }
//TODO:发送lark消息
async function sendMsg(status: number, symbol: string) { async function sendMsg(status: number, symbol: string) {
// 1被驳回2申请待审批3审批通过4交易对创建完成5交易对增加到撮合完成6等待撮合系统重启7发布交易对到撮合完成8交易对激活定时器完成9取消 // 1被驳回2申请待审批3审批通过4交易对创建完成5交易对增加到撮合完成6等待撮合系统重启7发布交易对到撮合完成8交易对激活定时器完成9取消
let content = ""; let content = "";
...@@ -477,7 +474,8 @@ async function sendMsg(status: number, symbol: string) { ...@@ -477,7 +474,8 @@ async function sendMsg(status: number, symbol: string) {
content = "申请上交易对,被取消:" + symbol + ",流程结束"; content = "申请上交易对,被取消:" + symbol + ",流程结束";
} }
if (content != null) { if (content != null) {
//TODO:发lark RobotUtil.sendRobotMessage(RobotUtil.ROBOT_KEYS.COMMON_KEY, content);
} }
} }
......
...@@ -47,6 +47,7 @@ import * as pairApplyCtrl from "../../mvc/control/pairApply.control"; ...@@ -47,6 +47,7 @@ import * as pairApplyCtrl from "../../mvc/control/pairApply.control";
import * as cronApplyCtrl from "../../mvc/control/cronApply.control"; import * as cronApplyCtrl from "../../mvc/control/cronApply.control";
import * as spotDataCtrl from "../../mvc/control/spotData.control"; import * as spotDataCtrl from "../../mvc/control/spotData.control";
import * as exBusinessAreaCtrl from "../../mvc/control/exBusinessArea.control"; import * as exBusinessAreaCtrl from "../../mvc/control/exBusinessArea.control";
import * as rewardTimePeriodCtrl from "../../mvc/control/rewardTimePeriod.control";
const getFunc = { const getFunc = {
'user/info': userController.getUserInfo, 'user/info': userController.getUserInfo,
...@@ -283,6 +284,10 @@ const postFunc = { ...@@ -283,6 +284,10 @@ const postFunc = {
'operate/other/business/area/router/update': exBusinessAreaCtrl.routerUpdate, 'operate/other/business/area/router/update': exBusinessAreaCtrl.routerUpdate,
'operate/other/business/area/router/delete': exBusinessAreaCtrl.routerDel, 'operate/other/business/area/router/delete': exBusinessAreaCtrl.routerDel,
'operate/other/business/area/router/list': exBusinessAreaCtrl.routerList, 'operate/other/business/area/router/list': exBusinessAreaCtrl.routerList,
//技术部-其他管理-返佣时间配置
'tech/other/reward/time/period/set': rewardTimePeriodCtrl.set,
'tech/other/reward/time/period/get': rewardTimePeriodCtrl.get,
}; };
// TODO 这里先和 nodejs 的注册路由方式保持一样,后面在调整。 // TODO 这里先和 nodejs 的注册路由方式保持一样,后面在调整。
......
...@@ -224,6 +224,9 @@ let cmdWhiteList = { ...@@ -224,6 +224,9 @@ let cmdWhiteList = {
'operate/other/business/area/router/update': 1, 'operate/other/business/area/router/update': 1,
'operate/other/business/area/router/delete': 1, 'operate/other/business/area/router/delete': 1,
'operate/other/business/area/router/list': 1, 'operate/other/business/area/router/list': 1,
//技术部-其他管理-返佣时间配置
'tech/other/reward/time/period/set': 1,
'tech/other/reward/time/period/get': 1,
}; };
......
import { mainUserAsset } from "@madex/ex-ts-dao"; import { mainUserAsset } from "@madex/ex-ts-dao";
import { getUserAccountFromCore } from "./coreSystemUtils";
let blockCoin = "BIX0"; let blockCoin = "BIX0";
...@@ -13,13 +14,11 @@ export const spotCheck = async function (user_id: number) { ...@@ -13,13 +14,11 @@ export const spotCheck = async function (user_id: number) {
} }
export const baseCoinCheck = async function (user_id: number) { export const baseCoinCheck = async function (user_id: number) {
//TODO:后面补齐查询币本位资产逻辑 let resList = await getUserAccountFromCore(user_id);
let exist = {}; return resList.length;
return exist;
} }
export const baseUCheck = async function (user_id: number) { export const baseUCheck = async function (user_id: number) {
//TODO:后面补齐查询U本位资产逻辑 let resList = await getUserAccountFromCore(user_id);
let exist = {}; return resList.length;
return exist;
} }
\ No newline at end of file
let {
debug,
logger
} = require('@madex/ex-js-public');
const {
larkRobotUtils: LarkRobotUtils,
} = require("@madex/ex-js-common")
let config = require('../../config');
debug = config.env === "development";
let COMMON_KEY = "9e06e260-6c2f-49d4-98b4-e08ef096f6f5";
//测试
if (debug) {
COMMON_KEY = "9e06e260-6c2f-49d4-98b4-e08ef096f6f5";
}
export const ROBOT_KEYS = {
COMMON_KEY: COMMON_KEY
}
/**
*
* @param url 机器人链接 (必填)
* @param content 发送内容(必填)
* @param _func_name_ 报错方法(可选)
*/
export const sendRobotMessage = async function (url: string, content: any, _func_name_?: string) {
if (typeof content != 'string') {
if (content && content.sql) {
content = `backend._func_name_ ${_func_name_}, ${content.sql}`;
}
else if (content && content.message) {
content = `backend._func_name_ ${_func_name_}, ${content.message}`;
}
else {
content = `backend._func_name_ ${_func_name_}, ${JSON.stringify(content)}`;
}
}
else {
content = `backend._func_name_ ${_func_name_}, ${content}`;
}
if (debug) {
content = `backend.测试.${content}`;
await doSend(COMMON_KEY, content);
}
else {
await doSend(url, content);
}
}
async function doSend(url: string, content: any) {
logger.info('robot message', url, content);
await LarkRobotUtils.sendTextSimple(url, content).catch()
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment