|
@@ -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
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|