sdk.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. var router = require('koa-router')();
  2. var moralis = require('../model/moralis_sdk.js')
  3. var utils = require('../model/utils.js');
  4. var { reids_token_config, account_config } = require('../config/config.js');
  5. const logger = require('../model/logger.js');
  6. router.prefix('/sdk');
  7. const redis = require("../model/db/redis_db") //导入 db.js
  8. const withdraw_db = require("../model/db/withdraw_db") //导入 db.js
  9. const report = require("../model/report") //导入 db.js
  10. const BigNumber = require('bignumber.js')
  11. /**
  12. * 获取代币价格
  13. * @param {*} ctx
  14. */
  15. async function getAllTotkenPrice(ctx) {
  16. console.log('getTotkenPrice in:')
  17. var ret = await moralis.getAllTotkenPrice()
  18. console.log('getTotkenPrice result:', ret)
  19. if (ret)
  20. ctx.body = utils.toJson(0, ret, null);
  21. else ctx.body = utils.toJson(-1, null, "redis read error.");
  22. }
  23. /**
  24. * 获取交易记录
  25. * @param {*} ctx
  26. */
  27. async function getTransfers(ctx) {
  28. const obj = ctx.request.body;
  29. console.log("getTransfers body", obj);
  30. if (!obj.chain)//默认 bsc 币安链
  31. obj.chain = 'bsc_mainnet'
  32. var temp_obj = { ...obj }
  33. var index = 0
  34. await moralis.getTokenTransfers(obj).then((result) => {
  35. logger.log('getTransfers response', 'index=' + index, result)
  36. ctx.body = result;
  37. if (result) {
  38. //提交归集任务 native 能获取到 gas 、token 无法获取到 gas 费
  39. try {
  40. if (temp_obj.address && moralis.isTransferSucceed(result)) {
  41. var log_obj = { ...obj }
  42. log_obj.results = result
  43. log_obj.type = report.REPORT_TYPE.transfer_record
  44. //埋点日志上报-入金检查
  45. report.logReport(log_obj)
  46. var json_obj = JSON.parse(result);
  47. //缓存当前交易的 gas 费用
  48. var tr = moralis.getTransferRecordGasFree('native', json_obj, temp_obj.address)
  49. logger.log('getTransferRecordGasFree:', tr, temp_obj.address)
  50. if (tr && tr.totalGasFree > 0) {
  51. logger.log('getTransferRecordGasFree redis_set LAST_PRICE:', tr)
  52. redis.redis_set(reids_token_config.LAST_BNB_PRICE, tr.gas_price.toString());
  53. redis.redis_set(reids_token_config.LAST_TOKEN_PRICE, tr.gas_price.toString());
  54. }
  55. if (json_obj.data.total > 0) {
  56. //提交归集任务
  57. if (temp_obj.address) {
  58. logger.log('pushCollectConisObj>>>', temp_obj.address)
  59. redis.redis_push(reids_token_config.COLLECT_CONIS_QUEUE_KEY, JSON.stringify(temp_obj))
  60. }
  61. }
  62. if (json_obj.data.total > 0) {
  63. //提交归集任务
  64. if (temp_obj.address) {
  65. logger.log('pushCollectConisObj>>>', temp_obj.address)
  66. redis.redis_push(reids_token_config.COLLECT_CONIS_QUEUE_KEY, JSON.stringify(temp_obj))
  67. }
  68. }
  69. }
  70. } catch (error) {
  71. console.error('pushCollectConisObj error=', error)
  72. }
  73. }
  74. })
  75. }
  76. /**
  77. * 获取交易记录
  78. * @param {*} ctx
  79. */
  80. async function getTransfersV2(ctx) {
  81. const obj = ctx.request.body;
  82. console.log("getTransfers body", obj);
  83. if (!obj.chain)//默认 bsc 币安链
  84. obj.chain = 'bsc_mainnet'
  85. var temp_obj = { ...obj }
  86. var index = 0
  87. await moralis.getTokenTransfersV2(obj).then((result) => {
  88. logger.log('getTokenTransfersV2 response', 'index=' + index, result)
  89. ctx.body = result;
  90. if (result) {
  91. //提交归集任务 native 能获取到 gas 、token 无法获取到 gas 费
  92. try {
  93. if (temp_obj.address && moralis.isTransferSucceed(result)) {
  94. var log_obj = { ...obj }
  95. log_obj.results = result
  96. log_obj.type = report.REPORT_TYPE.transfer_record
  97. //埋点日志上报-入金检查
  98. report.logReport(log_obj)
  99. var json_obj = JSON.parse(result);
  100. //缓存当前交易的 gas 费用
  101. var tr = moralis.getTransferRecordGasFree('native', json_obj, temp_obj.address)
  102. logger.log('getTransferRecordGasFree:', tr, temp_obj.address)
  103. if (tr && tr.totalGasFree > 0) {
  104. logger.log('getTransferRecordGasFree redis_set LAST_TOTAL_BNB_FREE:', tr.totalGasFree.toString())
  105. logger.log('getTransferRecordGasFree redis_set LAST_TOTAL_TOKEN_FREE:', (parseInt(tr.totalGasFree) * parseInt(account_config.TOKEN_GAS_LIMIT)).toString())
  106. redis.redis_set(reids_token_config.LAST_TOTAL_BNB_FREE, tr.totalGasFree.toString());
  107. redis.redis_set(reids_token_config.LAST_TOTAL_TOKEN_FREE, (parseInt(tr.gas_price) * parseInt(account_config.TOKEN_GAS_LIMIT)).toString());
  108. }
  109. if (json_obj.data.total > 0) {
  110. //提交归集任务
  111. if (temp_obj.address) {
  112. logger.log('pushCollectConisObj>>>', temp_obj.address)
  113. redis.redis_push(reids_token_config.COLLECT_CONIS_QUEUE_KEY, JSON.stringify(temp_obj))
  114. }
  115. }
  116. }
  117. } catch (error) {
  118. console.error('pushCollectConisObj error=', error)
  119. }
  120. }
  121. })
  122. }
  123. async function getAllTokenWithdrawInfoLists(ctx) {
  124. if (ctx.request == null || ctx.request.body == null) {
  125. ctx.body = utils.toJson(-1, null, "request error. ");
  126. return
  127. }
  128. ctx.body = await moralis.getAllTokenWithdrawInfoLists(ctx);
  129. }
  130. async function collect_conis_task() {
  131. logger.log("collect_conis_task start")
  132. while (true) {
  133. var start_time = utils.getTimestamp()
  134. var exec_obj = await redis.redis_pop(reids_token_config.COLLECT_CONIS_QUEUE_KEY)
  135. if (!exec_obj) {
  136. await utils.sleep(30000)
  137. logger.log("没有归集任务")
  138. continue
  139. }
  140. try {
  141. exec_obj = JSON.parse(exec_obj)
  142. logger.log('collect_conis_task exec item>>>>', exec_obj);
  143. //开始收集用户地址里面的币到归集地址
  144. var ret = await moralis.collectCoins(exec_obj)
  145. logger.log('collect_conis_task ret =', exec_obj, ret)
  146. try {
  147. var ret_obj = JSON.parse(ret)
  148. if (ret_obj.code == 0) {
  149. logger.log('触发归集 delay collect_conis_task ret =', exec_obj, ret)
  150. //间隔 10s 归集,避免提交任务过多
  151. await utils.sleep(10000)
  152. }
  153. } catch (error) { }
  154. } catch (error) {
  155. logger.error('collect_conis_task error', error.toString());
  156. }
  157. logger.log("collect_conis_task cost-time", utils.getTimestamp() - start_time, exec_obj)
  158. }
  159. }
  160. async function withdraw_task() {
  161. logger.log("withdraw_task start")
  162. let last_time = 0
  163. let last_hash = ''
  164. while (true) {
  165. var exec_obj = await redis.redis_pop(reids_token_config.WITHDRAW_QUEUE_KEY)
  166. if (!exec_obj) {
  167. await utils.sleep(60000)
  168. logger.log("没有出金任务")
  169. continue
  170. }
  171. try {
  172. exec_obj = JSON.parse(exec_obj)
  173. } catch (error) {
  174. logger.error('item parse error', error);
  175. break
  176. }
  177. var temp_obj = { ...exec_obj }
  178. if (utils.getTimestamp() - last_time < 60000) {
  179. //有可能上一个区块还未更新,这里做一个尝试限制
  180. //Error: Failed to make "eth_sendRawTransaction" request with networkConnector: "already known"
  181. //通过 交易 hash 获取块。last_hash
  182. if (last_hash) {
  183. var options = {
  184. transaction_hash: last_hash,
  185. chain: temp_obj.chain,
  186. endTime: '2099-01-01'
  187. }
  188. var tryCount = 10;
  189. do {
  190. try {
  191. //通过获取上一个交易记录来进行确认
  192. var transaction = await moralis.getTokenTransfers(options);
  193. logger.log('withdraw_task exectransaction', transaction, options, tryCount);
  194. transaction = JSON.parse(transaction)
  195. if (transaction.code == 0) {
  196. if (transaction.data.result.length <= 0) {
  197. logger.log('等待10s');
  198. await utils.sleep(10000)
  199. } else {
  200. logger.log('等待5s');
  201. await utils.sleep(5000)
  202. break
  203. }
  204. } else {
  205. break
  206. }
  207. tryCount -= 1
  208. } catch (error) {
  209. logger.error('withdraw_task exectransaction', error.toString());
  210. }
  211. } while (tryCount >= 0);
  212. }
  213. }
  214. //如果失败重试一次
  215. var tryCount = 1;
  216. for (let index = 0; index < 1 + tryCount; index++) {
  217. try {
  218. var result = await withdraw_({ ...temp_obj })
  219. last_time = utils.getTimestamp()
  220. logger.log('withdraw_task withdraw_ =', result, last_time)
  221. if (result && moralis.isTransferSucceed(result)) {
  222. var obj = JSON.parse(result)
  223. var nonce = obj.data.nonce
  224. var curGasPrice = BigNumber(obj.data.gasPrice.hex).toNumber()
  225. var curGasLimit = BigNumber(obj.data.gasLimit.hex).toNumber()
  226. var value = BigNumber(obj.data.value.hex).toNumber()
  227. var hash = obj.data.hash
  228. last_hash = hash
  229. var update_obj = {}
  230. update_obj.withdraw_status = 2
  231. update_obj.withdraw_hash = hash
  232. update_obj.nonce = nonce
  233. update_obj.gas_price = curGasPrice.toString()
  234. update_obj.gas_limit = curGasLimit.toString()
  235. update_obj.value = value.toString()
  236. update_obj.errorMsg = ''
  237. await withdraw_db.update_withdraw_task(exec_obj.withdraw_id, update_obj)
  238. break
  239. } else {
  240. logger.error('withdraw_task withdraw_ error=', result, JSON.stringify(temp_obj))
  241. if (index < 1 + tryCount && result.includes('eth_sendRawTransaction')) {
  242. logger.error('try withdraw_:', JSON.stringify(temp_obj), index)
  243. await utils.sleep(3000)
  244. continue
  245. }
  246. var update_obj = {}
  247. update_obj.withdraw_status = 3
  248. if (typeof result === 'string') {
  249. try {
  250. result = JSON.parse(result)
  251. update_obj.errorMsg = result.errMsg
  252. } catch (error) {
  253. logger.error('withdraw_task=', result)
  254. }
  255. }
  256. await withdraw_db.update_withdraw_task(exec_obj.withdraw_id, update_obj)
  257. break
  258. }
  259. } catch (error) {
  260. var update_obj = {}
  261. update_obj.withdraw_status = 3
  262. update_obj.errorMsg = error.toString()
  263. await withdraw_db.update_withdraw_task(exec_obj.withdraw_id, update_obj)
  264. logger.error('withdraw_task error=', error.toString())
  265. break
  266. }
  267. }
  268. }
  269. logger.log("withdraw_task end")
  270. }
  271. /**
  272. * 队列版本
  273. * @param {*} ctx
  274. * @returns
  275. */
  276. async function withdrawV3(ctx) {
  277. logger.log('withdrawV3')
  278. if (ctx.request == null || ctx.request.body == null) {
  279. ctx.body = utils.toJson(-1, null, "request error. ");
  280. return
  281. }
  282. const obj = ctx.request.body;
  283. // for (let index = 0; index < 10; index++) {
  284. var log_obj = { ...obj }
  285. logger.log('withdrawV3', log_obj)
  286. var obj_ = decrypt_withdraw_content(log_obj.content)
  287. obj_.withdraw_id = obj_.withdrawId;
  288. // obj_.withdraw_id = utils.getTimestamp().toString();
  289. // var obj_ = log_obj
  290. if (obj_.withdraw_id) {
  291. var isExist = await withdraw_db.withdraw_id_exist(obj_.withdraw_id)
  292. if (isExist) {
  293. logger.error('withdraw_id_exist', obj_.withdraw_id + ' is already in the queue.')
  294. ctx.body = utils.toJson(-2, null, obj_.withdraw_id + ' is already in the queue.')
  295. return
  296. }
  297. redis.redis_push(reids_token_config.WITHDRAW_QUEUE_KEY, JSON.stringify(obj_))
  298. var info = await moralis.queryCompanyInfoFromId(0);
  299. obj_.user_address = info.user_address
  300. await withdraw_db.create_withdraw_task(obj_)
  301. // withdraw_task()
  302. ctx.body = utils.toJson(0, obj_.withdraw_id, null)
  303. } else {
  304. return utils.toJson(-2, null, ' withdraw_id not empty.')
  305. }
  306. // }
  307. }
  308. async function withdrawV3Test(ctx) {
  309. logger.log('withdrawV3Test')
  310. if (ctx.request == null || ctx.request.body == null) {
  311. ctx.body = utils.toJson(-1, null, "request error. ");
  312. return
  313. }
  314. const obj = ctx.request.body;
  315. // for (let index = 0; index < 10; index++) {
  316. var log_obj = { ...obj }
  317. logger.log('withdrawV3', log_obj)
  318. var obj_ = decrypt_withdraw_content(log_obj.content)
  319. obj_.withdraw_id = obj_.withdrawId;
  320. obj_.withdraw_id = utils.getTimestamp().toString();
  321. // var obj_ = log_obj
  322. if (obj_.withdraw_id) {
  323. var isExist = await withdraw_db.withdraw_id_exist(obj_.withdraw_id)
  324. if (isExist) {
  325. logger.error('withdraw_id_exist', obj_.withdraw_id + ' is already in the queue.')
  326. ctx.body = utils.toJson(-2, null, obj_.withdraw_id + ' is already in the queue.')
  327. return
  328. }
  329. redis.redis_push(reids_token_config.WITHDRAW_QUEUE_KEY, JSON.stringify(obj_))
  330. var info = await moralis.queryCompanyInfoFromId(0);
  331. obj_.user_address = info.user_address
  332. await withdraw_db.create_withdraw_task(obj_)
  333. ctx.body = utils.toJson(0, obj_.withdraw_id, null)
  334. } else {
  335. return utils.toJson(-2, null, ' withdraw_id not empty.')
  336. }
  337. // }
  338. }
  339. function decrypt_withdraw_content(content) {
  340. // const encryptText = utils.encrypt(log_obj);
  341. const encryptText = content;
  342. logger.log("加密", encryptText);
  343. let decryptObj = utils.decrypt(encryptText);
  344. try {
  345. logger.log("解密 before", decryptObj);
  346. decryptObj = JSON.parse(decryptObj);
  347. console.log("解密 json parse", decryptObj);
  348. } catch (error) {
  349. logger.error("json error:", error);
  350. decryptObj = null;
  351. }
  352. return decryptObj;
  353. }
  354. /**
  355. *
  356. * @param {鉴权版本} ctx
  357. */
  358. async function withdrawV2(ctx) {
  359. if (ctx.request == null || ctx.request.body == null) {
  360. ctx.body = utils.toJson(-1, null, "request error. ");
  361. return
  362. }
  363. const obj = ctx.request.body;
  364. var log_obj = { ...obj }
  365. // const encryptText = utils.encrypt(log_obj);
  366. const encryptText = log_obj.content;
  367. logger.log("加密", encryptText);
  368. let decryptObj = utils.decrypt(encryptText);
  369. try {
  370. logger.log("解密 before", decryptObj);
  371. decryptObj = JSON.parse(decryptObj);
  372. // console.log("解密 json parse", decryptObj);
  373. await withdraw_(decryptObj).then(result => {
  374. ctx.body = result;
  375. })
  376. } catch (error) {
  377. logger.error("json error:", error);
  378. ctx.body = utils.toJson(-1, null, error.toString());
  379. }
  380. }
  381. async function withdraw_(obj) {
  382. console.log("withdraw_", obj);
  383. var log_obj = { ...obj }
  384. var info = await moralis.queryCompanyInfoFromId(0);
  385. // log_obj.company_address_total_balance_before = await moralis.queryCollectBalance(info.user_address, obj.chain)
  386. log_obj.company_public_key = info.user_address
  387. logger.log('withdraw log', log_obj);
  388. return new Promise((resolve) => {
  389. moralis.withdraw(obj).then((result) => {
  390. if (moralis.isTransferSucceed(result)) {
  391. //提币日志上报
  392. log_obj.results = result
  393. log_obj.type = report.REPORT_TYPE.withdraw
  394. //缓存当前交易的 gas 费用
  395. if (result && log_obj.contractAddress) {
  396. var tr = moralis.getTransferGasFree('token', result)
  397. log_obj.withdrawTotalGasFee = tr.totalGasFree.toString()
  398. } else {
  399. var tr = moralis.getTransferGasFree('native', result)
  400. log_obj.withdrawTotalGasFee = tr.totalGasFree.toString()
  401. }
  402. // log_obj.receiver_address_total_balance_after = await queryCollectBalance(info.user_address, utils.getChainName(obj.chain))
  403. //日志上报
  404. report.logReport(log_obj)
  405. }
  406. resolve(result)
  407. });
  408. })
  409. }
  410. //出金
  411. async function withdraw(ctx) {
  412. if (ctx.request == null || ctx.request.body == null) {
  413. ctx.body = utils.toJson(-1, null, "request error. ");
  414. return
  415. }
  416. const obj = ctx.request.body;
  417. await withdraw_(obj).then(result => {
  418. ctx.body = result;
  419. })
  420. }
  421. /**
  422. * 查询出金状态
  423. * @param {*} ctx
  424. */
  425. async function getWithdrawStatus(ctx) {
  426. if (ctx.request == null || ctx.request.body == null) {
  427. ctx.body = utils.toJson(-1, null, "request error. ");
  428. return
  429. }
  430. const obj = ctx.request.body;
  431. var info = await withdraw_db.queryWithdrawInfoFromWithdrawId(obj.withdrawId)
  432. logger.log('getWithdrawStatus info', JSON.stringify(info))
  433. if (info) {
  434. if (info.withdraw_status != 3) {
  435. ctx.body = utils.toJson(0, {
  436. withdrawId: info.withdraw_id,
  437. withdrawStatus: info.withdraw_status,
  438. withdrawHash: info.withdraw_hash,
  439. chainId: info.chain_id,
  440. transferTimestamp: info.update_time,
  441. }, null)
  442. } else {
  443. ctx.body = utils.toJson(0, {
  444. withdrawId: info.withdraw_id,
  445. withdrawStatus: info.withdraw_status,
  446. withdrawHash: info.withdraw_hash,
  447. chainId: info.chain_id,
  448. transferTimestamp: info.update_time,
  449. errorMsg: info.errorMsg
  450. }, null)
  451. }
  452. } else {
  453. ctx.body = utils.toJson(-1, null, obj.withdraw_id + ' id does not exist.')
  454. }
  455. }
  456. async function timer_transfer_task() {
  457. var index = 0
  458. var delay = 60 * 1000 * 60
  459. while (1) {
  460. var obj_ = {
  461. "type": "erc20",
  462. "contractAddress": "0xFF94950Ee8A79c52cC4B0Aa5178C8cEa48A3F3A6",
  463. "amount": "111000000000000000000",
  464. "chain": "bsc_testnet",
  465. "receiver": "0x3B525c35DdC323B08241493f148340D89e3A73a7",
  466. "withdrawId": index.toString()
  467. }
  468. obj_.withdraw_id = utils.getTimestamp().toString();
  469. var info = await moralis.queryCompanyInfoFromId(0);
  470. obj_.user_address = info.user_address
  471. await withdraw_db.create_withdraw_task(obj_)
  472. redis.redis_push(reids_token_config.WITHDRAW_QUEUE_KEY, JSON.stringify(obj_))
  473. await utils.sleep(delay)
  474. index += 1
  475. }
  476. }
  477. //获取交易记录
  478. router.post('/getTransfers', getTransfers)
  479. router.post('/getTransfersV2', getTransfersV2)
  480. // 获取所有代币价格
  481. router.post('/getAllTotkenPrice', getAllTotkenPrice)
  482. // router.post('/transfer', transfer)
  483. //提现
  484. router.post('/withdraw', withdraw);
  485. //提现鉴权-body 加密
  486. router.post('/withdrawV2', withdrawV2);
  487. //队列的形式
  488. router.post('/withdrawV3', withdrawV3);
  489. if (process.env.NODE_ENV == 'dev')
  490. router.post('/withdrawV3Test', withdrawV3Test);
  491. //查询出金服务
  492. router.post('/getWithdrawStatus', getWithdrawStatus);
  493. //获取所有地址的所要消耗的最低提取费
  494. router.post('/getAllTokenWithdrawInfoLists', getAllTokenWithdrawInfoLists)
  495. // 定时任务 提币+归集
  496. withdraw_task();
  497. collect_conis_task();
  498. if (process.env.NODE_ENV == 'dev' || process.env.NODE_ENV == 'test')
  499. timer_transfer_task()
  500. module.exports = router