index.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. const OneInch = require('./1inch.js')
  2. const DoDo = require('./dodo.js')
  3. const BinanceSpot = require('./BinanceSpot.js')
  4. const Config = require('./Config.js')
  5. const PrivateConfig = require('./PrivateConfig.js')
  6. const MyKit = require('./kit/MyKit.js')
  7. const Wallet = require('./wallet.js')
  8. const wallet = new Wallet()
  9. const bs = new BinanceSpot('-', '-')
  10. async function onTickDoDo(toToken) {
  11. while (true) {
  12. // 如果BNB连续变化maxRefreshBNBTimes次,则1INCH或其他交易所可能已经出bug。
  13. if (Config.refreshBNBTimes >= Config.maxRefreshBNBTimes) {
  14. console.log(`机器人判定交易所可能出了bug,失败次数:${Config.refreshBNBTimes},为保护BNB,已停止交易。`)
  15. break
  16. }
  17. try {
  18. const tokenSymbol = toToken.symbol
  19. const baseToken = Config.baseToken
  20. if (!baseToken.balance) {
  21. await MyKit.sleep(1000)
  22. continue
  23. }
  24. const binancePairSymbol = tokenSymbol + baseToken.symbol
  25. const amount = Config.baseTokenAmount < baseToken.balance ? Config.baseTokenAmount : baseToken.balance
  26. const profitLimit = toToken.profitLimit ? toToken.profitLimit : Config.profitLimit
  27. const binancePrice = await bs.price(binancePairSymbol)
  28. // 一次判断
  29. let time = MyKit.getTimeByMillisecond(new Date().getTime())
  30. // 直接判断并抢单
  31. const DoDoSwapRst = await DoDo.swap(baseToken.contract, baseToken.decimals, toToken.contract, toToken.decimals, amount)
  32. // 对询价结果容错
  33. if (!DoDoSwapRst || !DoDoSwapRst.data) {
  34. continue
  35. }
  36. // 构建交易包
  37. const swapRST = DoDoSwapRst.data
  38. swapRST.price = MyKit._N(swapRST.resPricePerToToken, 6)
  39. swapRST.tx = {
  40. gasPrice: 7 * (10 ** 9),
  41. gas: '500000',
  42. from: PrivateConfig.address,
  43. to: swapRST.to,
  44. data: swapRST.data
  45. }
  46. // 间距百分比与预估利润
  47. distance = MyKit._N(100 * ((binancePrice / swapRST.price - 1.001)), 4)
  48. profit = MyKit._N(amount * distance / 100 - Config.charge, 4)
  49. // debug
  50. if (Config.debug) {
  51. console.log(`[${time}, ${binancePairSymbol}] D价格: ${swapRST.price},C价格: ${binancePrice},利润:${profit},源:${swapRST.useSource}。`)
  52. }
  53. // 屏蔽询价源
  54. if (Config.limitSources.indexOf(swapRST.useSource) !== -1 || !swapRST.useSource) {
  55. continue
  56. }
  57. if (swapRST.price && !baseToken.isSwap && profit > Config.profitLimit) {
  58. if (distance > 20) {
  59. console.log('[利润大于20%]手续费*1.5执行抢单逻辑.')
  60. swapRST.tx.gasPrice = parseInt((parseInt(swapRST.tx.gasPrice) * 1.5)) + ''
  61. }
  62. console.log(`[${time}, ${tokenSymbol}]判定通过, 利润率:${distance}%, 预估利润:${profit}${baseToken.symbol}, 目标利润:${Config.profitLimit}${baseToken.symbol}.\n`)
  63. console.log(`DEFI价格: ${swapRST.price}, CEFI价格: ${binancePrice}, 报价源: ${swapRST.useSource}\n\n`)
  64. await wallet.transferByTXDoDo(swapRST.tx)
  65. }
  66. // else if (profit > 0) {
  67. // console.log(`[${time}, ${tokenSymbol}]二次判定不通过, 利润率:${distance}%, 预估利润:${profit}${baseToken.symbol}, 目标利润:${profitLimit}${baseToken.symbol}.\n`)
  68. // console.log(`DEFI价格: ${swapRST.price}, CEFI价格: ${binancePrice}, 报价源: ${swapRST.useSource}\n\n`)
  69. // }
  70. } catch (e) {
  71. console.log(e)
  72. }
  73. await MyKit.sleep(Config.delay)
  74. }
  75. }
  76. async function onTick1Inch(toToken) {
  77. while (true) {
  78. toToken.alive = true
  79. // 如果BNB连续变化maxRefreshBNBTimes次,则1INCH或其他交易所可能已经出bug。
  80. if (Config.refreshBNBTimes >= Config.maxRefreshBNBTimes) {
  81. console.log(`机器人判定交易所可能出了bug,失败次数:${Config.refreshBNBTimes},为保护BNB,已停止交易。`)
  82. break
  83. }
  84. try {
  85. const tokenSymbol = toToken.symbol
  86. const baseToken = Config.baseToken
  87. if (!baseToken.balance) {
  88. await MyKit.sleep(1000)
  89. continue
  90. }
  91. const binancePairSymbol = tokenSymbol + baseToken.symbol
  92. const amount = Config.baseTokenAmount < baseToken.balance ? Config.baseTokenAmount : baseToken.balance
  93. const OneInchPrice = await OneInch.price(baseToken.contract, baseToken.decimals, amount, toToken.contract)
  94. const binancePrice = await bs.price(binancePairSymbol)
  95. let distance = MyKit._N(100 * ((binancePrice / OneInchPrice) - 1.001), 4)
  96. let profit = MyKit._N(amount * distance / 100 - Config.charge, 4)
  97. let time = MyKit.getTimeByMillisecond(new Date().getTime())
  98. // debug
  99. if (Config.debug && profit > 0) {
  100. console.log(`[${time}, ${binancePairSymbol}] D价格: ${OneInchPrice},C价格: ${binancePrice},利润:${profit}。`)
  101. }
  102. // 一次判断
  103. if (profit > Config.profitLimit) {
  104. // 二次判断,并获取交易tx
  105. const swapRST = await OneInch.swap(baseToken.contract, toToken.contract, baseToken.decimals, amount)
  106. if (!swapRST) {
  107. continue
  108. }
  109. distance = MyKit._N(100 * ((binancePrice / swapRST.price) - 1.001), 4)
  110. profit = MyKit._N(amount * distance / 100 - Config.charge, 4)
  111. if (!baseToken.isSwap && profit > Config.profitLimit) {
  112. time = MyKit.getTimeByMillisecond(new Date().getTime())
  113. // gas容错
  114. swapRST.tx.gas = parseInt((parseInt(swapRST.tx.gas) * 1.5)) + ''
  115. // 如果利润大于5%,手续费*2抢单
  116. if (distance > 20) {
  117. console.log('[利润大于20%]手续费*1.5执行抢单逻辑.')
  118. swapRST.tx.gasPrice = parseInt((parseInt(swapRST.tx.gasPrice) * 1.5)) + ''
  119. }
  120. console.log(`[${time}, ${tokenSymbol}]判定通过, 利润率:${distance}%, 预估利润:${profit}${baseToken.symbol}, 目标利润:${Config.profitLimit}${baseToken.symbol}.\n`)
  121. console.log(`DEFI价格: ${swapRST.price}, CEFI价格: ${binancePrice}\n\n`)
  122. await wallet.transferByTX1Inch(swapRST.tx)
  123. }
  124. }
  125. await MyKit.sleep(5000)
  126. } catch (e) {
  127. console.log(e)
  128. }
  129. }
  130. }
  131. async function flushBalance () {
  132. while (true) {
  133. try {
  134. Config.baseToken.contractModel.methods.balanceOf(PrivateConfig.address).call((err, result) => {
  135. if (result) {
  136. let balance = MyKit._N(parseFloat(result) / (10 ** Config.baseToken.decimals), 4)
  137. const prevBalance = Config.baseToken.balance
  138. Config.baseToken.balance = balance
  139. if ((prevBalance || prevBalance === 0) && balance !== prevBalance) {
  140. console.log(`[${Config.baseToken.symbol}余额变更]${prevBalance}->${balance}, 交易失败(BNB连续减少但BUSD不变化)次数: 0.\n`)
  141. Config.refreshBNBTimes = 0
  142. } else if (!prevBalance && prevBalance !== 0) {
  143. console.log(`[${Config.baseToken.symbol}余额初始化]${balance}.`)
  144. }
  145. }
  146. })
  147. } catch (e) {
  148. console.log(e)
  149. }
  150. await MyKit.sleep(1000)
  151. }
  152. }
  153. async function flushBNB() {
  154. while (true) {
  155. try {
  156. let balance = await wallet.getBalance()
  157. if (balance) {
  158. balance = MyKit._N(parseFloat(balance), 4)
  159. const prevBalance = Config.bnbBalance
  160. if ((prevBalance || prevBalance === 0) && balance !== prevBalance) {
  161. console.log(`[BNB余额变更]${prevBalance}->${balance}.`)
  162. // 发送过交易的情况下才判定为因交易减少BNB
  163. if (balance < prevBalance) {
  164. console.log(`\t当前交易失败(BNB连续减少但BUSD不变化)次数:${++Config.refreshBNBTimes}.`)
  165. }
  166. } else if (!prevBalance && prevBalance !== 0) {
  167. console.log(`[BNB余额初始化]${balance}.`)
  168. }
  169. Config.bnbBalance = balance
  170. }
  171. } catch (e) {
  172. console.log(e)
  173. }
  174. await MyKit.sleep(1000)
  175. }
  176. }
  177. async function main () {
  178. console.log('初始化中...')
  179. console.log(`交易所:${Config.exchange}。`)
  180. await MyKit.sleep(1000)
  181. flushBalance()
  182. flushBNB()
  183. for (const token of Config.tokenList) {
  184. if (Config.exchange === '1inch') {
  185. onTick1Inch(token)
  186. } else if (Config.exchange === 'dodo') {
  187. onTickDoDo(token)
  188. }
  189. }
  190. }
  191. main()