server_data_statistics.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. const logger = require('../model/logger')
  2. var remote_config_db = require("../model/db/remote_config_db");
  3. var collect_coins_db = require("../model/db/collect_coins_db");
  4. var withdraw_db = require("../model/db/withdraw_db");
  5. var moralis = require("../model/moralis_sdk");
  6. var utils = require("../model/utils");
  7. const axios = require('axios');
  8. var { account_config } = require('../config/config.js');
  9. const { max } = require('moment');
  10. //########################################### 出入金数据统计 ########################################
  11. const http_request_get = async (data) => {
  12. var host = account_config.STATISTICS_URL
  13. var path = data
  14. var url = host + path
  15. logger.log('http_request_get', url)
  16. return new Promise(response => {
  17. axios.get(url)
  18. .then(res => {
  19. logger.log('res=>', res.status, res.data);
  20. if (res.data.code == 0) {
  21. response(res.data)
  22. } else {
  23. response({
  24. code: 0,
  25. msg: err.toString(),
  26. data: {
  27. canNotWithdrawUSD: '0',
  28. canWithdrawUSD: '0',
  29. incomeUSDTotal: '0',
  30. incomeUSDFee: '0'
  31. }
  32. })
  33. }
  34. }).catch(err => {
  35. logger.error('http_request_get', err.toString(), url.toString());
  36. response({
  37. code: -1,
  38. msg: err.toString(),
  39. data: {
  40. canNotWithdrawUSD: '0',
  41. canWithdrawUSD: '0',
  42. incomeUSDTotal: '0',
  43. incomeUSDFee: '0'
  44. }
  45. })
  46. });
  47. })
  48. }
  49. async function computeAddressPrice(total_in_coins) {
  50. //计算总的价格
  51. for (key of total_in_coins.keys()) {
  52. var item = total_in_coins.get(key)
  53. var amount = item.amount
  54. var usdPrice = item.usdPrice
  55. if (key == '0x0000000000000000000000000000000000000000') {
  56. item.totalUsdPrice = parseFloat(amount) / parseFloat(10 ** 18) * parseFloat(usdPrice)
  57. } else {
  58. var decimals = 18
  59. try {
  60. decimals = await redis.readAppendRedis('REDIS_ERC20_CONTRACT_DECIMALS', item.chain, key.toLowerCase())
  61. logger.info('REDIS_ERC20_CONTRACT_DECIMALS', key.toLowerCase(), decimals)
  62. } catch (error) {
  63. decimals = 18
  64. }
  65. item.totalUsdPrice = parseFloat(amount) / parseFloat(10 ** decimals) * parseFloat(usdPrice)
  66. }
  67. }
  68. }
  69. async function filterCollectCoinsLists(collect_ret, filterTypt) {
  70. const total_in_coins = new Map();
  71. var total_gas_fee = 0
  72. for (let index = 0; index < collect_ret.results.length; index++) {
  73. const element = collect_ret.results[index];
  74. if (element.chain == null || element.chain == filterTypt) {
  75. var before_gas_fee = element.before_gas_fee ? BigInt(element.before_gas_fee) : BigInt('0')
  76. total_gas_fee = BigInt(element.total_gas_fee) + BigInt(before_gas_fee) + BigInt(total_gas_fee)
  77. if (element.transfers) {
  78. var opts = JSON.parse(element.transfers)
  79. for (let index = 0; index < opts.length; index++) {
  80. const transfers = opts[index];
  81. if (transfers.chain == filterTypt) {
  82. var address = transfers.contractAddress ? transfers.contractAddress : '0x0000000000000000000000000000000000000000'
  83. if (total_in_coins.get(address) != null) {
  84. var ins = total_in_coins.get(address)
  85. ins.amount = BigInt(ins.amount) + BigInt(transfers.amount)
  86. total_in_coins.set(address, ins)
  87. } else {
  88. total_in_coins.set(address, {
  89. amount: BigInt(transfers.amount), //总入金
  90. usdPrice: transfers.usdPrice,
  91. chain: transfers.chain,
  92. })
  93. }
  94. }
  95. }
  96. }
  97. }
  98. }
  99. //计算总的价格
  100. await computeAddressPrice(total_in_coins)
  101. var bsc_env
  102. switch (process.env.NODE_ENV) {
  103. case 'dev':
  104. case 'test':
  105. bsc_env = 'bsc_testnet'
  106. break
  107. case 'prd':
  108. bsc_env = 'bsc_mainnet'
  109. break
  110. default:
  111. bsc_env = 'bsc_mainnet'
  112. break
  113. }
  114. //获取 total gas
  115. try {
  116. if (total_in_coins.size > 0) {
  117. switch (filterTypt) {
  118. case 'bsc_testnet':
  119. case 'bsc_mainnet':
  120. var price = await moralis.getAllTotkenPrice({ chain: bsc_env })
  121. if (typeof price === 'string') {
  122. price = JSON.parse(price)
  123. }
  124. var bnbPriceItem = moralis.findTokenPriceItem('0x0000000000000000000000000000000000000000', price)
  125. total_gas_fee = parseFloat(total_gas_fee) / parseFloat(10 ** 18) * parseFloat(bnbPriceItem.usdPrice)
  126. logger.info('new-total_gas_fee ', total_gas_fee, bnbPriceItem)
  127. break
  128. case 'czz':
  129. var price = await moralis.getAllTotkenPrice({ chain: 'czz' })
  130. if (typeof price === 'string') {
  131. price = JSON.parse(price)
  132. }
  133. var czzPriceItem = moralis.findTokenPriceItem('0x0000000000000000000000000000000000000000', price)
  134. total_gas_fee = parseFloat(total_gas_fee) / parseFloat(10 ** 18) * parseFloat(czzPriceItem.usdPrice)
  135. logger.info('new-total_gas_fee czz', total_gas_fee, czzPriceItem)
  136. break
  137. }
  138. }
  139. } catch (error) {
  140. logger.error('total_gas_fee', error)
  141. }
  142. return {
  143. map: total_in_coins,
  144. totalGasFee: total_gas_fee //总入金所消耗的 gas fee
  145. }
  146. }
  147. function sumBalance(map) {
  148. var balances = 0;
  149. for (key of map.keys()) {
  150. balances += map.get(key).totalUsdPrice
  151. }
  152. return balances
  153. }
  154. async function getSLGas() {
  155. var maps = new Map()
  156. var collect_ret = await collect_coins_db.query_collect_total_fee(null, null);
  157. for (let index = 0; index < collect_ret.results.length; index++) {
  158. var element = collect_ret.results[index]
  159. try {
  160. if (element.prestore_gas_fee && typeof element.prestore_gas_fee === 'string') {
  161. var pre_gas_obj = JSON.parse(element.prestore_gas_fee)
  162. var bgf = element.before_gas_fee
  163. if (!bgf && pre_gas_obj.amount) {
  164. bgf = pre_gas_obj.amount
  165. }
  166. logger.info('getSLGas item', bgf, pre_gas_obj, element)
  167. if (maps.get(pre_gas_obj.chain)) {
  168. 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))
  169. } else {
  170. maps.set(pre_gas_obj.chain, {
  171. sl_gas_fee: BigInt(pre_gas_obj.amount) - BigInt(bgf)
  172. })
  173. }
  174. }
  175. } catch (error) {
  176. logger.error('getSLGas error', error.toString())
  177. }
  178. }
  179. var bsc_env
  180. switch (process.env.NODE_ENV) {
  181. case 'dev':
  182. case 'test':
  183. bsc_env = 'bsc_testnet'
  184. break
  185. case 'prd':
  186. bsc_env = 'bsc_mainnet'
  187. break
  188. default:
  189. bsc_env = 'bsc_mainnet'
  190. break
  191. }
  192. logger.info('getSLGas', maps)
  193. var bsc_sl
  194. var czz_sl
  195. for (key of maps.keys()) {
  196. var item = maps.get(key)
  197. switch (key) {
  198. case "bsc_mainnet":
  199. case "bsc_testnet":
  200. var price = await moralis.getAllTotkenPrice({ chain: bsc_env })
  201. if (typeof price === 'string') {
  202. price = JSON.parse(price)
  203. }
  204. var bnbPriceItem = moralis.findTokenPriceItem('0x0000000000000000000000000000000000000000', price)
  205. bsc_sl = parseFloat(item.sl_gas_fee) / parseFloat(10 ** 18) * parseFloat(bnbPriceItem.usdPrice)
  206. break
  207. case "czz":
  208. var price = await moralis.getAllTotkenPrice({ chain: 'czz' })
  209. if (typeof price === 'string') {
  210. price = JSON.parse(price)
  211. }
  212. var czzPriceItem = moralis.findTokenPriceItem('0x0000000000000000000000000000000000000000', price)
  213. czz_sl = parseFloat(item.sl_gas_fee) / parseFloat(10 ** 18) * parseFloat(czzPriceItem.usdPrice)
  214. break
  215. }
  216. }
  217. return {
  218. bsc: bsc_sl,
  219. czz: czz_sl
  220. }
  221. }
  222. async function getCollectCoinsOutInfo(startTime, endTime) {
  223. var collect_ret = await collect_coins_db.query_collect_total_fee(startTime, endTime);
  224. logger.info('getCollectCoinsOutInfo query_collect_total_fee', startTime, endTime)
  225. var bsc_env
  226. switch (process.env.NODE_ENV) {
  227. case 'dev':
  228. case 'test':
  229. bsc_env = 'bsc_testnet'
  230. break
  231. case 'prd':
  232. bsc_env = 'bsc_mainnet'
  233. break
  234. default:
  235. bsc_env = 'bsc_mainnet'
  236. break
  237. }
  238. var bsc_envnet = await filterCollectCoinsLists(collect_ret, bsc_env)
  239. logger.info('getCollectCoinsOutInfo bsc_env', bsc_env, bsc_envnet)
  240. var czz = await filterCollectCoinsLists(collect_ret, 'czz')
  241. logger.info('getCollectCoinsOutInfo czz', czz)
  242. logger.info('getCollectCoinsOutInfo total ', bsc_envnet.totalGasFee, czz.totalGasFee)
  243. return {
  244. bsc: bsc_envnet.map,
  245. czz: czz.map,
  246. totalGasFee: parseFloat(bsc_envnet.totalGasFee) + parseFloat(czz.totalGasFee), //总归集消耗的 gas fee
  247. totalInFee: sumBalance(bsc_envnet.map) + sumBalance(czz.map),//总入金美元
  248. }
  249. }
  250. async function filterWithdrawTotalOutFee(chain_id, filterItem) {
  251. const withdraw_out_map = new Map();
  252. var price = await moralis.getAllTotkenPrice({ chain: chain_id + "" })
  253. if (typeof price === 'string') {
  254. price = JSON.parse(price)
  255. }
  256. for (let index = 0; index < filterItem.length; index++) {
  257. const element = filterItem[index];
  258. if (element.chain_id == chain_id) {
  259. var address = element.type == 'native' ? '0x0000000000000000000000000000000000000000' : element.contract_address
  260. if (withdraw_out_map.get(address) != null) {
  261. var item = withdraw_out_map.get(address)
  262. item.totalAmount = BigInt(element.amount) + BigInt(item.totalAmount)
  263. } else {
  264. var priceItem = moralis.findTokenPriceItem(address, price)
  265. var decimals = 18
  266. if (key == '0x0000000000000000000000000000000000000000') {
  267. item.totalUsdPrice = parseFloat(amount) / parseFloat(10 ** 18) * parseFloat(usdPrice)
  268. } else {
  269. try {
  270. decimals = await redis.readAppendRedis('REDIS_ERC20_CONTRACT_DECIMALS', chain_id + "", address.toLowerCase())
  271. logger.info('REDIS_ERC20_CONTRACT_DECIMALS', key.toLowerCase(), decimals)
  272. } catch (error) {
  273. decimals = 18
  274. }
  275. }
  276. withdraw_out_map.set(address, {
  277. totalAmount: BigInt(element.amount), //出金数量
  278. usdPrice: priceItem.usdPrice,
  279. chain: element.chain_id,
  280. decimals: decimals,
  281. })
  282. }
  283. }
  284. }
  285. logger.info('filterWithdrawTotalOutFee', withdraw_out_map, chain_id)
  286. return withdraw_out_map
  287. }
  288. async function getWithdrawOutInfo(startTime, endTime) {
  289. if (startTime && endTime) {
  290. startTime = new Date(startTime).getTime()
  291. endTime = new Date(endTime).getTime()
  292. }
  293. var withdraw_ret = await withdraw_db.getWidthdrawTotalFee(startTime, endTime)
  294. const withdraw_gas_map = new Map();
  295. for (let index = 0; index < withdraw_ret.length; index++) {
  296. const element = withdraw_ret[index];
  297. if (element.gas_price && element.gas_limit)
  298. var total_gas_fee2 = (BigInt(element.gas_price) * BigInt(element.gas_limit))
  299. if (withdraw_gas_map.get(element.chain_id) != null) {
  300. 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)
  301. } else {
  302. withdraw_gas_map.set(element.chain_id,
  303. {
  304. total_gas_fee: BigInt(total_gas_fee2),
  305. total_withdraw: null
  306. }
  307. )
  308. }
  309. }
  310. var bsc_env
  311. switch (process.env.NODE_ENV) {
  312. case 'dev':
  313. case 'test':
  314. bsc_env = 'bsc_testnet'
  315. break
  316. case 'prd':
  317. bsc_env = 'bsc_mainnet'
  318. break
  319. default:
  320. bsc_env = 'bsc_mainnet'
  321. break
  322. }
  323. //计算总消耗的 gas
  324. var keys = withdraw_gas_map.keys();
  325. var total_gas_fee = 0
  326. for (key of keys) {
  327. console.log(key, withdraw_gas_map.get(key)); // map.get(key)可得value值。
  328. var value = withdraw_gas_map.get(key).total_gas_fee
  329. //获取币价
  330. try {
  331. if (key == 2019) {
  332. var price = await moralis.getAllTotkenPrice({ chain: 'czz' })
  333. if (typeof price === 'string') {
  334. price = JSON.parse(price)
  335. }
  336. var czzPriceItem = moralis.findTokenPriceItem('0x0000000000000000000000000000000000000000', price)
  337. total_gas_fee += parseFloat(value) / parseFloat(10 ** 18) * parseFloat(czzPriceItem.usdPrice)
  338. logger.info('new-total_gas_fee czz', total_gas_fee, czzPriceItem)
  339. } else {
  340. var price = await moralis.getAllTotkenPrice({ chain: bsc_env })
  341. if (typeof price === 'string') {
  342. price = JSON.parse(price)
  343. }
  344. var bnbPriceItem = moralis.findTokenPriceItem('0x0000000000000000000000000000000000000000', price)
  345. total_gas_fee += parseFloat(value) / parseFloat(10 ** 18) * parseFloat(bnbPriceItem.usdPrice)
  346. logger.info('new-total_gas_fee bsc', total_gas_fee, bnbPriceItem)
  347. }
  348. } catch (error) {
  349. logger.error('total_gas_fee', error)
  350. }
  351. }
  352. var withdrawout = 0
  353. if (!startTime && !endTime) {
  354. for (key of withdraw_gas_map.keys()) {
  355. try {
  356. var outs = await filterWithdrawTotalOutFee(key, withdraw_ret)
  357. withdraw_gas_map.get(key).total_withdraw = outs
  358. logger.error('withdraw_gas_map.get(key).total_withdraw outs', outs)
  359. if (outs) {
  360. for (ckey of outs.keys()) {
  361. var item = outs.get(ckey);
  362. withdrawout = parseFloat(withdrawout) + (parseFloat(item.totalAmount) / parseFloat(10 ** item.decimals) * parseFloat(item.usdPrice))
  363. }
  364. }
  365. } catch (error) {
  366. logger.error('filterWithdrawTotalOutFee error', error.toString())
  367. }
  368. }
  369. }
  370. return {
  371. outmap: withdraw_gas_map,
  372. totalGasFee: total_gas_fee,
  373. totalWithdraw: withdrawout
  374. };
  375. }
  376. async function updateBalance(obj, type) {
  377. var price
  378. if (type == 'bsc') {
  379. var bsc_env
  380. switch (process.env.NODE_ENV) {
  381. case 'dev':
  382. case 'test':
  383. bsc_env = 'bsc_testnet'
  384. break
  385. case 'prd':
  386. bsc_env = 'bsc_mainnet'
  387. break
  388. default:
  389. bsc_env = 'bsc_mainnet'
  390. break
  391. }
  392. price = await moralis.getAllTotkenPrice({ chain: bsc_env })
  393. } else if (type == 'czz') {
  394. price = await moralis.getAllTotkenPrice({ chain: 'czz' })
  395. }
  396. if (typeof price === 'string') {
  397. price = JSON.parse(price)
  398. }
  399. var priceItem = moralis.findTokenPriceItem('0x0000000000000000000000000000000000000000', price, price)
  400. if (obj.native) {
  401. obj.native.usdPrice = parseFloat(obj.native.balance) / parseFloat(10 ** 18) * priceItem.usdPrice
  402. logger.info('findTokenPriceItem 0x0000000000000000000000000000000000000000 ', obj, priceItem, type)
  403. }
  404. var tokenTotal = 0
  405. if (obj.other && Array.isArray(obj.other)) {
  406. for (let index = 0; index < obj.other.length; index++) {
  407. const element = obj.other[index];
  408. priceItem = moralis.findTokenPriceItem(element.token_address, price)
  409. logger.info('findTokenPriceItem element ', priceItem, element.token_address)
  410. if (priceItem) {
  411. element.usdPrice = parseFloat(element.balance) / parseFloat(10 ** element.decimals) * priceItem.usdPrice
  412. tokenTotal += element.usdPrice
  413. }
  414. }
  415. }
  416. return {
  417. nativeTotal: obj.native.usdPrice,
  418. tokenTotal: tokenTotal,
  419. }
  420. }
  421. async function getAllBalance() {
  422. var bsc_env
  423. switch (process.env.NODE_ENV) {
  424. case 'dev':
  425. case 'test':
  426. bsc_env = 'bsc_testnet'
  427. break
  428. case 'prd':
  429. bsc_env = 'bsc_mainnet'
  430. break
  431. default:
  432. bsc_env = 'bsc_mainnet'
  433. break
  434. }
  435. var company = await moralis.queryCompanyInfoFromId(0)
  436. var bsc_balance = await moralis.getAccountAllCoins({
  437. chain: bsc_env,
  438. address: company.user_address
  439. })
  440. var bscb = await updateBalance(bsc_balance, 'bsc')
  441. var czz_balance = await moralis.getAccountAllCoins({
  442. chain: 'czz',
  443. address: company.user_address
  444. })
  445. var czzb = await updateBalance(czz_balance, 'czz')
  446. return {
  447. bsc: bscb,
  448. czz: czzb
  449. }
  450. }
  451. /**
  452. * 获取时间段总支出的 gas fee
  453. * @param {*} startTime
  454. * @param {*} endTime
  455. */
  456. async function getStatisticsInfo() {
  457. // //今日
  458. var startTime = utils.getLastDay('YYYY-MM-DD') + " 00:00:00"
  459. var endTime = utils.getLastDay('YYYY-MM-DD') + " 23:59:59"
  460. logger.info('getTotalOutGasFee', startTime, endTime)
  461. //归集
  462. var collectCoinsOut = await getCollectCoinsOutInfo(startTime, endTime)
  463. logger.info('getCollectCoinsOutInfo collectCoinsOut', collectCoinsOut)
  464. //提币
  465. var withdrawOut = await getWithdrawOutInfo(startTime, endTime)
  466. logger.info('getWithdrawOutInfo withdrawOut ', withdrawOut)
  467. var data = await http_request_get(utils.getLastDay('YYYYMMDD'))
  468. //历史,总的
  469. //归集
  470. var totalCollectCoinsOut = await getCollectCoinsOutInfo(null, null)
  471. logger.info('totalCollectCoinsOut ', totalCollectCoinsOut)
  472. //提币
  473. var totalWithdrawOut = await getWithdrawOutInfo(null, null)
  474. logger.info('totalWithdrawOut ', totalWithdrawOut)
  475. //获取当前账户总余额
  476. var curBalances = await getAllBalance()
  477. logger.info('getAllBalance ', curBalances)
  478. //获取散落 gas
  479. var totalSLGas = await getSLGas()
  480. return {
  481. todayTotalOutGasFee: collectCoinsOut.totalGasFee + withdrawOut.totalGasFee, //今日总支出的 gas fee
  482. todayCanNotWithdrawUSD: data.data.canNotWithdrawUSD, //今日不可提现余额
  483. todayCanWithdrawUSD: data.data.canWithdrawUSD, //今日可提现余额
  484. todayIncomeUSDTotal: data.data.incomeUSDTotal, //今日总收入
  485. todayIncomeUSDFee: data.data.incomeUSDFee, //今日固定收入
  486. totalOutGasFee: totalCollectCoinsOut.totalGasFee + totalWithdrawOut.totalGasFee, //总支出 gas fee
  487. totalWithdrawGasFee: totalWithdrawOut.totalGasFee, //总提币 gas fee
  488. totalCollectCoinsGasFee: totalCollectCoinsOut.totalGasFee, //总归集 gas fee
  489. totalInFee: totalCollectCoinsOut.totalInFee,
  490. totalNativeInFee: {
  491. bsc: totalCollectCoinsOut.bsc.get('0x0000000000000000000000000000000000000000').totalUsdPrice,
  492. czz: totalCollectCoinsOut.czz.get('0x0000000000000000000000000000000000000000').totalUsdPrice
  493. }, //总 native 入金
  494. totalOutFee: totalWithdrawOut.totalWithdraw, //总出金
  495. totalBalances: curBalances, //总余额
  496. ylGasBalance: { //预留 gas 费余额 native 总余额 - 总入金
  497. bsc: curBalances.bsc.nativeTotal - totalCollectCoinsOut.bsc.get('0x0000000000000000000000000000000000000000').totalUsdPrice,
  498. czz: curBalances.czz.nativeTotal - totalCollectCoinsOut.czz.get('0x0000000000000000000000000000000000000000').totalUsdPrice
  499. },
  500. slGasBalance: totalSLGas, //散落 gas 费余额 充值 0.5 gas - 使用 0.3 gas= 散落 0.2gas
  501. }
  502. }
  503. function timeoutFunc(config, func) {
  504. config.runNow && func()
  505. let nowTime = new Date().getTime()
  506. let timePoints = config.time.split(':').map(i => parseInt(i))
  507. let recent = new Date().setHours(...timePoints)
  508. recent >= nowTime || (recent += 24 * 3600000)
  509. setTimeout(() => {
  510. func()
  511. setInterval(func, config.interval * 3600000)
  512. }, recent - nowTime)
  513. }
  514. timeoutFunc({
  515. interval: 1, //间隔天数,间隔为整数
  516. runNow: false, //是否立即运行
  517. time: "08:00:00" //执行的时间点 时在0~23之间
  518. }, func => {
  519. getStatisticsInfo()
  520. })
  521. module.exports = {
  522. getStatisticsInfo
  523. }