Bläddra i källkod

Merge branch 'opt-code' into test

DevYK 2 år sedan
förälder
incheckning
8e8f0090d1

+ 11 - 12
config/dev_config.js

@@ -19,6 +19,7 @@ const account_config = {
     TRANSFER_GAS: true,
     FEISHU_URL: 'https://open.feishu.cn/open-apis/bot/v2/hook/18dfe21f-b1bd-46ca-a8c7-c85e1c84f02d',
     CZZ_BASEURL: "https://internal-block-payout-test.denet.me",
+    STATISTICS_URL: 'https://testapi.denetme.net/denet/wallet/stat/getMoneyStat?date='
 }
 
 const reids_token_config = {
@@ -46,7 +47,6 @@ const http_log_report_config = {
 // 设置数据库配置文件
 const db_config = {
     // 数据库配置
-
     mysql: {
         DATABASE: 'denet_chain',   //数据库名称
         DATABASE_MY_NODE: 'bnb_block_sync',   //自建 node 存储
@@ -59,7 +59,14 @@ const db_config = {
         POOL_SIZE: 5,
     },
 
-    // 数据库配置
+    redis: {
+        PORT: 6379, // Redis port
+        HOST: "denet-test.y2slbl.clustercfg.memorydb.us-east-1.amazonaws.com", // Redis host
+        USERNAME: null, // needs Redis >= 6
+        PASSWORD: null,
+    },
+
+    // 线上数据库配置
     // mysql: {
     //     DATABASE: 'denet_chain',   //数据库名称
     //     DATABASE_MY_NODE: 'bnb_block_sync',   //自建 node 存储
@@ -70,22 +77,14 @@ const db_config = {
     //     HOST: 'denet-chain-prod.csi2lctklqzg.us-east-1.rds.amazonaws.com', //host
     //     OPEN_POOL: true,
     //     POOL_SIZE: 5,
-
     // },
 
     // redis: {
     //     PORT: 6379, // Redis port
-    //     HOST: "r-bp1ps6my7lzg8rdhwxpi.redis.rds.aliyuncs.com", // Redis host
+    //     HOST: "denet-chain-prod.y2slbl.clustercfg.memorydb.us-east-1.amazonaws.com", // Redis host
     //     USERNAME: null,
-    //     PASSWORD: "Wqsd@2019"
+    //     PASSWORD: null,
     // },
-
-    redis: {
-        PORT: 6379, // Redis port
-        HOST: "denet-test.y2slbl.clustercfg.memorydb.us-east-1.amazonaws.com", // Redis host
-        USERNAME: null, // needs Redis >= 6
-        PASSWORD: null,
-    },
 }
 
 // 设置 moralis sdk 配置文件

+ 1 - 0
config/prd_config.js

@@ -12,6 +12,7 @@ const account_config = {
     TRANSFER_GAS: true,
     FEISHU_URL: 'https://open.feishu.cn/open-apis/bot/v2/hook/9ab2594f-3d27-4f70-a5ed-a6aee0420aa6',
     CZZ_BASEURL: "https://internal-block-payout.denet.me",
+    STATISTICS_URL:'https://api.denetme.net/denet/wallet/stat/getMoneyStat?date='
 }
 
 const cryppt_config = {

+ 1 - 0
config/test_config.js

@@ -12,6 +12,7 @@ const account_config = {
     TRANSFER_GAS: true,
     FEISHU_URL: 'https://open.feishu.cn/open-apis/bot/v2/hook/18dfe21f-b1bd-46ca-a8c7-c85e1c84f02d',
     CZZ_BASEURL: "https://internal-block-payout-test.denet.me",
+    STATISTICS_URL:'https://testapi.denetme.net/denet/wallet/stat/getMoneyStat?date='
 }
 
 const cryppt_config = {

+ 1 - 1
model/db/account_info_db.js

@@ -219,7 +219,7 @@ async function getAccountBalances(opts) {
                         // decimals = await redis.readRedis('REDIS_ERC20_CONTRACT_DECIMALS_' + element.token_address.toLowerCase())
                         decimals = await redis.readAppendRedis('REDIS_ERC20_CONTRACT_DECIMALS', opts.chain, element.token_address.toLowerCase())
                     } catch (error) {
-
+                        
                     }
                     results.push({
                         type: 'token',

+ 14 - 7
model/db/collect_coins_db.js

@@ -8,9 +8,14 @@ const utils = require('../utils.js')
 /**
  * 查询归集入账总金额和总消耗的 gas fee
  */
-async function query_collect_total_fee() {
-    var sql = 'select * from collect_coins_manage WHERE status=?'
-    var param = [0]
+async function query_collect_total_fee(startTime, endTime) {
+    var sql = 'select * from collect_coins_manage WHERE status=? AND update_time>=? AND update_time<=? '
+    var param = [0, startTime, endTime]
+    if (!startTime && !endTime) {
+        sql = 'select * from collect_coins_manage WHERE status=? '
+        param = [0]
+    }
+
     // sql = 'select * from collect_coins_manage'
     // param=[]
     return new Promise((resolve) => {
@@ -29,7 +34,7 @@ async function query_collect_total_fee() {
                         resolve(null);
                         return;
                     }
-                    logger.log('query_collect_total_fee ret=', error, results);
+                    // logger.log('query_collect_total_fee ret=', error, results);
                     //用完当前连接需要释放,归还给连接池
                     connection.release();
                     resolve({
@@ -112,10 +117,12 @@ async function create_collect_coins_task(opts) {
 
     var gas_trx_hash = opts.gas_trx_hash ? opts.gas_trx_hash : ''
 
-    var create_withdraw_sql = 'INSERT INTO collect_coins_manage (user_address,balances,transfers,prestore_gas_fee,company_public_key,total_gas_fee,status,create_time,update_time,resposes,error_msg,chain,gas_trx_hash)' +
-        'VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)'
+    var before_gas_fee = opts.before_gas_fee ? opts.before_gas_fee : ''
+
+    var create_withdraw_sql = 'INSERT INTO collect_coins_manage (user_address,balances,transfers,prestore_gas_fee,company_public_key,total_gas_fee,status,create_time,update_time,resposes,error_msg,chain,gas_trx_hash,before_gas_fee)' +
+        'VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)'
     var chain = opts.chain
-    var create_withdraw_params = [user_address, JSON.stringify(balances), JSON.stringify(transfers), JSON.stringify(prestore_gas_free), company_public_key, total_gas_fee, status, create_time, update_time, resposes, error_msg ? error_msg : '', chain, gas_trx_hash]
+    var create_withdraw_params = [user_address, JSON.stringify(balances), JSON.stringify(transfers), JSON.stringify(prestore_gas_free), company_public_key, total_gas_fee, status, create_time, update_time, resposes, error_msg ? error_msg : '', chain, gas_trx_hash, before_gas_fee]
 
     logger.log('create_collect_coins_task create_collect_coins_task_sql', create_withdraw_sql, create_withdraw_params);
     return new Promise((resolve) => {

+ 12 - 4
model/db/withdraw_db.js

@@ -20,6 +20,9 @@ async function create_withdraw_task(task_obj) {
     }
     //提币任务创建时间
     var withdraw_create_time = utils.getTimestamp();
+
+    // withdraw_create_time = utils.getCurrentDate()
+
     var from_address = task_obj.user_address
     var to_address = task_obj.receiver
     var contract_address = task_obj.contractAddress
@@ -174,9 +177,14 @@ function queryWithdrawInfoFromWithdrawId(withdrawId) {
 
 
 
-function getWidthdrawTotalFee() {
-    var create_withdraw_sql = 'select * from withdraw_manage WHERE withdraw_status=? AND chain_id=? '
-    var create_withdraw_params = [2, 56]
+function getWidthdrawTotalFee(startTime, endTime) {
+    var create_withdraw_sql = 'select * from withdraw_manage WHERE withdraw_status=? AND  update_time>=? AND update_time<=? '
+    var create_withdraw_params = [2, startTime, endTime]
+
+    if (!startTime && !endTime) {
+        create_withdraw_sql = 'select * from withdraw_manage WHERE withdraw_status=? '
+        create_withdraw_params = [2]
+    }
     return new Promise((resolve) => {
         mysql.getMySqlInstance().getConnection(function (err, connection) {
             if (err) {
@@ -193,7 +201,7 @@ function getWidthdrawTotalFee() {
                         resolve(null);
                         return;
                     }
-                    logger.log('getWidthdrawTotalFee ret=', error, results);
+                    // logger.log('getWidthdrawTotalFee ret=', error, results);
                     //用完当前连接需要释放,归还给连接池
                     connection.release();
                     if (results && Array.isArray(results) && results.length > 0) {

+ 4 - 0
model/moralis_sdk.js

@@ -607,6 +607,7 @@ async function transfers(obj, my_account_all_coins, logParams) {
         logParams.results = collects
         logParams.collects = JSON.stringify(collects_mysql)
         logParams.createTime = obj.createTime
+        logParams.before_gas_fee =obj.before_gas_fee
         if (obj.address)
             logParams.user_address = obj.address
         if (t_i == my_account_all_coins.transfer_arrays.length) {
@@ -884,6 +885,8 @@ const collectCoins = async (obj) => {
 
         obj.chain = chain;
         obj.transFerGasFree = transFerGasFree;
+        if (transfer.totalGasFree)
+            obj.before_gas_fee = transfer.totalGasFree
         logParams.chain = chain
         logger.log('transfers--->', obj);
         var ret = await transfers(obj, my_account_all_coins, logParams);
@@ -1691,6 +1694,7 @@ module.exports = {
     queryCollectBalance,
     queryCompanyInfoFromId,
     getAccountAllCoins,
+    findTokenPriceItem,
 }
 
 

+ 8 - 8
model/report.js

@@ -29,15 +29,15 @@ const http_request_post = async (params) => {
     var path = http_log_report_config.PATH
     var url = host + path
     var url = host + path
-    logger.log('http_request_post eventData', params.eventData)
-    logger.log('http_request_post', JSON.stringify(data), url)
+    // logger.log('http_request_post eventData', params.eventData)
+    // logger.log('http_request_post', JSON.stringify(data), url)
 
-    axios.post(url, data)
-        .then(res => {
-            logger.log('res=>', res.status, res.data);
-        }).catch(err => {
-            logger.error('http_request_post', err.toString(),url.toString());
-        });
+    // axios.post(url, data)
+    //     .then(res => {
+    //         logger.log('res=>', res.status, res.data);
+    //     }).catch(err => {
+    //         logger.error('http_request_post', err.toString(),url.toString());
+    //     });
 }
 
 /**

+ 702 - 0
model/server_data_statistics.js

@@ -0,0 +1,702 @@
+const logger = require('../model/logger')
+var remote_config_db = require("../model/db/remote_config_db");
+var collect_coins_db = require("../model/db/collect_coins_db");
+var withdraw_db = require("../model/db/withdraw_db");
+var moralis = require("../model/moralis_sdk");
+var utils = require("../model/utils");
+const axios = require('axios');
+var { account_config } = require('../config/config.js');
+const { max } = require('moment');
+
+// 拿到飞书写入的 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 reportTime = '08:00:00'
+
+//########################################### 出入金数据统计 ########################################
+
+const http_request_get = async (data) => {
+    var host = account_config.STATISTICS_URL
+    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'
+                    }
+                })
+            });
+    })
+}
+
+async function computeAddressPrice(total_in_coins) {
+    //计算总的价格
+    for (key of total_in_coins.keys()) {
+        var item = total_in_coins.get(key)
+        var amount = item.amount
+        var usdPrice = item.usdPrice
+        if (key == '0x0000000000000000000000000000000000000000') {
+            item.totalUsdPrice = parseFloat(amount) / parseFloat(10 ** 18) * parseFloat(usdPrice)
+        } else {
+            var decimals = 18
+            try {
+                decimals = await redis.readAppendRedis('REDIS_ERC20_CONTRACT_DECIMALS', item.chain, key.toLowerCase())
+                logger.info('REDIS_ERC20_CONTRACT_DECIMALS', key.toLowerCase(), decimals)
+            } catch (error) {
+                decimals = 18
+            }
+            item.totalUsdPrice = parseFloat(amount) / parseFloat(10 ** decimals) * parseFloat(usdPrice)
+        }
+    }
+}
+
+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 filterCollectCoinsLists(collect_ret, filterTypt) {
+    const total_in_coins = new Map();
+    var total_gas_fee = 0
+    for (let index = 0; index < collect_ret.results.length; index++) {
+        const element = collect_ret.results[index];
+        if (element.chain == null || element.chain == filterTypt) {
+            var before_gas_fee = element.before_gas_fee ? BigInt(element.before_gas_fee) : element.chain == 'czz' ? BigInt(21000 * 2000000000) : BigInt(21000 * 5000000000)
+            total_gas_fee = BigInt(element.total_gas_fee) + BigInt(before_gas_fee) + BigInt(total_gas_fee)
+            if (element.transfers) {
+                var opts = JSON.parse(element.transfers)
+                for (let index = 0; index < opts.length; index++) {
+                    const transfers = opts[index];
+                    if (transfers.chain == filterTypt) {
+                        var address = transfers.contractAddress ? transfers.contractAddress : '0x0000000000000000000000000000000000000000'
+                        if (total_in_coins.get(address) != null) {
+                            var ins = total_in_coins.get(address)
+                            ins.amount = BigInt(ins.amount) + BigInt(transfers.amount)
+                            total_in_coins.set(address, ins)
+                        } else {
+                            total_in_coins.set(address, {
+                                amount: BigInt(transfers.amount), //总入金
+                                usdPrice: transfers.usdPrice,
+                                chain: transfers.chain,
+                            })
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+
+    //计算总的价格
+    await computeAddressPrice(total_in_coins)
+
+    var bsc_env = getBscEnv()
+
+    //获取 total gas
+    try {
+        if (total_in_coins.size > 0) {
+            switch (filterTypt) {
+                case 'bsc_testnet':
+                case 'bsc_mainnet':
+                    var price = await moralis.getAllTotkenPrice({ chain: bsc_env })
+                    if (typeof price === 'string') {
+                        price = JSON.parse(price)
+                    }
+                    var bnbPriceItem = moralis.findTokenPriceItem('0x0000000000000000000000000000000000000000', price)
+                    total_gas_fee = parseFloat(total_gas_fee) / parseFloat(10 ** 18) * parseFloat(bnbPriceItem.usdPrice)
+                    logger.info('new-total_gas_fee ', total_gas_fee, bnbPriceItem)
+                    break
+                case 'czz':
+                    var price = await moralis.getAllTotkenPrice({ chain: 'czz' })
+                    if (typeof price === 'string') {
+                        price = JSON.parse(price)
+                    }
+                    var czzPriceItem = moralis.findTokenPriceItem('0x0000000000000000000000000000000000000000', price)
+                    total_gas_fee = parseFloat(total_gas_fee) / parseFloat(10 ** 18) * parseFloat(czzPriceItem.usdPrice)
+                    logger.info('new-total_gas_fee czz', total_gas_fee, czzPriceItem)
+                    break
+            }
+        }
+    } catch (error) {
+        logger.error('total_gas_fee', error)
+    }
+
+
+    if (!total_in_coins.get('0x0000000000000000000000000000000000000000')) {
+        total_in_coins.set('0x0000000000000000000000000000000000000000', {
+            amount: 0,
+            usdPrice: 0,
+            chain: filterTypt,
+            totalUsdPrice: 0
+        })
+    }
+    return {
+        map: total_in_coins,
+        totalGasFee: total_gas_fee //总入金所消耗的 gas fee
+    }
+}
+
+function sumBalance(map) {
+    var balances = 0;
+    for (key of map.keys()) {
+        balances += map.get(key).totalUsdPrice
+    }
+    return balances
+}
+
+async function getSLGas() {
+    var maps = new Map()
+    var collect_ret = await collect_coins_db.query_collect_total_fee(null, null);
+    for (let index = 0; index < collect_ret.results.length; index++) {
+        var element = collect_ret.results[index]
+        try {
+            if (element.prestore_gas_fee && typeof element.prestore_gas_fee === 'string') {
+                var pre_gas_obj = JSON.parse(element.prestore_gas_fee)
+
+                var bgf = element.before_gas_fee
+                if (!bgf && pre_gas_obj.amount) {
+                    bgf = pre_gas_obj.amount
+                }
+
+                // logger.info('getSLGas item', bgf, pre_gas_obj, element)
+                if (maps.get(pre_gas_obj.chain)) {
+                    maps.get(pre_gas_obj.chain).sl_gas_fee = BigInt(maps.get(pre_gas_obj.chain).sl_gas_fee) + (BigInt(pre_gas_obj.amount) - BigInt(bgf))
+                } else {
+                    maps.set(pre_gas_obj.chain, {
+                        sl_gas_fee: BigInt(pre_gas_obj.amount) - BigInt(bgf)
+                    })
+                }
+            }
+        } catch (error) {
+            logger.error('getSLGas error', error.toString())
+        }
+    }
+
+    var bsc_env = getBscEnv()
+
+    logger.info('getSLGas', maps)
+
+    var bsc_sl
+    var czz_sl
+    for (key of maps.keys()) {
+        var item = maps.get(key)
+        switch (key) {
+            case "bsc_mainnet":
+            case "bsc_testnet":
+                var price = await moralis.getAllTotkenPrice({ chain: bsc_env })
+                if (typeof price === 'string') {
+                    price = JSON.parse(price)
+                }
+                var bnbPriceItem = moralis.findTokenPriceItem('0x0000000000000000000000000000000000000000', price)
+                bsc_sl = parseFloat(item.sl_gas_fee) / parseFloat(10 ** 18) * parseFloat(bnbPriceItem.usdPrice)
+                break
+            case "czz":
+                var price = await moralis.getAllTotkenPrice({ chain: 'czz' })
+                if (typeof price === 'string') {
+                    price = JSON.parse(price)
+                }
+                var czzPriceItem = moralis.findTokenPriceItem('0x0000000000000000000000000000000000000000', price)
+                czz_sl = parseFloat(item.sl_gas_fee) / parseFloat(10 ** 18) * parseFloat(czzPriceItem.usdPrice)
+                break
+        }
+    }
+
+    return {
+        bsc: bsc_sl,
+        czz: czz_sl,
+        total: bsc_sl + czz_sl
+    }
+}
+
+async function getCollectCoinsOutInfo(startTime, endTime) {
+    var collect_ret = await collect_coins_db.query_collect_total_fee(startTime, endTime);
+    logger.info('getCollectCoinsOutInfo query_collect_total_fee', startTime, endTime)
+
+    var bsc_env = getBscEnv()
+
+    var bsc_envnet = await filterCollectCoinsLists(collect_ret, bsc_env)
+    logger.info('getCollectCoinsOutInfo bsc_env', bsc_env, bsc_envnet)
+    var czz = await filterCollectCoinsLists(collect_ret, 'czz')
+    logger.info('getCollectCoinsOutInfo czz', czz)
+
+    logger.info('getCollectCoinsOutInfo total ', bsc_envnet.totalGasFee, czz.totalGasFee)
+    return {
+        bsc: bsc_envnet.map,
+        czz: czz.map,
+        totalGasFee: parseFloat(bsc_envnet.totalGasFee) + parseFloat(czz.totalGasFee), //总归集消耗的 gas fee
+        totalInFee: sumBalance(bsc_envnet.map) + sumBalance(czz.map),//总入金美元
+    }
+}
+
+async function filterWithdrawTotalOutFee(chain_id, filterItem) {
+    const withdraw_out_map = new Map();
+
+    var price = await moralis.getAllTotkenPrice({ chain: chain_id + "" })
+    if (typeof price === 'string') {
+        price = JSON.parse(price)
+    }
+
+
+    for (let index = 0; index < filterItem.length; index++) {
+        const element = filterItem[index];
+        if (element.chain_id == chain_id) {
+            var address = element.type == 'native' ? '0x0000000000000000000000000000000000000000' : element.contract_address
+            if (withdraw_out_map.get(address) != null) {
+                var item = withdraw_out_map.get(address)
+                item.totalAmount = BigInt(element.amount) + BigInt(item.totalAmount)
+            } else {
+                var priceItem = moralis.findTokenPriceItem(address, price)
+                var decimals = 18
+
+                if (key == '0x0000000000000000000000000000000000000000') {
+                    item.totalUsdPrice = parseFloat(amount) / parseFloat(10 ** 18) * parseFloat(usdPrice)
+                } else {
+                    try {
+                        decimals = await redis.readAppendRedis('REDIS_ERC20_CONTRACT_DECIMALS', chain_id + "", address.toLowerCase())
+                        logger.info('REDIS_ERC20_CONTRACT_DECIMALS', key.toLowerCase(), decimals)
+                    } catch (error) {
+                        decimals = 18
+                    }
+                }
+                withdraw_out_map.set(address, {
+                    totalAmount: BigInt(element.amount), //出金数量
+                    usdPrice: priceItem.usdPrice,
+                    chain: element.chain_id,
+                    decimals: decimals,
+                })
+            }
+        }
+    }
+
+    logger.info('filterWithdrawTotalOutFee', withdraw_out_map, chain_id)
+    return withdraw_out_map
+}
+
+async function getWithdrawOutInfo(startTime, endTime) {
+    if (startTime && endTime) {
+        startTime = new Date(startTime).getTime()
+        endTime = new Date(endTime).getTime()
+    }
+    var withdraw_ret = await withdraw_db.getWidthdrawTotalFee(startTime, endTime)
+    const withdraw_gas_map = new Map();
+    for (let index = 0; index < withdraw_ret.length; index++) {
+        const element = withdraw_ret[index];
+        if (element.gas_price && element.gas_limit)
+            var total_gas_fee2 = (BigInt(element.gas_price) * BigInt(element.gas_limit))
+        if (withdraw_gas_map.get(element.chain_id) != null) {
+            withdraw_gas_map.get(element.chain_id).total_gas_fee = BigInt(withdraw_gas_map.get(element.chain_id).total_gas_fee) + BigInt(total_gas_fee2)
+        } else {
+            withdraw_gas_map.set(element.chain_id,
+                {
+                    total_gas_fee: BigInt(total_gas_fee2),
+                    total_withdraw: null
+                }
+            )
+        }
+    }
+
+    var bsc_env = getBscEnv()
+
+    //计算总消耗的 gas
+    var keys = withdraw_gas_map.keys();
+    var total_gas_fee = 0
+    for (key of keys) {
+        // console.log(key, withdraw_gas_map.get(key));  // map.get(key)可得value值。
+        var value = withdraw_gas_map.get(key).total_gas_fee
+        //获取币价
+        try {
+            if (key == 2019) {
+                var price = await moralis.getAllTotkenPrice({ chain: 'czz' })
+                if (typeof price === 'string') {
+                    price = JSON.parse(price)
+                }
+                var czzPriceItem = moralis.findTokenPriceItem('0x0000000000000000000000000000000000000000', price)
+                total_gas_fee += parseFloat(value) / parseFloat(10 ** 18) * parseFloat(czzPriceItem.usdPrice)
+                logger.info('new-total_gas_fee czz', total_gas_fee, czzPriceItem)
+            } else {
+                var price = await moralis.getAllTotkenPrice({ chain: bsc_env })
+                if (typeof price === 'string') {
+                    price = JSON.parse(price)
+                }
+                var bnbPriceItem = moralis.findTokenPriceItem('0x0000000000000000000000000000000000000000', price)
+                total_gas_fee += parseFloat(value) / parseFloat(10 ** 18) * parseFloat(bnbPriceItem.usdPrice)
+                logger.info('new-total_gas_fee bsc', total_gas_fee, bnbPriceItem)
+            }
+        } catch (error) {
+            logger.error('total_gas_fee', error)
+        }
+    }
+    var withdrawout = 0
+    if (!startTime && !endTime) {
+        for (key of withdraw_gas_map.keys()) {
+            try {
+                var outs = await filterWithdrawTotalOutFee(key, withdraw_ret)
+                withdraw_gas_map.get(key).total_withdraw = outs
+                // logger.error('withdraw_gas_map.get(key).total_withdraw outs', outs)
+                if (outs) {
+                    for (ckey of outs.keys()) {
+                        var item = outs.get(ckey);
+                        withdrawout = parseFloat(withdrawout) + (parseFloat(item.totalAmount) / parseFloat(10 ** item.decimals) * parseFloat(item.usdPrice))
+                    }
+                }
+            } catch (error) {
+                logger.error('filterWithdrawTotalOutFee error', error.toString())
+            }
+        }
+    }
+    return {
+        outmap: withdraw_gas_map,
+        totalGasFee: total_gas_fee,
+        totalWithdraw: withdrawout
+    };
+}
+
+async function updateBalance(obj, type) {
+    var price
+    if (type == 'bsc') {
+        var bsc_env = getBscEnv()
+        price = await moralis.getAllTotkenPrice({ chain: bsc_env })
+    } else if (type == 'czz') {
+        price = await moralis.getAllTotkenPrice({ chain: 'czz' })
+    }
+
+    if (typeof price === 'string') {
+        price = JSON.parse(price)
+    }
+    var priceItem = moralis.findTokenPriceItem('0x0000000000000000000000000000000000000000', price, price)
+
+    if (!obj.native.balance) {
+        obj.native.balance = '0'
+    }
+    if (obj.native) {
+        obj.native.usdPrice = parseFloat(obj.native.balance) / parseFloat(10 ** 18) * priceItem.usdPrice
+        logger.info('findTokenPriceItem 0x0000000000000000000000000000000000000000 ', obj, priceItem, type)
+    }
+
+    var tokenTotal = 0
+    if (obj.other && Array.isArray(obj.other)) {
+        for (let index = 0; index < obj.other.length; index++) {
+            const element = obj.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
+                tokenTotal += element.usdPrice
+            }
+        }
+    }
+    return {
+        nativeTotal: obj.native.usdPrice,
+        tokenTotal: tokenTotal,
+        total: parseFloat(obj.native.usdPrice) + parseFloat(tokenTotal)
+    }
+}
+
+async function getAllBalance() {
+    var bsc_env = getBscEnv()
+    var company = await moralis.queryCompanyInfoFromId(0)
+    logger.info('getAllBalance company', company)
+    var bsc_balance = await moralis.getAccountAllCoins({
+        chain: bsc_env,
+        address: company.user_address
+    })
+    logger.info('getAccountAllCoins bsc_balance', bsc_balance)
+    var bscb = await updateBalance(bsc_balance, 'bsc')
+    logger.info('getAccountAllCoins updateBalance bscb', bscb)
+    var czz_balance = await moralis.getAccountAllCoins({
+        chain: 'czz',
+        address: company.user_address
+    })
+    logger.info('getAccountAllCoins czz_balance', czz_balance)
+    var czzb = await updateBalance(czz_balance, 'czz')
+
+    logger.info('getAccountAllCoins updateBalance czzb', czzb)
+
+    return {
+        bsc: bscb,
+        czz: czzb,
+        totalBalance: bscb.total + czzb.total
+    }
+}
+
+/**
+ * 获取时间段总支出的 gas fee
+ * @param {*} startTime 
+ * @param {*} endTime 
+ */
+async function getStatisticsInfo() {
+    // //今日
+    var startTime = utils.getLastDay('YYYY-MM-DD') + " 00:00:00"
+    var endTime = utils.getLastDay('YYYY-MM-DD') + " 23:59:59"
+    logger.info('getTotalOutGasFee', startTime, endTime)
+    //归集
+    var collectCoinsOut = await getCollectCoinsOutInfo(startTime, endTime)
+    logger.info('getCollectCoinsOutInfo  collectCoinsOut', collectCoinsOut)
+    //提币
+    var withdrawOut = await getWithdrawOutInfo(startTime, endTime)
+    logger.info('getWithdrawOutInfo withdrawOut ', withdrawOut)
+
+    var data = await http_request_get(utils.getLastDay('YYYYMMDD'))
+
+    //历史,总的
+    //归集
+    var totalCollectCoinsOut = await getCollectCoinsOutInfo(null, null)
+    logger.info('totalCollectCoinsOut  ', totalCollectCoinsOut)
+    //提币
+    var totalWithdrawOut = await getWithdrawOutInfo(null, null)
+    logger.info('totalWithdrawOut  ', totalWithdrawOut)
+
+    //获取当前账户总余额
+    var curBalances = await getAllBalance()
+    logger.info('getAllBalance  ', curBalances)
+
+    //获取散落 gas 
+    var totalSLGas = await getSLGas()
+    logger.info('getSLGas ret', totalSLGas)
+
+    return {
+        updateTime: utils.getLastDay('YYYY-MM-DD'),
+        todayTotalProfit: parseFloat(data.data.incomeUSDTotal) - parseFloat(collectCoinsOut.totalGasFee + withdrawOut.totalGasFee),
+        todayTotalOutGasFee: collectCoinsOut.totalGasFee + withdrawOut.totalGasFee,             //今日总支出的 gas fee
+        canNotWithdrawUSD: parseFloat(data.data.canNotWithdrawUSD),                                    //不可提现余额
+        canWithdrawUSD: parseFloat(data.data.canWithdrawUSD),                                          //可提现余额
+        todayIncomeUSDTotal: parseFloat(data.data.incomeUSDTotal),                                          //今日总收入
+        todayIncomeUSDFee: parseFloat(data.data.incomeUSDFee),                                              //今日固定收入
+        totalOutGasFee: totalCollectCoinsOut.totalGasFee + totalWithdrawOut.totalGasFee,        //总支出 gas fee
+        totalWithdrawGasFee: totalWithdrawOut.totalGasFee,                                      //总提币 gas fee
+        totalCollectCoinsGasFee: totalCollectCoinsOut.totalGasFee,                              //总归集 gas fee
+        totalInFee: totalCollectCoinsOut.totalInFee,                                            //总入金
+        totalNativeInFee: {
+            bsc: totalCollectCoinsOut.bsc.get('0x0000000000000000000000000000000000000000').totalUsdPrice,
+            czz: totalCollectCoinsOut.czz.get('0x0000000000000000000000000000000000000000').totalUsdPrice
+        },                                                                                      //总 native 入金
+        totalOutFee: totalWithdrawOut.totalWithdraw,                                            //总出金
+        totalBalances: curBalances.totalBalance,                                                             //总余额
+        ylGasBalance: {                                                                         //预留 gas 费余额  native 总余额 - 总入金
+            bsc: curBalances.bsc.nativeTotal - totalCollectCoinsOut.bsc.get('0x0000000000000000000000000000000000000000').totalUsdPrice,
+            czz: curBalances.czz.nativeTotal - totalCollectCoinsOut.czz.get('0x0000000000000000000000000000000000000000').totalUsdPrice,
+            total: (curBalances.bsc.nativeTotal - totalCollectCoinsOut.bsc.get('0x0000000000000000000000000000000000000000').totalUsdPrice) + (curBalances.czz.nativeTotal - totalCollectCoinsOut.czz.get('0x0000000000000000000000000000000000000000').totalUsdPrice)
+        },
+        slGasBalance: totalSLGas,                                                            //散落 gas 费余额  充值 0.5 gas - 使用 0.3 gas= 散落 0.2gas
+    }
+}
+
+
+
+function timeoutFunc(config, func) {
+
+    config.runNow && func()
+
+    let nowTime = new Date().getTime()
+
+    let timePoints = config.time.split(':').map(i => parseInt(i))
+
+    let recent = new Date().setHours(...timePoints)
+
+    recent >= nowTime || (recent += 24 * 3600000)
+
+    setTimeout(() => {
+
+        func()
+
+        setInterval(func, config.interval * 3600000)
+
+    }, recent - nowTime)
+}
+
+
+
+
+
+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 insertTableRows(app_token) {
+    var body = {
+        dimension: {
+            sheetId: 'BMjMDr',
+            majorDimension: 'ROWS',
+            startIndex: 2,
+            endIndex: 3,
+        },
+        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 exec(data) {
+    var app = await getFeishuToken()
+    await insertTableRows(app.app_access_token)
+    await writeTable(app.app_access_token, data)
+}
+
+async function report2FeishuTable() {
+    try {
+        logger.info('report2FeishuTable')
+        var data = await getStatisticsInfo();
+        logger.info('getStatisticsInfo', data)
+        await exec(data)
+    } catch (error) {
+        logger.error('report2FeishuTable', error.toString())
+    }
+
+}
+
+timeoutFunc({
+
+    interval: 1, //间隔天数,间隔为整数
+
+    runNow: false, //是否立即运行
+
+    time: reportTime //执行的时间点 时在0~23之间
+
+}, func => {
+    report2FeishuTable()
+})
+module.exports = {
+    getStatisticsInfo
+}
+
+
+

+ 18 - 4
model/utils.js

@@ -2,10 +2,10 @@
 var CryptoJS = require("crypto-js");
 require('dotenv').config()
 const logger = require('./logger')
-var moment = require('moment');
 const chinaTime = require('china-time');
 
 var { cryppt_config } = require('../config/config.js')
+const moment = require('moment-timezone');
 
 function toJson(code_, obj_, errMsg_) {
     var code = code_
@@ -31,7 +31,7 @@ function decryptPrivityKey(message) {
     // var iv = 'Zh4A7bOY2ksp9oIn'
 
     var encrypted = message; //python is base64 ECB
-    var key = process.env.DENET_CRYPT_KEY 
+    var key = process.env.DENET_CRYPT_KEY
     var iv = process.env.DENET_CRYPT_IV
     if (!key || !iv) {
         logger.error('decryptPrivityKey key or iv is empty?');
@@ -121,8 +121,11 @@ function getRedisKeyFromChain(chain) {
         case CHAIN_NAME.bsc_testnet:
         case 'bsc_testnet':
         case 'bsc_mainnet':
+        case '97':
+        case '56':
             return '_BSC'
         case CHAIN_NAME.czz:
+        case '2019':
             return '_CZZ'
         default:
             return null
@@ -158,6 +161,16 @@ 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 getLastDay(format) {
+    return moment().subtract(1, 'day').tz('Asia/Shanghai').format(format)
+}
+
 function getTimestampToDate(tm) {
     var now = new Date(tm),
         y = now.getFullYear(),
@@ -175,7 +188,7 @@ function scientificNotationToString(param) {
         let strParam = String(param)
         let flag = /e/.test(strParam)
         if (!flag) return param
-    
+
         // 指数符号 true: 正,false: 负
         let sysbol = true
         if (/e-/.test(strParam)) {
@@ -185,7 +198,7 @@ function scientificNotationToString(param) {
         let index = Number(strParam.match(/\d+$/)[0])
         // 基数
         let basis = strParam.match(/^[\d\.]+/)[0].replace(/\./, '')
-    
+
         if (sysbol) {
             return basis.padEnd(index + 1, 0)
         } else {
@@ -214,4 +227,5 @@ module.exports = {
     scientificNotationToString,
     getTimestampToDate,
     getRedisKeyFromChain,
+    getLastDay,
 }

+ 5 - 5
routes/sdk.js

@@ -686,7 +686,7 @@ async function getWithdrawStatus(ctx) {
                 chainId: info.chain_id,
                 transferTimestamp: info.update_time,
                 errorMsg: info.errorMsg
-            }, null)
+            }, info.errorMsg)
         }
     } else {
         ctx.body = utils.toJson(-1, null, obj.withdraw_id + ' id does not exist.')
@@ -840,10 +840,10 @@ check_czz_withdraw_task();
 bsc_log_monitoring()
 
 if (process.env.NODE_ENV == 'dev' || process.env.NODE_ENV == 'test') {
-    timer_transfer_bsc_task()
-    timer_transfer_czz_task()
-    timer_collect_conis_bsc_task()
-    timer_collect_conis_czz_task()
+    // timer_transfer_bsc_task()
+    // timer_transfer_czz_task()
+    // timer_collect_conis_bsc_task()
+    // timer_collect_conis_czz_task()
 }
 
 module.exports = router

+ 9 - 3
test/db_test.js

@@ -8,6 +8,8 @@ var remote_config_db = require("../model/db/remote_config_db");
 var collect_coins_db = require("../model/db/collect_coins_db");
 var withdraw_db = require("../model/db/withdraw_db");
 const BigNumber = require('bignumber.js')
+var utils = require('../model/utils')
+var statistics = require('../model/server_data_statistics')
 router.prefix('/test');
 router.post('/set', async (ctx) => {
     // const obj = ctx.request.body;
@@ -142,20 +144,24 @@ async function getInfo2() {
     //     console.log('total', total_gas_fee2 + total_gas_fee)
 }
 
-function getInfo3() {
+async function getInfo3() {
     // console.log('1018087452840284941787', 1018087452840284941787 / (10**18))
 
     // console.log('101000000000000000000', 101000000000000000000 / (10**18) * 0.6476)
 
     // console.log('64585000000000000000000', 64585000000000000000000 / (10**18) * 0.0005)
 
-    
+
     // console.log('1000000000000000', 1000000000000000 / (10**18) * 0.0482)
     // console.log('2410418338592426908426', 2410418338592426908426 / (10**18) * 0.2074)
     // console.log('2501561242336020120158', 2501561242336020120158 / (10**18) * 0.2074)
 
+    console.log("YYYY-MM-dd", utils.getCurrentDateFormat('YYYY-MM-DD'))
+   
+    console.error("getStatisticsInfo", await statistics.getStatisticsInfo())
+
 }
-getInfo3()
+// getInfo3()
 // getInfo2()
 // query()
 module.exports = router

+ 109 - 5
test/sample.js

@@ -1,8 +1,9 @@
 var CryptoJS = require("crypto-js");
+const axios = require('axios');
 
 function decryptPrivityKey(message) {
-    var encrypted = message; 
-    var key = process.env.DENET_CRYPT_KEY 
+    var encrypted = message;
+    var key = process.env.DENET_CRYPT_KEY
     var iv = process.env.DENET_CRYPT_IV
     if (!key || !iv) {
         console.error('decryptPrivityKey key or iv is empty?');
@@ -13,14 +14,117 @@ function decryptPrivityKey(message) {
     iv = CryptoJS.enc.Utf8.parse(iv)
     var decrypted = CryptoJS.AES.decrypt(encrypted
         , key
-        , { iv: iv, mode: CryptoJS.mode.CBC}
-        );
+        , { iv: iv, mode: CryptoJS.mode.CBC }
+    );
     console.log('decrypted decrypt ==', decrypted);
     var de_pk = decrypted.toString(CryptoJS.enc.Utf8);
     console.log('decrypted==', de_pk);
     return de_pk
 }
 
-decryptPrivityKey('bnUvrSKmU3l7zONP+hIH1BOMhNVfIBUgEziWb2tGiUgn63FZVdzXC9E1DT+Mx3B+nqrzUAqd60I/8rLobYYl+0TSR3Ri1o0iX/hcxqs/0yg=')
+// decryptPrivityKey('bnUvrSKmU3l7zONP+hIH1BOMhNVfIBUgEziWb2tGiUgn63FZVdzXC9E1DT+Mx3B+nqrzUAqd60I/8rLobYYl+0TSR3Ri1o0iX/hcxqs/0yg=')
+
+
+const getFeishuToken = async (params) => {
+    return new Promise(resolve => {
+        axios.post('https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal',
+            {
+                app_id: "cli_a223f015abbad00e",
+                app_secret: "DMCF6tBwIpeOQPnWrFUMYd6tmjb53C4n"
+            },
+            {
+                timeout: 1 * 60 * 1000,
+                headers: {
+                    'Content-Type': "application/json; charset=utf-8"
+                }
+            })
+            .then(res => {
+                console.log('res=>', res.status, res.data);
+                resolve(res.data)
+            }).catch(err => {
+                logger.error('http_request_post withdraw_czz error ', JSON.stringify(err));
+                resolve(JSON.stringify(err))
+            });
+    })
+}
+
+
+function writeTable(app_token) {
+    var body = {
+        'valueRanges': [
+            {
+                'range': '072d4e!A1:B1',
+                'values': [
+                    ['2022/06/15 11:43:23', 1],
+                ]
+            }
+        ]
+    }
+    return new Promise(resolve => {
+        axios.post('https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/shtcnsS7N9KS6pVUvR9qvj8mYpb/values_batch_update',
+            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 => {
+                console.error('error ', JSON.stringify(err));
+                resolve(JSON.stringify(err))
+            });
+    })
+}
+
+async function insertTableRows(app_token) {
+    var body = {
+        dimension: {
+            sheetId: '072d4e',
+            majorDimension: 'ROWS',
+            startIndex: 0,
+            endIndex: 1,
+        },
+        inheritStyle: 'AFTER'
+    }
+    return new Promise(resolve => {
+        axios.post('https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/shtcnsS7N9KS6pVUvR9qvj8mYpb/insert_dimension_range',
+            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 => {
+                console.error('error ', JSON.stringify(err));
+                resolve(JSON.stringify(err))
+            });
+    })
+}
+
+async function exec() {
+    var app = await getFeishuToken()
+    await insertTableRows(app.app_access_token)
+    await writeTable(app.app_access_token)
+}
+
+
+exec()
+
+
+
+
+
+
+
+