dodo.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. const HttpKit = require('../kit/http-kit.js')
  2. const Config = require('../config/config.js')
  3. const PrivateConfig = require('../PrivateConfig.js')
  4. const SimpleWeb3 = require("./web3/simple-web3");
  5. const chainID = 56
  6. const rpc = 'https://bsc-dataseed1.binance.org'
  7. class DoDo {}
  8. DoDo.price = async function(sellToken = '0xe9e7cea3dedca5984780bafc599bd69add087d56',
  9. sellTokenDecimals = 18,
  10. sellAmount = 100,
  11. buyToken = '0xba2ae424d960c26247dd6c32edc70b295c744c43',
  12. slippagePercentage = 0.03,
  13. affiliateAddress = '0x221d5c4993297Fd95fA17743b9297E2e49FCe9D2') {
  14. sellAmount = sellAmount * (10 ** sellTokenDecimals)
  15. const url = `https://bsc.api.0x.org/swap/v1/quote?sellToken=${sellToken}&sellAmount=${sellAmount}&buyToken=${buyToken}`
  16. + `&slippagePercentage=${slippagePercentage}&affiliateAddress=${affiliateAddress}`
  17. const { data: rst } = await HttpKit.get(url)
  18. if (!rst || !rst.price) {
  19. return rst
  20. }
  21. if (sellToken === '0xe9e7cea3dedca5984780bafc599bd69add087d56') {
  22. return 1 / parseFloat(rst.price)
  23. } else {
  24. parseFloat(rst.price)
  25. }
  26. }
  27. DoDo.buildSwapTx = async function(fromTokenAddress = '0xe9e7cea3dedca5984780bafc599bd69add087d56',
  28. fromTokenDecimals = 18,
  29. toTokenAddress = '0x111111111117dc0aa78b770fa6a738034120c302',
  30. toTokenDecimals = 18,
  31. amount = 100,
  32. userAddr = PrivateConfig.address,
  33. slippage = 1) {
  34. amount = amount * (10 ** fromTokenDecimals)
  35. const url = `https://dodo-route.dodoex.io/dodoapi/getdodoroute?fromTokenAddress=${fromTokenAddress}&fromTokenDecimals=${fromTokenDecimals}`
  36. + `&toTokenAddress=${toTokenAddress}&toTokenDecimals=${toTokenDecimals}&fromAmount=${amount}&userAddr=${userAddr}`
  37. + `&slippage=${slippage}&chainId=${chainID}&rpc=${rpc}`
  38. const { data: rst } = await HttpKit.get(url, {
  39. 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4464.0 Safari/537.36 Edg/91.0.852.0'
  40. })
  41. return rst
  42. }
  43. DoDo.swap = async function(txObject) {
  44. const txCount = await SimpleWeb3.web3.eth.getTransactionCount(PrivateConfig.address)
  45. txObject.nonce = SimpleWeb3.web3.utils.toHex(txCount)
  46. txObject.gasPrice = SimpleWeb3.web3.utils.toHex(txObject.gasPrice)
  47. txObject.gas = SimpleWeb3.web3.utils.toHex(txObject.gas)
  48. txObject.gasLimit = SimpleWeb3.web3.utils.toHex(txObject.gasLimit)
  49. await SimpleWeb3.sendTransaction(txObject)
  50. }
  51. DoDo.Start = async function(toToken) {
  52. while (true) {
  53. // 如果BNB连续变化maxRefreshBNBTimes次,则1INCH或其他交易所可能已经出bug。
  54. if (Config.refreshBNBTimes >= Config.maxRefreshBNBTimes) {
  55. console.log(`机器人判定交易所可能出了bug,失败次数:${Config.refreshBNBTimes},为保护BNB,已停止交易。`)
  56. break
  57. }
  58. try {
  59. const tokenSymbol = toToken.symbol
  60. const baseToken = Config.baseToken
  61. if (!baseToken.balance) {
  62. await MyKit.sleep(1000)
  63. continue
  64. }
  65. const binancePairSymbol = tokenSymbol + baseToken.symbol
  66. const amount = Config.baseTokenAmount < baseToken.balance ? Config.baseTokenAmount : baseToken.balance
  67. const profitLimit = toToken.profitLimit ? toToken.profitLimit : Config.profitLimit
  68. const binancePrice = await bs.price(binancePairSymbol)
  69. // 一次判断
  70. let time = MyKit.getTimeByMillisecond(new Date().getTime())
  71. // 直接判断并抢单
  72. const DoDoSwapRst = await DoDo.swap(baseToken.contract, baseToken.decimals, toToken.contract, toToken.decimals, amount)
  73. // 对询价结果容错
  74. if (!DoDoSwapRst || !DoDoSwapRst.data) {
  75. continue
  76. }
  77. // 构建交易包
  78. const swapRST = DoDoSwapRst.data
  79. swapRST.price = MyKit._N(swapRST.resPricePerToToken, 6)
  80. swapRST.tx = {
  81. gasPrice: 7 * (10 ** 9),
  82. gas: '500000',
  83. from: PrivateConfig.address,
  84. to: swapRST.to,
  85. data: swapRST.data
  86. }
  87. // 间距百分比与预估利润
  88. distance = MyKit._N(100 * ((binancePrice / swapRST.price - 1.001)), 4)
  89. profit = MyKit._N(amount * distance / 100 - Config.charge, 4)
  90. // debug
  91. if (Config.debug) {
  92. console.log(`[${time}, ${binancePairSymbol}] D价格: ${swapRST.price},C价格: ${binancePrice},利润:${profit},源:${swapRST.useSource}。`)
  93. }
  94. // 屏蔽询价源
  95. if (Config.limitSources.indexOf(swapRST.useSource) !== -1 || !swapRST.useSource) {
  96. continue
  97. }
  98. if (swapRST.price && !baseToken.isSwap && profit > Config.profitLimit) {
  99. if (distance > 20) {
  100. console.log('[利润大于20%]手续费*1.5执行抢单逻辑.')
  101. swapRST.tx.gasPrice = parseInt((parseInt(swapRST.tx.gasPrice) * 1.5)) + ''
  102. }
  103. console.log(`[${time}, ${tokenSymbol}]判定通过, 利润率:${distance}%, 预估利润:${profit}${baseToken.symbol}, 目标利润:${Config.profitLimit}${baseToken.symbol}.\n`)
  104. console.log(`DEFI价格: ${swapRST.price}, CEFI价格: ${binancePrice}, 报价源: ${swapRST.useSource}\n\n`)
  105. await wallet.transferByTXDoDo(swapRST.tx)
  106. }
  107. // else if (profit > 0) {
  108. // console.log(`[${time}, ${tokenSymbol}]二次判定不通过, 利润率:${distance}%, 预估利润:${profit}${baseToken.symbol}, 目标利润:${profitLimit}${baseToken.symbol}.\n`)
  109. // console.log(`DEFI价格: ${swapRST.price}, CEFI价格: ${binancePrice}, 报价源: ${swapRST.useSource}\n\n`)
  110. // }
  111. } catch (e) {
  112. console.log(e)
  113. }
  114. await MyKit.sleep(Config.delay)
  115. }
  116. }
  117. module.exports = DoDo