瀏覽代碼

okc,kcc withdraw 自测通过

DevYK 2 年之前
父節點
當前提交
2d99e63992

+ 3 - 1
model/db/redis_db.js

@@ -141,10 +141,11 @@ async function readRedis(key) {
     // REDIS_INSTANCE.get(key)
     redis_get(key)
       .then(result => {
-        console.log("redis_get=", result); // Prints "value"
+        // console.log("redis_get=", result); // Prints "value"
         resolve(result);
       }).catch(e => {
         console.log("readRedis key error=", key, e); // Prints "error"
+        resolve(null);
       });
   })
 }
@@ -157,4 +158,5 @@ module.exports = {
   readRedis,
   readAppendRedis,
   writeAppendRedis,
+  formatRedisKey,
 }

+ 5 - 6
model/db/withdraw_db.js

@@ -30,12 +30,11 @@ async function create_withdraw_task(task_obj) {
     var type = task_obj.type
     var amount = task_obj.amount
 
-    if (chain_id == 2019)
-        switch (type) {
-            case 'erc20':
-                type = 'token'
-                break
-        }
+    switch (type) {
+        case 'erc20':
+            type = 'token'
+            break
+    }
 
     if (!from_address || !to_address) {
         return {

+ 3 - 3
model/czz.js → model/http_withdraw.js

@@ -29,14 +29,14 @@ const withdraw = async (params) => {
 const check_withdraw_status = async (params) => {
     logger.info('txn_status_czz', process.env.NODE_ENV, url, ' params ', params)
     var pars = {
-        txn_hash: params.hash,
-        chain: "czz"
+        txn_hash: params.txn_hash,
+        chain: params.chain
     }
     var data = pars
     return new Promise(resolve => {
         axios.post(url + '/txn_status', data, { timeout: 1 * 60 * 1000 })
             .then(res => {
-                console.log('res=>', res.status, res.data);
+                console.log('check_withdraw_status res=>', res.status, res.data);
                 resolve(res.data)
             }).catch(err => {
                 logger.error('http_request_post check_withdraw_status error ', JSON.stringify(err));

+ 7 - 5
model/moralis_sdk.js

@@ -12,7 +12,7 @@ const logger = require('./logger')
 const report = require("./report")  //导入 db.js
 const BigNumber = require('bignumber.js')
 const collect_coins_db = require('./db/collect_coins_db')
-const czz = require('./czz')
+const czz = require('./http_withdraw')
 var remote_config_db = require("../model/db/remote_config_db");
 
 /* Moralis init code */
@@ -356,12 +356,14 @@ async function computeTransferGasFree(obj, my_account_all_coins, tokenPrices) {
                     tokenCount += 1;
                     logger.log('token > 1.0', tokenCount, element.token_address);
 
+                    var type = utils.getTokenTransferType(obj.chain)
+
                     var obj_20 = {
                         chain: obj.chain,
                         contractAddress: element.token_address,
                         amount: element.balance,
                         receiver: receiver_info.user_address,
-                        type: obj.chain == utils.CHAIN_NAME.czz ? 'token' : 'erc20',
+                        type: type,
                         address: obj.address,
                         usdPrice: find_transfer_item.usdPrice
                     }
@@ -1105,7 +1107,8 @@ async function transfer_(opts) {
         } else if (ret && ret.data && ret.code == 1) {
             return {
                 code: 1,
-                hash: ret.data.hash,
+                chain: opts.chain,
+                hash: ret.data.txn_hash,
                 create_time: utils.getTimestamp(),
                 lifecycle: 24 * 60 * 60 * 1000,
             }
@@ -1163,10 +1166,9 @@ const getAllTokenWithdrawInfoLists = async (obj) => {
 const getAllTotkenPrice = async (opts) => {
     try {
         logger.log('当前环境:', process.env.NODE_ENV);
-        logger.log("getAllTotkenPrice in", reids_token_config); // Prints "value"
+        // logger.log("getAllTotkenPrice in", reids_token_config); // Prints "value"
         var token_price_key = reids_token_config.TOKENPRICE;
         logger.log("getAllTotkenPrice token_price_key=", token_price_key);
-        // return await redis.readRedis(token_price_key)
         return await redis.readAppendRedis(token_price_key, opts.chain, '')
     } catch (error) {
         logger.error("getTotkenPrice=", error);

+ 3 - 3
model/server_data_statistics.js

@@ -697,9 +697,9 @@ timeoutFunc({
     time: reportTime //执行的时间点 时在0~23之间
 
 }, func => {
-    if (process.env.NODE_ENV == 'prd') {
-        report2FeishuTable()
-    }
+    // if (process.env.NODE_ENV == 'prd') {
+    //     report2FeishuTable()
+    // }
 })
 // logger.info('getAllBalance  ', getAllBalance())
 module.exports = {

+ 751 - 0
model/server_data_statisticsv2.js

@@ -0,0 +1,751 @@
+const logger = require('./logger')
+var remote_config_db = require("./db/remote_config_db");
+var collect_coins_db = require("./db/collect_coins_db");
+var withdraw_db = require("./db/withdraw_db");
+var moralis = require("./moralis_sdk");
+var utils = require("./utils");
+const axios = require('axios');
+var { account_config } = require('../config/config.js');
+const { max } = require('moment');
+const redis = require('./db/redis_db');
+
+// 拿到飞书写入的 token
+const feishu_write_table_token_url = 'https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal'
+const feishu_write_table_data_url = 'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/shtcnp6zbrsep1Sz3Cvk7NXRpDg/values_batch_update'
+const feishu_insert_table_url = 'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/shtcnp6zbrsep1Sz3Cvk7NXRpDg/insert_dimension_range'
+const feishu_delete_table_url = 'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/shtcnp6zbrsep1Sz3Cvk7NXRpDg/dimension_range'
+const feishu_get_table_metadata_url = 'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/shtcnp6zbrsep1Sz3Cvk7NXRpDg/metainfo'
+const feishu_create_table_url = 'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/shtcnp6zbrsep1Sz3Cvk7NXRpDg/dimension_range'
+
+const mTokenPriceCache = new Map()
+const mDecimalsCache = new Map()
+
+//########################################### 出入金数据统计 ########################################
+
+const http_request_get = async (data) => {
+    var host = account_config.STATISTICS_URL
+    // host = 'https://api.denetme.net/denet/wallet/stat/getMoneyStat?date='
+    var path = data
+    var url = host + path
+    logger.log('http_request_get', url)
+    return new Promise(response => {
+        axios.get(url)
+            .then(res => {
+                logger.log('res=>', res.status, res.data);
+                if (res.data.code == 0) {
+                    response(res.data)
+                } else {
+                    response({
+                        code: 0,
+                        msg: err.toString(),
+                        data: {
+                            canNotWithdrawUSD: '0',
+                            canWithdrawUSD: '0',
+                            incomeUSDTotal: '0',
+                            incomeUSDFee: '0'
+                        }
+                    })
+                }
+            }).catch(err => {
+                logger.error('http_request_get', err.toString(), url.toString());
+                response({
+                    code: -1,
+                    msg: err.toString(),
+                    data: {
+                        canNotWithdrawUSD: '0',
+                        canWithdrawUSD: '0',
+                        incomeUSDTotal: '0',
+                        incomeUSDFee: '0'
+                    }
+                })
+            });
+    })
+}
+
+
+function getBscEnv() {
+    var bsc_env
+    switch (process.env.NODE_ENV) {
+        case 'dev':
+        case 'test':
+            bsc_env = 'bsc_testnet'
+            bsc_env = 'bsc_mainnet'
+            break
+        case 'prd':
+            bsc_env = 'bsc_mainnet'
+            break
+        default:
+            bsc_env = 'bsc_mainnet'
+            break
+    }
+    return bsc_env;
+}
+
+
+
+async function findCurBalance(type, address) {
+    var balances
+    var price
+    var tokenItems = []
+    switch (type) {
+        case 'bsc':
+            balances = await moralis.getAccountAllCoins({
+                chain: getBscEnv(),
+                address: address
+            })
+            // price = await moralis.getAllTotkenPrice({ chain: getBscEnv() })
+            price = await getPrice(getBscEnv())
+            break
+        case 'czz':
+            balances = await moralis.getAccountAllCoins({
+                chain: 'czz',
+                address: address
+            })
+            price = await getPrice('czz')
+            // price = await moralis.getAllTotkenPrice({ chain: 'czz' })
+            break
+    }
+    logger.info('findCurBalance', type, address, balances, price)
+    if (typeof price === 'string') {
+        price = JSON.parse(price)
+    }
+    if (!balances || !price) return null
+    priceItem = moralis.findTokenPriceItem('0x0000000000000000000000000000000000000000', price)
+    if (!balances.native.balance) {
+        balances.native.balance = '0'
+    }
+    if (balances.native) {
+        balances.native.usdPrice = parseFloat(balances.native.balance) / parseFloat(10 ** 18) * priceItem.usdPrice
+        logger.info('findTokenPriceItem 0x0000000000000000000000000000000000000000 ', balances, priceItem, type)
+        var bo = {
+            address: address,
+            token_address: '0x0000000000000000000000000000000000000000',
+            chain: type,
+            amount: balances.native.balance,
+            decimals: 18,
+            price: priceItem.usdPrice,
+            usd: balances.native.usdPrice
+        }
+        tokenItems.push(bo)
+    }
+
+    if (balances.other && Array.isArray(balances.other)) {
+        for (let index = 0; index < balances.other.length; index++) {
+            const element = balances.other[index];
+            priceItem = moralis.findTokenPriceItem(element.token_address, price)
+            logger.info('findTokenPriceItem element ', priceItem, element.token_address)
+            if (priceItem) {
+
+                if (!element.decimals || element.decimals == 0)
+                    element.decimals = 18
+                element.usdPrice = parseFloat(element.balance) / parseFloat(10 ** element.decimals) * priceItem.usdPrice
+
+                var bo = {
+                    address: address,
+                    token_address: element.token_address,
+                    chain: type,
+                    amount: element.balance,
+                    decimals: element.decimals,
+                    price: priceItem.usdPrice,
+                    usd: element.usdPrice
+                }
+                tokenItems.push(bo)
+            }
+        }
+    }
+
+    logger.debug('tokenUsds', tokenItems, type)
+    return {
+        nativeUsd: balances.native.usdPrice,
+        tokenUsds: tokenItems,
+        totalUsd: addUsds(tokenItems, 'token_balance')
+    }
+}
+
+async function getAllBalanceV2() {
+    var company = await moralis.queryCompanyInfoFromId(0)
+    logger.info('getAllBalance company', company)
+
+    var bsc_balances = await findCurBalance('bsc', company.user_address)
+    var czz_balances = await findCurBalance('czz', company.user_address)
+
+    logger.info('findCurBalance bsc_balances', bsc_balances)
+    logger.info('findCurBalance czz_balances', czz_balances)
+    let lists = bsc_balances.tokenUsds.concat(czz_balances.tokenUsds);
+    return {
+        bsc: bsc_balances,
+        czz: czz_balances,
+        infos: lists,
+        totalUsd: bsc_balances.totalUsd + czz_balances.totalUsd,
+        totalNativeBalanceUsd: bsc_balances.nativeUsd + czz_balances.nativeUsd
+    }
+}
+
+
+
+
+function parseGas(response, index, price) {
+    try {
+        logger.info('parseGas in', response, index)
+        if (response && Array.isArray(response) && response.length > 0) {
+            var obj
+            if (response[index] && typeof response[index] === 'string')
+                try {
+                    obj = JSON.parse(response[index])
+                } catch (error) {
+                    logger.error('JSON.parse(response[index])', error.toString)
+                }
+            return parseFloat(obj.gasPrice.number) * parseFloat(obj.gasLimit.number) / parseFloat(10 ** 18) * parseFloat(price)
+        }
+
+        else return 0
+    } catch (error) {
+        logger.error('parseGas', error.toString(), JSON.stringify(response))
+        return 0
+    }
+}
+
+async function getPrice(key) {
+    if (mTokenPriceCache.has(key)) {
+        price = mTokenPriceCache.get(key)
+    } else {
+        var price = await moralis.getAllTotkenPrice({
+            chain: key
+        })
+        if (typeof price === 'string') {
+            price = JSON.parse(price)
+        }
+        mTokenPriceCache.set(key, price)
+    }
+    return price
+}
+
+async function getPriceFromCache(key, address) {
+    console.info('getPriceFromCache>', key, address)
+    var price = await getPrice(key)
+
+
+    // var price = await moralis.getAllTotkenPrice({
+    //     chain: key
+    // })
+    // if (typeof price === 'string') {
+    //     price = JSON.parse(price)
+    // }
+
+    var priceItem = moralis.findTokenPriceItem(address, price)
+    if (priceItem && priceItem.usdPrice) {
+        return priceItem.usdPrice
+    } else {
+        return '0'
+    }
+}
+
+
+function convertChain(chain) {
+    return chain
+}
+
+function balance2USDPrice(amount, decimals, price) {
+    return parseFloat(amount) / parseFloat(10 ** decimals) * parseFloat(price)
+}
+
+async function getDecimalsFromRedis(chain, address) {
+    var decimals = 18
+    try {
+        var newKey = redis.formatRedisKey('REDIS_ERC20_CONTRACT_DECIMALS', chain, address.toLowerCase())
+        if (mDecimalsCache.has(newKey)) {
+            decimals = mDecimalsCache.get(newKey)
+        } else {
+            decimals = await redis.readAppendRedis('REDIS_ERC20_CONTRACT_DECIMALS', chain, address.toLowerCase())
+            mDecimalsCache.set(newKey, decimals)
+        }
+        if (!decimals) decimals = '18'
+    } catch (error) {
+        logger.error('getDecimalsFromRedis', chain, address, error.toString())
+        decimals = 18
+    }
+    return decimals
+}
+
+
+function addUsds(infos, type) {
+    var total = 0
+    if (infos && Array.isArray(infos) && infos.length > 0) {
+        for (let index = 0; index < infos.length; index++) {
+            const element = infos[index];
+            switch (type) {
+                case 'gas':
+                    // logger.info('addUsds total ', type, element.gasUsd, element, total)
+                    total += element.gasUsd
+                    break
+                case 'withdraw':
+                    total += element.withdrawUsd
+                    break
+                case 'collect_coins':
+                    total += element.withdrawUsd
+                    break
+                case 'slGas':
+                    total += element.slGasUsd
+                    break
+                case 'token_balance':
+                    total += element.usd
+                    break
+                case 'native_in_coins':
+                    if (element.token_address && element.token_address == '0x0000000000000000000000000000000000000000')
+                        total += element.inUsd
+                    break
+                case 'native_token_in_coins':
+                    total += element.inUsd
+                    break
+            }
+        }
+    }
+    return total
+}
+
+async function getWithdrawOutInfoV2(startTime, endTime) {
+    if (startTime && endTime) {
+        startTime = new Date(startTime).getTime()
+        endTime = new Date(endTime).getTime()
+    }
+    var withdraw_ret = await withdraw_db.getWidthdrawTotalFee(startTime, endTime)
+
+    var withDrawInfos = []
+    for (let index = 0; index < withdraw_ret.length; index++) {
+        const trs = withdraw_ret[index];
+        // console.log('getWithdrawOutInfoV2 element ', trs)
+        var token_address = trs.contract_address
+        if (!trs.contract_address)
+            token_address = '0x0000000000000000000000000000000000000000'
+        try {
+            var input = {
+                dt: utils.chinaTimeMs(trs.update_time),
+                user_address: trs.to_address,
+                token_address: token_address,
+                chain: convertChain(trs.chain_id + ""),
+                amount: trs.amount,
+                decimals: await getDecimalsFromRedis(convertChain(trs.chain_id + ""), token_address),
+                price: await getPriceFromCache(convertChain(trs.chain_id + ""), token_address),
+                gasUsd: parseFloat(trs.gas_price) * parseFloat(trs.gas_limit) / parseFloat(10 ** 18) * await getPriceFromCache(convertChain(trs.chain_id + ""), '0x0000000000000000000000000000000000000000')
+            }
+            if (!input.gasUsd) {
+                logger.info('withdraw_ret input ', trs, input)
+                input.gasUsd = 0
+            }
+
+            //换算成美元
+            input.withdrawUsd = balance2USDPrice(input.amount, input.decimals, input.price)
+            console.log('getWithdrawOutInfoV2 input ', input)
+            withDrawInfos.push(input)
+        } catch (error) {
+            logger.error('getWithdrawOutInfoV2 trs', error.toString())
+        }
+    }
+
+    // logger.log('getWithdrawOutInfoV2 totalOutGasFeeUsd addUsds', addUsds(withDrawInfos, 'gas'), withDrawInfos[0], withDrawInfos[1])
+    return {
+        infos: withDrawInfos,
+        totalOutGasFeeUsd: addUsds(withDrawInfos, 'gas'),
+        totalWithdrawUsd: addUsds(withDrawInfos, 'withdraw'),
+    }
+}
+
+
+async function getCollectCoinsOutInfoV2(startTime, endTime) {
+    var collect_ret = await collect_coins_db.query_collect_total_fee(startTime, endTime);
+    // console.log('getCollectCoinsOutInfoV2 collect_ret', collect_ret.results.length)
+    //每笔入金的详细信息
+    var infos = []
+    //入金充值的 gas 和实际消费的 gas
+    var inGasFeeInfo = []
+    if (collect_ret && collect_ret.results && Array.isArray(collect_ret.results) && collect_ret.results.length > 0) {
+        for (let index = 0; index < collect_ret.results.length; index++) {
+            var element = collect_ret.results[index]
+            if (!element.chain)
+                element.chain = 'bsc_mainnet'
+            var update_tm = element.update_time
+            var user_address = element.user_address
+
+            // console.log('getCollectCoinsOutInfoV2 element', element.before_gas_fee, element.resposes, typeof element.resposes, JSON.parse(element.resposes))
+            var resposes;
+            if (element.resposes && typeof element.resposes === 'string') {
+                try {
+                    resposes = JSON.parse(element.resposes)
+                } catch (error) {
+                    logger.error('element.response parse', error.toString())
+                }
+            }
+
+
+            if (element.prestore_gas_fee && typeof element.prestore_gas_fee === 'string') {
+                try {
+                    var gasObj = JSON.parse(element.prestore_gas_fee)
+
+                    var before_gas_fee = element.before_gas_fee ? element.before_gas_fee : '0'
+                    if (gasObj) {
+                        // logger.log('element.prestore_gas_fee parse', before_gas_fee, gasObj, gasObj.chain)
+                        var newGasObj = {
+                            chain: convertChain(gasObj.chain),
+                            amount: gasObj.amount,
+                            useGas: before_gas_fee,
+                            price: await getPriceFromCache(convertChain(gasObj.chain), '0x0000000000000000000000000000000000000000'),
+                        }
+                        //实际充值手续费用到的 usd
+                        newGasObj.gasUsd = balance2USDPrice(newGasObj.useGas, 18, newGasObj.price)
+                        //散落 gas
+                        newGasObj.slGasUsd = balance2USDPrice(parseFloat(newGasObj.amount) - parseFloat(newGasObj.useGas), 18, newGasObj.price)
+                        inGasFeeInfo.push(newGasObj)
+                    }
+                } catch (error) {
+                    logger.error('element.prestore_gas_fee parse', error.toString())
+                }
+            }
+
+            if (element.transfers && typeof element.transfers === 'string') {
+                try {
+                    var trss = JSON.parse(element.transfers)
+                    // console.log('trss.transfers', trss.chain)
+                    for (let index = 0; index < trss.length; index++) {
+                        const trs = trss[index];
+                        var address = trs.contractAddress == null ? '0x0000000000000000000000000000000000000000' : trs.contractAddress
+                        console.log('trss.transfers', address, trs)
+                        var input = {
+                            dt: update_tm,
+                            user_address: user_address,
+                            token_address: address,
+                            chain: convertChain(trs.chain),
+                            amount: trs.amount,
+                            decimals: trs.contractAddress == null ? 18 : await getDecimalsFromRedis(convertChain(trs.chain), trs.contractAddress),
+                            price: await getPriceFromCache(convertChain(trs.chain), address),
+                            gasUsd: parseGas(resposes, index, await getPriceFromCache(convertChain(trs.chain), '0x0000000000000000000000000000000000000000')) //入金 gas 手续费
+                        }
+                        //换算成美元
+                        input.inUsd = balance2USDPrice(input.amount, input.decimals, input.price)
+                        infos.push(input)
+                    }
+                } catch (error) {
+                    logger.error('transfers handle error', error.toString())
+                }
+            }
+        }
+    }
+    return {
+        infos: infos,
+        totalNativeInFee: addUsds(infos, 'native_in_coins'), //总 native 入金
+        totalInFee: addUsds(infos, 'native_token_in_coins'), //总入金
+        totalInGasFeeUsd: addUsds(infos, 'gas') + addUsds(inGasFeeInfo, 'gas'),//总入金消耗的 gas 包含打 gas fee
+        slTotalGasFeeUsd: addUsds(inGasFeeInfo, 'slGas') //散落 gas
+    }
+}
+
+async function getServerData(startTime, endTime) {
+    //拿到所有归集 list
+    var collectCoinsInfos = await getCollectCoinsOutInfoV2(startTime, endTime)
+    // console.log('getCollectCoinsOutInfoV2 collectCoinsInfos ', collectCoinsInfos)
+
+    //拿到所有出金
+    var withdrawInfos = await getWithdrawOutInfoV2(startTime, endTime)
+    // console.log('getWithdrawOutInfoV2 withdrawInfos ', withdrawInfos)
+    return {
+        collectCoinsInfos: collectCoinsInfos,
+        withdrawInfos: withdrawInfos
+    }
+}
+
+function sortList(lists) {
+    lists.sort((a, b) => {
+        let t1 = new Date(a.dt)
+        let t2 = new Date(b.dt)
+        return t2.getTime() - t1.getTime()
+    })
+    return lists
+}
+
+async function getStatisticsInfoV2(day) {
+    // //今日
+    var startTime = utils.getLastDay(day, 'YYYY-MM-DD') + " 00:00:00"
+    var endTime = utils.getLastDay(day, 'YYYY-MM-DD') + " 23:59:59"
+    logger.info('getTotalOutGasFee', startTime, endTime)
+    var rangeData = await getServerData(startTime, endTime)
+    logger.info('getServerData rangeData', rangeData)
+
+    var allData = await getServerData(null, null)
+
+    logger.info('getServerData allData', allData)
+
+    var data = await http_request_get(utils.getLastDay(day, 'YYYYMMDD'))
+    logger.info('http_request_get data', data)
+    //获取当前账户总余额
+    var curBalances = await getAllBalanceV2()
+    logger.info('getAllBalanceV2 curBalances', curBalances)
+
+
+    return {
+        updateTime: utils.getLastDay(day, 'YYYY-MM-DD'),
+        todayTotalProfit: parseFloat(data.data.incomeUSDTotal) - parseFloat(rangeData.collectCoinsInfos.totalInGasFeeUsd + rangeData.withdrawInfos.totalOutGasFeeUsd),//今日收入
+        todayTotalOutGasFee: rangeData.collectCoinsInfos.totalInGasFeeUsd + rangeData.withdrawInfos.totalOutGasFeeUsd,//今日总支出的 gas fee
+        canNotWithdrawUSD: parseFloat(data.data.canNotWithdrawUSD),                                    //不可提现余额
+        canWithdrawUSD: parseFloat(data.data.canWithdrawUSD),                                          //可提现余额
+        todayIncomeUSDTotal: parseFloat(data.data.incomeUSDTotal),                                     //今日总收入
+        todayIncomeUSDFee: parseFloat(data.data.incomeUSDFee),                                         //今日固定收入
+        totalOutGasFee: allData.collectCoinsInfos.totalInGasFeeUsd + allData.withdrawInfos.totalOutGasFeeUsd, //总支出 gas fee
+        totalWithdrawGasFee: allData.withdrawInfos.totalOutGasFeeUsd,                        //总提币 gas fee
+        totalCollectCoinsGasFee: allData.collectCoinsInfos.totalInGasFeeUsd,                            //总归集 gas fee
+        totalInFee: allData.collectCoinsInfos.totalInFee,                                               //总入金
+        totalNativeInFee: allData.collectCoinsInfos.totalNativeInFee,                                   //总 native 入金
+        totalOutFee: allData.withdrawInfos.totalWithdrawUsd,                                            //总出金
+        totalBalances: curBalances.totalUsd,                                                            //总余额
+        ylGasBalance: curBalances.totalNativeBalanceUsd - allData.collectCoinsInfos.totalNativeInFee,   //预留 gas 费余额  native 总余额 - 总入金
+        slGasBalance: allData.collectCoinsInfos.slTotalGasFeeUsd,   //散落 gas 费余额  充值 0.5 gas - 使用 0.3 gas= 散落 0.2gas
+
+        todayInUsdLists: sortList(rangeData.collectCoinsInfos.infos),//入金列表
+        todayOutUsdLists: sortList(rangeData.withdrawInfos.infos),//出金列表
+        totalInUsdLists: sortList(allData.collectCoinsInfos.infos),//总入金列表
+        totalOutUsdLists: sortList(allData.withdrawInfos.infos),//总出金列表
+        totalBalanceLists: curBalances.infos //总余额
+    }
+}
+
+
+
+
+
+
+
+const getFeishuToken = async (params) => {
+    return new Promise(resolve => {
+        axios.post(feishu_write_table_token_url,
+            {
+                app_id: "cli_a223f015abbad00e",
+                app_secret: "DMCF6tBwIpeOQPnWrFUMYd6tmjb53C4n"
+            },
+            {
+                timeout: 1 * 60 * 1000,
+                headers: {
+                    'Content-Type': "application/json; charset=utf-8"
+                }
+            })
+            .then(res => {
+                logger.log('getFeishuToken res=>', res.status, res.data);
+                resolve(res.data)
+            }).catch(err => {
+                logger.error('getFeishuToken error ', JSON.stringify(err));
+                resolve(JSON.stringify(err))
+            });
+    })
+}
+
+
+function writeTable(app_token, data) {
+    logger.info('writeTable', data)
+    var body = {
+        'valueRanges': [
+            {
+                'range': '0pRQpu!A2:C2',
+                'values': [
+                    [data.totalCollectCoinsGasFee, //归集总 gas
+                    data.totalWithdrawGasFee, //提币总 gas
+                    data.totalOutGasFee], //总支出 gas
+                ]
+            },
+            {
+                'range': '1ygrMB!A2:B2',
+                'values': [
+                    [
+                        data.totalInFee, //总入金
+                        data.totalOutFee,//总出金
+                    ],
+                ]
+            },
+            {
+                'range': 'BMjMDr!A3:J3',
+                'values': [
+                    [
+                        data.updateTime,      //更新时间
+                        data.todayTotalProfit,//今日总利润
+                        data.todayIncomeUSDTotal,//今日总收入
+                        data.todayIncomeUSDFee,//今日固定手续费收入
+                        data.todayTotalOutGasFee,//今日总 gas 支出
+                        data.totalBalances, //总余额
+                        data.canNotWithdrawUSD, //不可提现余额
+                        data.canWithdrawUSD,//可提现余额
+                        data.ylGasBalance.total,//预留 gas
+                        data.slGasBalance.total,//散落 gas
+                    ],
+                ]
+            }
+        ]
+    }
+    return new Promise(resolve => {
+        axios.post(feishu_write_table_data_url,
+            body,
+            {
+                timeout: 1 * 60 * 1000,
+                headers: {
+                    'Content-Type': "application/json; charset=utf-8",
+                    'Authorization': 'Bearer ' + app_token
+                }
+            })
+            .then(res => {
+                logger.log('writeTable res=>', res.status, res.data);
+                resolve(res.data)
+            }).catch(err => {
+                logger.error('writeTable error ', JSON.stringify(err));
+                resolve(JSON.stringify(err))
+            });
+    })
+}
+
+async function getTableRows(app_token, index) {
+    return new Promise(resolve => {
+        axios.get(feishu_get_table_metadata_url,
+            {
+                timeout: 1 * 60 * 1000,
+                headers: {
+                    'Content-Type': "application/json; charset=utf-8",
+                    'Authorization': 'Bearer ' + app_token
+                }
+            })
+            .then(res => {
+                console.log('res=>', res.status, res.data, res.data.data.sheets);
+                resolve(res.data.data.sheets[index].rowCount)
+            }).catch(err => {
+                logger.error('error ', JSON.stringify(err));
+                resolve(0)
+            });
+    })
+}
+
+async function delTableRows(app_token, sheetId, startIndex, endIndex) {
+    var body = {
+        dimension: {
+            sheetId: sheetId,
+            majorDimension: 'ROWS',
+            startIndex: startIndex,
+            endIndex: endIndex,
+        },
+    }
+
+
+    return new Promise(resolve => {
+        axios.delete(feishu_delete_table_url,
+            {
+                data: body,
+                timeout: 1 * 60 * 1000,
+                headers: {
+                    'Content-Type': "application/json; charset=utf-8",
+                    'Authorization': 'Bearer ' + app_token
+                }
+            })
+            .then(res => {
+                console.log('delTableRows res=>', res.status, res.data);
+                resolve(res.data)
+            }).catch(err => {
+                logger.error('delTableRows error ', JSON.stringify(err));
+                resolve(JSON.stringify(err))
+            });
+    })
+}
+
+async function insertTableRows(app_token, sheetId, startIndex, endIndex) {
+    var body = {
+        dimension: {
+            sheetId: sheetId,
+            majorDimension: 'ROWS',
+            startIndex: startIndex,
+            endIndex: endIndex,
+        },
+        inheritStyle: 'AFTER'
+    }
+    return new Promise(resolve => {
+        axios.post(feishu_insert_table_url,
+            JSON.stringify(body),
+            {
+                timeout: 1 * 60 * 1000,
+                headers: {
+                    'Content-Type': "application/json; charset=utf-8",
+                    'Authorization': 'Bearer ' + app_token
+                }
+            })
+            .then(res => {
+                console.log('res=>', res.status, res.data);
+                resolve(res.data)
+            }).catch(err => {
+                logger.error('error ', JSON.stringify(err));
+                resolve(JSON.stringify(err))
+            });
+    })
+}
+
+async function addTableRows(app_token, sheetId, endIndex) {
+    var body = {
+        dimension: {
+            sheetId: sheetId,
+            majorDimension: 'ROWS',
+            length: endIndex,
+        },
+    }
+    return new Promise(resolve => {
+        axios.post(feishu_create_table_url,
+            JSON.stringify(body),
+            {
+                timeout: 1 * 60 * 1000,
+                headers: {
+                    'Content-Type': "application/json; charset=utf-8",
+                    'Authorization': 'Bearer ' + app_token
+                }
+            })
+            .then(res => {
+                console.log('res=>', res.status, res.data);
+                resolve(res.data)
+            }).catch(err => {
+                logger.error('error ', JSON.stringify(err));
+                resolve(JSON.stringify(err))
+            });
+    })
+}
+
+async function exec(data) {
+    var app = await getFeishuToken()
+    // await insertTableRows(app.app_access_token, 'Ji1hLG', 2, data.totalInUsdLists.length)
+    // await insertTableRows(app.app_access_token, 'aFCrrP', 2, data.totalOutUsdLists.length)
+
+    var rows = await getTableRows(app.app_access_token, 2)
+    if (rows > 1) {
+        logger.info('getTableRows', rows)
+        await delTableRows(app.app_access_token, '2hNaot', 2, rows)
+        await addTableRows(app.app_access_token, '2hNaot', rows)
+    }
+
+    // await writeTable(app.app_access_token, data)
+}
+
+async function report2FeishuTable() {
+    try {
+        logger.error('数据统计 start')
+        logger.info('report2FeishuTable')
+        var data = await getStatisticsInfoV2(2);
+        logger.info('getStatisticsInfo', data)
+        var ret = await exec(data)
+        logger.error('数据统计 end', 'https://st94nif1cq.feishu.cn/sheets/shtcnp6zbrsep1Sz3Cvk7NXRpDg?sheet=BMjMDr', JSON.stringify(data), JSON.stringify(ret))
+        mTokenPriceCache.clear()
+    } catch (error) {
+        logger.error('report2FeishuTable', error.toString())
+    }
+
+}
+
+
+async function test() {
+    // var ret = await getStatisticsInfoV2(2)
+    // logger.debug('getStatisticsInfoV2', await getStatisticsInfoV2(2), mTokenPriceCache.size)
+    report2FeishuTable()
+}
+// test()
+// exec()
+module.exports = {
+    getStatisticsInfoV2
+}
+
+
+

+ 48 - 11
model/utils.js

@@ -102,6 +102,16 @@ const CHAIN_NAME = {
     okc_mainnet: 'okc_mainnet',
 }
 
+const CHAIN_TOKEN_TYPE = {
+    bsc_testnet: 'erc20',
+    bsc_mainnet: 'erc20',
+    czz: 'czz',
+    kcc_testnet: 'kcc_testnet',
+    kcc_mainnet: 'kcc_mainnet',
+    okc_testnet: 'okc_testnet',
+    okc_mainnet: 'okc_mainnet',
+}
+
 const CHAIN_ID = {
     eth: '0x1',
     bsc_testnet: '0x61',
@@ -117,10 +127,10 @@ const CHAIN_ID_NAME = {
     97: 'bsc_testnet',
     56: 'bsc_mainnet',
     2019: 'czz',
-    65: 'okc_testnet',
-    66: 'okc_mainnet',
-    321: 'kcc_mainnet',
-    322: 'kcc_testnet',
+    65: 'okc',
+    66: 'okc',
+    321: 'kcc',
+    322: 'kcc',
 }
 
 const USE_SDK = {
@@ -138,7 +148,7 @@ function getRedisKeyFromChain(chain) {
         case '56':
             return '_BSC'
         case CHAIN_NAME.czz:
-        case CHAIN_ID.czz :
+        case CHAIN_ID.czz:
             return '_CZZ'
         case CHAIN_NAME.kcc_mainnet:
         case CHAIN_NAME.kcc_testnet:
@@ -155,6 +165,20 @@ function getRedisKeyFromChain(chain) {
     }
 }
 
+function getTokenTransferType(chain) {
+    switch (chain) {
+        case CHAIN_NAME.bsc_mainnet:
+        case CHAIN_NAME.bsc_testnet:
+        case 'bsc_testnet':
+        case 'bsc_mainnet':
+        case '97':
+        case '56':
+            return 'erc20'
+        default:
+            return 'token'
+    }
+}
+
 function trim(str) {
     try {
         return str.replace(/(^\s*)|(\s*$)/g, "");
@@ -185,6 +209,16 @@ function getTimestamp() {
     return new Date().getTime()
 }
 
+function contain(str, char) {
+    try {
+        return str.indexOf(char) != -1
+    } catch (error) {
+        logger.error()
+        return false
+    }
+}
+
+
 function getCurrentDate() {
     return chinaTime('YYYY-MM-DD HH:mm:ss');
 }
@@ -193,14 +227,14 @@ function getCurrentDateFormat(format) {
     return chinaTime(format);
 }
 
-function chinaTimeMs(format, ms) {
-    return format
-        ? moment(ms).tz('Asia/Shanghai').format(format)
-        : new Date(moment(ms).tz('Asia/Shanghai').format('YYYY-MM-DD HH:mm'));
+function chinaTimeMs(ms) {
+    return moment(ms).tz('Asia/Shanghai').format('YYYY-MM-DD HH:mm:ss');
 }
 
-function getLastDay(format) {
-    return moment().subtract(1, 'day').tz('Asia/Shanghai').format(format)
+function getLastDay(day, format) {
+    return day ?
+        moment().subtract(day, 'day').tz('Asia/Shanghai').format(format)
+        : moment().subtract(1, 'day').tz('Asia/Shanghai').format(format)
 }
 
 function getTimestampToDate(tm) {
@@ -261,4 +295,7 @@ module.exports = {
     getRedisKeyFromChain,
     trim,
     getLastDay,
+    chinaTimeMs,
+    contain,
+    getTokenTransferType,
 }

+ 12 - 9
routes/sdk.js

@@ -8,7 +8,7 @@ const redis = require("../model/db/redis_db")  //导入 db.js
 const withdraw_db = require("../model/db/withdraw_db")  //导入 db.js
 const report = require("../model/report")  //导入 db.js
 const BigNumber = require('bignumber.js')
-const czz = require('../model/czz')
+const czz = require('../model/http_withdraw')
 var remote_config_db = require("../model/db/remote_config_db");
 const account_mysql = require("../model/db/account_info_db")  //导入 db.js
 var collect_coins_db = require("../model/db/collect_coins_db");
@@ -103,9 +103,9 @@ async function getCollectCoinsHash(trx_hash) {
 function isExistHash(trx_hash, arrs) {
     if (arrs && Array.isArray(arrs) && arrs.length > 0) {
         var ret = arrs.filter(element => {
-           return element.gas_trx_hash == trx_hash
+            return element.gas_trx_hash == trx_hash
         })
-        logger.info('isExistHash',trx_hash,ret)
+        logger.info('isExistHash', trx_hash, ret)
         return ret == null ? false : ret.length > 0
     } else {
         return false
@@ -123,7 +123,7 @@ async function filterTransfers(result) {
                 for (let index = 0; index < ret.data.results.length; index++) {
                     const element = ret.data.results[index];
                     // if (element.trx_hash == await getCollectCoinsHash(element.trx_hash)) {
-                    if (isExistHash(element.trx_hash,filter_list)) {
+                    if (isExistHash(element.trx_hash, filter_list)) {
                         logger.debug('element.trx_hash == await getCollectCoinsHash(element.trx_hash)', element)
                     } else {
                         new_ret.push(element)
@@ -239,6 +239,10 @@ async function check_czz_withdraw_task() {
                 continue
             }
 
+            if (!exec_obj.txn_hash || !exec_obj.chain) {
+                logger.error('check_withdraw_status error:',JSON.stringify(exec_obj))
+                continue
+            }
             var obj = await czz.check_withdraw_status(exec_obj)
             if (obj.code == 0) {
                 var nonce = obj.data.nonce
@@ -446,8 +450,7 @@ async function withdraw_task() {
                     try {
                         curGasPrice = BigNumber(obj.data.gasPrice.hex).toNumber()
                         curGasLimit = BigNumber(obj.data.gasLimit.hex).toNumber()
-                        //不是 czz chain
-                        if (obj.data.chainId != 2019) {
+                        if (!obj.data.value.number) {
                             value = BigNumber(obj.data.value.hex).toNumber()
                         } else {
                             value = obj.data.value.number
@@ -851,9 +854,9 @@ router.post('/getAllTokenWithdrawInfoLists', getAllTokenWithdrawInfoLists)
 withdraw_task();
 collect_conis_task();
 // //czz 504 检查
-// check_czz_withdraw_task();
-// // bsc 监控
-// bsc_log_monitoring()
+check_czz_withdraw_task();
+// bsc 监控
+bsc_log_monitoring()
 
 if (process.env.NODE_ENV == 'dev' || process.env.NODE_ENV == 'test') {
     // timer_transfer_bsc_task()

+ 1 - 1
test/withdraw_czz.js

@@ -1,4 +1,4 @@
-const withdraw_test = require('../model/czz')
+const withdraw_test = require('../model/http_withdraw')
 const router = require('koa-router')() //导入 koa-router