pendingTradeV1.2.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. from web3Tools import *
  2. from calcTools import *
  3. def calOnlyLpInRouterArray(routerArray):
  4. onlyLpArray = []
  5. for router in routerArray:
  6. for lpInfo in router:
  7. lp = lpInfo['lp']
  8. if lp in onlyLpArray:
  9. continue
  10. if lp in nowBlockLpRes:
  11. continue
  12. onlyLpArray.append(lp)
  13. return onlyLpArray
  14. def findLpArrayRouter(lpArray, lpRouter256Info):
  15. routerArray = []
  16. sumUsed = {}
  17. for lpAddress in lpArray:
  18. if lpAddress not in lpRouter256Info:
  19. continue
  20. lpRouter = lpRouter256Info[lpAddress]
  21. for lpRouterI in lpRouter:
  22. sumValue = ''
  23. same = False
  24. for lpi in lpRouterI:
  25. sumValue = sumValue + lpi['lp'] + lpi['inToken']
  26. if lpi['lp'] == lpAddress:
  27. same = True
  28. if same:
  29. sumUsed[sumValue] = lpRouterI
  30. for key in sumUsed:
  31. routerArray.append(sumUsed[key])
  32. return routerArray
  33. def calLpInTradeInfo(tradeInfo):
  34. lpArray = []
  35. for i in tradeInfo:
  36. if i['to'] in topLpInfo and i['to'] not in lpArray:
  37. lpArray.append(i['to'])
  38. if i['from'] in topLpInfo and i['from'] not in lpArray:
  39. lpArray.append(i['from'])
  40. return lpArray
  41. def gethashInfo(hsResult):
  42. try:
  43. hashInfo = {}
  44. hashInfo['fromAddress'] = hsResult['from']
  45. hashInfo['toAddress']= hsResult['to']
  46. hashInfo['inputData'] = hsResult['input']
  47. hashInfo['function'] = hashInfo['inputData'][:10]
  48. hashInfo['value'] = int(hsResult['value'], 16)
  49. hashInfo['nonce'] = int(hsResult['nonce'], 16) # 对比nonce
  50. hashInfo['hash'] = hsResult['hash']
  51. hashInfo['gasLimit'] = int(hsResult['gas'], 16)
  52. hashInfo['type'] = int(hsResult['type'],16)
  53. hashInfo['gasPrice'] = int(hsResult['gasPrice'], 16)
  54. if hashInfo['type'] == 2:
  55. hashInfo['maxFeePerGas'] = int(hsResult['maxFeePerGas'], 16)
  56. hashInfo['maxPriorityFeePerGas'] = int(hsResult['maxPriorityFeePerGas'], 16)
  57. return hashInfo
  58. except:
  59. return False
  60. def getLpArrayResAfterTrade(fromAddress, toAddress, inputData, value, lpArray, block = 'latest'):
  61. paramsRes = {}
  62. paramsRes['to'] = toolsAddress
  63. paramsRes['data'] = '0xd94ccee1' + encodeInput(0x20, lpArray)
  64. params0 = {}
  65. params0['from'] = fromAddress
  66. params0['to'] = toAddress
  67. params0['data'] = inputData
  68. params0['value'] = hex(int(value))
  69. r = batchCall([params0, paramsRes], block)
  70. result = r['result'][1]['Return']
  71. result = w3.debug.decodeOutput(result)
  72. info = {}
  73. length = len(lpArray)
  74. for index in range(0, length):
  75. lpAddress = lpArray[index]
  76. r0 = result[index + 3]
  77. r1 = result[index + 4 + length]
  78. info[lpAddress] = [r0, r1]
  79. return info
  80. def calRouterProfit(router):
  81. # 整理LP信息
  82. for lpInfo in router:
  83. lpAddress = lpInfo['lp']
  84. r0 = nowBlockLpRes[lpAddress][0]
  85. r1 = nowBlockLpRes[lpAddress][1]
  86. lpInfo['fee'] = topLpInfo[lpAddress]['fee']
  87. if lpInfo['inToken'] < lpInfo['outToken']:
  88. lpInfo['rIn'] = r0
  89. lpInfo['rOut'] = r1
  90. else:
  91. lpInfo['rIn'] = r1
  92. lpInfo['rOut'] = r0
  93. # ABA
  94. if len(router) == 2:
  95. tokenLoan = router[1]['outToken']
  96. tokenIn0 = router[0]['inToken']
  97. tokenLoanETHPrice = baseTokenInfo[tokenLoan]['price'] * 10 ** baseTokenInfo[WETH]['decimals'] / 10 ** baseTokenInfo[tokenLoan]['decimals']
  98. # WETH - A - WETH
  99. tradeInfo = calBestAmountV2V2(router[0]['rIn'], router[0]['rOut'], router[0]['fee'], router[1]['rIn'], router[1]['rOut'], router[1]['fee'] )
  100. profit = tradeInfo['profit']
  101. tradeInfo['ethProfit'] = profit * tokenLoanETHPrice
  102. #printTime(router, amountIn0, amountOut0, amountOut1, profit)
  103. if tradeInfo['ethProfit'] < tradeMinProfit:
  104. return False
  105. else:
  106. tradeInfo['lp0'] = router[0]['lp']
  107. tradeInfo['lp1'] = router[1]['lp']
  108. tradeInfo['fee0'] = router[0]['fee']
  109. tradeInfo['fee1'] = router[1]['fee']
  110. tradeInfo['indexIn0'] = router[0]['indexIn']
  111. tradeInfo['indexIn1'] = router[1]['indexIn']
  112. tradeInfo['tokenLoan'] = tokenLoan
  113. tradeInfo['tokenIn0'] = tokenIn0
  114. tradeInfo['tradeToken0'] = router[0]['outToken']
  115. tradeInfo['type'] = 'type2'
  116. return tradeInfo
  117. # ABCA
  118. elif len(router) == 3:
  119. tokenLoan = router[2]['outToken']
  120. tokenIn0 = router[0]['inToken']
  121. tokenLoanETHPrice = baseTokenInfo[tokenLoan]['price'] * 10 ** baseTokenInfo[WETH]['decimals'] / 10 ** baseTokenInfo[tokenLoan]['decimals']
  122. tradeInfo = calBestAmountABCA(router[0]['rIn'], router[0]['rOut'], router[0]['fee'],
  123. router[1]['rIn'], router[1]['rOut'], router[1]['fee'],
  124. router[2]['rIn'], router[2]['rOut'], router[2]['fee'])
  125. profit = tradeInfo['profit']
  126. tradeInfo['ethProfit'] = profit * tokenLoanETHPrice
  127. #printTime(router, amountIn0, amountOut0, amountOut1, amountOut2, profit)
  128. if tradeInfo['ethProfit'] < tradeMinProfit:
  129. return False
  130. else:
  131. tradeInfo['lp0'] = router[0]['lp']
  132. tradeInfo['lp1'] = router[1]['lp']
  133. tradeInfo['lp2'] = router[2]['lp']
  134. tradeInfo['fee0'] = router[0]['fee']
  135. tradeInfo['fee1'] = router[1]['fee']
  136. tradeInfo['fee2'] = router[2]['fee']
  137. tradeInfo['indexIn0'] = router[0]['indexIn']
  138. tradeInfo['indexIn1'] = router[1]['indexIn']
  139. tradeInfo['indexIn2'] = router[2]['indexIn']
  140. tradeInfo['tokenLoan'] = tokenLoan
  141. tradeInfo['tokenIn0'] = tokenIn0
  142. tradeInfo['tradeToken0'] = router[0]['outToken']
  143. tradeInfo['tradeToken1'] = router[1]['outToken']
  144. tradeInfo['type'] = 'type3'
  145. return tradeInfo
  146. def getABAInput(lp0, lp1, lp2, tokenIn0, tokenLoan, fee0, fee1, fee2, lp0InIndex, lp1InIndex, lp2InIndex, minProfit):
  147. function = '0x5105a538'
  148. inputData = encodeInput(lp0, lp1, lp2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  149. fee0, fee1, fee2, lp0InIndex, lp1InIndex, lp2InIndex,
  150. tokenIn0, tokenLoan, minProfit, 0)
  151. inputData = function + inputData
  152. return inputData
  153. def callABAPending(tradeInfo, hashInfo):
  154. tradeInputData = getABAInput(tradeInfo['lp0'], tradeInfo['lp1'],tradeInfo['lp2'],
  155. tradeInfo['tokenIn0'], tradeInfo['tokenLoan'],
  156. tradeInfo['fee0'], tradeInfo['fee1'],tradeInfo['fee2'],
  157. tradeInfo['indexIn0'], tradeInfo['indexIn1'],tradeInfo['indexIn2'],
  158. baseTokenInfo[tradeInfo['tokenIn0']]['profitMin'])
  159. gasCalInputData = '0x4327f0db' + encodeInput(v5Address, 0x40, (len(tradeInputData) - 2)/2 , tradeInputData)
  160. paramsTrade = {}
  161. paramsTrade['from'] = myAddress
  162. paramsTrade['to'] = '0xEAf90BcB75e7B92900678c4aBD80883b414bEDD6'
  163. paramsTrade['data'] = gasCalInputData
  164. paramsHash = {}
  165. paramsHash['from'] = hashInfo['fromAddress']
  166. paramsHash['to'] = hashInfo['toAddress']
  167. paramsHash['data'] = hashInfo['inputData']
  168. paramsHash['value'] = hex(hashInfo['value'])
  169. result = batchCall([paramsHash,paramsTrade])
  170. result = result['result'][1]['Return']
  171. info = w3.debug.decodeOutput(result)
  172. r = {}
  173. r['gasUsed'] = info[1]
  174. r['info'] = info[3:]
  175. returnInfo = {'type':2, 'lp0': tradeInfo['lp0'], 'lpLoan':tradeInfo['lp1'], 'tokenIn':tradeInfo['tokenIn0'], 'tokenLoan':tradeInfo['tokenLoan'], 'profit':0, 'sumValue':0}
  176. if len(r['info']) != 23 or r['info'][-1] == 0:
  177. return returnInfo
  178. sumValue = r['info'][3] + r['info'][4] + r['info'][5] + r['info'][6] + r['info'][7] + r['info'][8]
  179. returnInfo['sumValue'] = sumValue
  180. returnInfo['profit'] = r['info'][-1]
  181. returnInfo['gasUsed'] = r['gasUsed']
  182. returnInfo['inputData'] = tradeInputData
  183. return returnInfo
  184. initTime = time.time()
  185. pendingInitTime = time.time()
  186. topLpInfo = readAny('topLP')
  187. lpRouterInfo = readAny('abcd')
  188. lpRouter256Info = readAny('256Router')
  189. r = w3.provider.make_request('eth_newPendingTransactionFilter',[])
  190. filterId = r['result']
  191. printTime(filterId)
  192. nowBlockLpRes = {}
  193. dataUsed = []
  194. while True:
  195. try:
  196. hsArry = w3.provider.make_request('eth_getFilterChanges', [filterId])
  197. hsArry = hsArry['result']
  198. nowBlockLpRes = {}
  199. blockNumber = w3.eth.blockNumber
  200. baseGasPrice = getBaseGasPrice(blockNumber) * 1.5
  201. if baseGasPrice < 3 * 1e9:
  202. baseGasPrice = 3 * 1e9
  203. if hsArry:
  204. for hsI in hsArry:
  205. tradeInfoArray = []
  206. #printTime('hsI OK')
  207. hsResult = w3.new.getTransaction(hsI)
  208. #printTime('hsResult OK')
  209. hashInfoExp = {
  210. 'blockHash': None,
  211. 'blockNumber': None,
  212. 'from': '0x7a5ddf8a2a924e4faa9d76b97b1363c864062df5',
  213. 'gas': '0x5208',
  214. 'gasPrice':
  215. '0x5968f26e',
  216. 'maxFeePerGas': '0x5968f26e',
  217. 'maxPriorityFeePerGas': '0x59682f00',
  218. 'hash': '0xe5eb2fb4ce91e96501e6ee6423198f3395341bab744cdad7eb2e354ac9fec8ac',
  219. 'input': '0x',
  220. 'nonce': '0x3',
  221. 'to': '0x92be6de0ae6d89a2378795553ecb4cdb820e0d7b',
  222. 'transactionIndex': None,
  223. 'value': '0x2386f26fc10000',
  224. 'type': '0x2',
  225. }
  226. hashInfo = gethashInfo(hsResult)
  227. if not hashInfo:
  228. continue
  229. if hashInfo['function'] not in swapFunction:
  230. continue
  231. if hashInfo['gasPrice'] > baseGasPrice * 5 or hashInfo['gasPrice'] > 20 * 1e9:
  232. continue
  233. #printTime(hsI)
  234. traceResult = w3.debug.traceCall(hashInfo['fromAddress'], hashInfo['toAddress'], hashInfo['inputData'], hashInfo['value'])
  235. #printTime('traceCall OK')
  236. if not traceResult:
  237. continue
  238. if 'error' in traceResult:
  239. continue
  240. if 'calls' not in traceResult:
  241. continue
  242. tradeInfo = w3.debug.transferDecodeFromCalldata(traceResult['calls'])
  243. #printTime('transferDecodeFromCalldata OK')
  244. if not tradeInfo:
  245. continue
  246. lpArray = calLpInTradeInfo(tradeInfo)
  247. if not lpArray:
  248. continue
  249. #printTime('calLpInTradeInfo OK', len(lpArray))
  250. lpRouterArray = findLpArrayRouter(lpArray, lpRouter256Info)
  251. if not lpRouterArray:
  252. continue
  253. #printTime('findLpArrayRouter OK', len(lpRouterArray))
  254. onlyLp = calOnlyLpInRouterArray(lpRouterArray)
  255. #printTime('calOnlyLpInRouterArray OK', len(onlyLp))
  256. # 获取余额
  257. lpResArray = getLpArrayResAfterTrade(hashInfo['fromAddress'], hashInfo['toAddress'], hashInfo['inputData'], hashInfo['value'], onlyLp)
  258. # 余额进行缓存
  259. for lpResI in lpResArray:
  260. nowBlockLpRes[lpResI] = lpResArray[lpResI]
  261. #printTime('RES OK')
  262. #计算每一个路由的利润
  263. for lpRouter in lpRouterArray:
  264. tradeInfo = calRouterProfit(lpRouter)
  265. if tradeInfo:
  266. type = tradeInfo['type']
  267. if type == 'type3':
  268. result = callABAPending(tradeInfo, hashInfo)
  269. if result['profit'] < tradeMinProfit:
  270. continue
  271. sumValue = result['sumValue']
  272. if sumValue in dataUsed:
  273. continue
  274. tokenLoanETHPrice = baseTokenInfo[tradeInfo['tokenLoan']]['price'] * 10 ** baseTokenInfo[WETH]['decimals'] / 10 ** \
  275. baseTokenInfo[tradeInfo['tokenLoan']]['decimals']
  276. result['ethProfit'] = result['profit'] * tokenLoanETHPrice
  277. result['ethProfit-E18'] = result['profit'] * tokenLoanETHPrice / 1e18
  278. result['tureProfit'] = result['ethProfit'] - result['gasUsed'] * int(hsResult['gasPrice'],16)
  279. result['maxPrice'] = result['ethProfit'] / result['gasUsed']
  280. if result['tureProfit'] < tradeMinProfit:
  281. continue
  282. tradeInfoArray.append(result)
  283. maxProfitInfo = {'tureProfit' : 0}
  284. for tradeInfoI in tradeInfoArray:
  285. if tradeInfoI['tureProfit'] > maxProfitInfo['tureProfit']:
  286. maxProfitInfo = tradeInfoI
  287. if maxProfitInfo['tureProfit'] > 0:
  288. printTime(maxProfitInfo['lp0'], maxProfitInfo['lpLoan'], maxProfitInfo['tureProfit'] / 1e18, hashInfo['hash'])
  289. tradeParams = {}
  290. tradeParams['to'] = v5Address
  291. tradeParams['data'] = maxProfitInfo['inputData']
  292. tradeParams['gas'] = hex(int(1e6))
  293. tradeParams['value'] = hex(0)
  294. tradeParams['type'] = hsResult['type']
  295. if tradeParams['type'] == '0x2':
  296. tradeParams['maxFeePerGas'] = hsResult['maxFeePerGas']
  297. tradeParams['maxPriorityFeePerGas'] = hsResult['maxPriorityFeePerGas']
  298. else:
  299. tradeParams['gasPrice'] = hsResult['gasPrice']
  300. params = {}
  301. params['method'] = 'sendTransaction'
  302. params['params'] = tradeParams
  303. try:
  304. hs = requests.post(url='http://127.0.0.1:410/operation', json=params).text
  305. if len(hs)>50:
  306. printTime(blockNumber, 'https://www.oklink.com/en/ethw/tx/' + str(hs))
  307. printTime('-' * 50)
  308. except:
  309. hs = 'err seed'
  310. pendingInitTime = time.time()
  311. time.sleep(0.0005)
  312. except BaseException as err:
  313. printTime(traceback.format_exc())
  314. printTime('loop', err)
  315. time.sleep(20)
  316. try:
  317. r = w3.provider.make_request('eth_newPendingTransactionFilter',[])
  318. filterId = r['result']
  319. printTime('filterId',filterId)
  320. except:
  321. time.sleep(10)