from web3Tools import * from calcTools import * def calOnlyLpInRouterArray(routerArray): onlyLpArray = [] for router in routerArray: for lpInfo in router: lp = lpInfo['lp'] if lp in onlyLpArray: continue if lp in nowBlockLpRes: continue onlyLpArray.append(lp) return onlyLpArray def findLpArrayRouter(lpArray, lpRouter256Info): routerArray = [] sumUsed = {} for lpAddress in lpArray: if lpAddress not in lpRouter256Info: continue lpRouter = lpRouter256Info[lpAddress] for lpRouterI in lpRouter: sumValue = '' same = False for lpi in lpRouterI: sumValue = sumValue + lpi['lp'] + lpi['inToken'] if lpi['lp'] == lpAddress: same = True if same: sumUsed[sumValue] = lpRouterI for key in sumUsed: routerArray.append(sumUsed[key]) return routerArray def calLpInTradeInfo(tradeInfo): lpArray = [] for i in tradeInfo: if i['to'] in topLpInfo and i['to'] not in lpArray: lpArray.append(i['to']) if i['from'] in topLpInfo and i['from'] not in lpArray: lpArray.append(i['from']) return lpArray def gethashInfo(hsResult): try: hashInfo = {} hashInfo['fromAddress'] = hsResult['from'] hashInfo['toAddress']= hsResult['to'] hashInfo['inputData'] = hsResult['input'] hashInfo['function'] = hashInfo['inputData'][:10] hashInfo['value'] = int(hsResult['value'], 16) hashInfo['nonce'] = int(hsResult['nonce'], 16) # 对比nonce hashInfo['hash'] = hsResult['hash'] hashInfo['gasLimit'] = int(hsResult['gas'], 16) hashInfo['type'] = int(hsResult['type'],16) hashInfo['gasPrice'] = int(hsResult['gasPrice'], 16) if hashInfo['type'] == 2: hashInfo['maxFeePerGas'] = int(hsResult['maxFeePerGas'], 16) hashInfo['maxPriorityFeePerGas'] = int(hsResult['maxPriorityFeePerGas'], 16) return hashInfo except: return False def getLpArrayResAfterTrade(fromAddress, toAddress, inputData, value, lpArray, block = 'latest'): paramsRes = {} paramsRes['to'] = toolsAddress paramsRes['data'] = '0xd94ccee1' + encodeInput(0x20, lpArray) params0 = {} params0['from'] = fromAddress params0['to'] = toAddress params0['data'] = inputData params0['value'] = hex(int(value)) r = batchCall([params0, paramsRes], block) result = r['result'][1]['Return'] result = w3.debug.decodeOutput(result) info = {} length = len(lpArray) for index in range(0, length): lpAddress = lpArray[index] r0 = result[index + 3] r1 = result[index + 4 + length] info[lpAddress] = [r0, r1] return info def calRouterProfit(router): # 整理LP信息 for lpInfo in router: lpAddress = lpInfo['lp'] r0 = nowBlockLpRes[lpAddress][0] r1 = nowBlockLpRes[lpAddress][1] lpInfo['fee'] = topLpInfo[lpAddress]['fee'] if lpInfo['inToken'] < lpInfo['outToken']: lpInfo['rIn'] = r0 lpInfo['rOut'] = r1 else: lpInfo['rIn'] = r1 lpInfo['rOut'] = r0 # ABA if len(router) == 2: tokenLoan = router[1]['outToken'] tokenIn0 = router[0]['inToken'] tokenLoanETHPrice = baseTokenInfo[tokenLoan]['price'] * 10 ** baseTokenInfo[WETH]['decimals'] / 10 ** baseTokenInfo[tokenLoan]['decimals'] # WETH - A - WETH tradeInfo = calBestAmountV2V2(router[0]['rIn'], router[0]['rOut'], router[0]['fee'], router[1]['rIn'], router[1]['rOut'], router[1]['fee'] ) profit = tradeInfo['profit'] tradeInfo['ethProfit'] = profit * tokenLoanETHPrice #printTime(router, amountIn0, amountOut0, amountOut1, profit) if tradeInfo['ethProfit'] < tradeMinProfit: return False else: tradeInfo['lp0'] = router[0]['lp'] tradeInfo['lp1'] = router[1]['lp'] tradeInfo['fee0'] = router[0]['fee'] tradeInfo['fee1'] = router[1]['fee'] tradeInfo['indexIn0'] = router[0]['indexIn'] tradeInfo['indexIn1'] = router[1]['indexIn'] tradeInfo['tokenLoan'] = tokenLoan tradeInfo['tokenIn0'] = tokenIn0 tradeInfo['tradeToken0'] = router[0]['outToken'] tradeInfo['type'] = 'type2' return tradeInfo # ABCA elif len(router) == 3: tokenLoan = router[2]['outToken'] tokenIn0 = router[0]['inToken'] tokenLoanETHPrice = baseTokenInfo[tokenLoan]['price'] * 10 ** baseTokenInfo[WETH]['decimals'] / 10 ** baseTokenInfo[tokenLoan]['decimals'] tradeInfo = calBestAmountABCA(router[0]['rIn'], router[0]['rOut'], router[0]['fee'], router[1]['rIn'], router[1]['rOut'], router[1]['fee'], router[2]['rIn'], router[2]['rOut'], router[2]['fee']) profit = tradeInfo['profit'] tradeInfo['ethProfit'] = profit * tokenLoanETHPrice #printTime(router, amountIn0, amountOut0, amountOut1, amountOut2, profit) if tradeInfo['ethProfit'] < tradeMinProfit: return False else: tradeInfo['lp0'] = router[0]['lp'] tradeInfo['lp1'] = router[1]['lp'] tradeInfo['lp2'] = router[2]['lp'] tradeInfo['fee0'] = router[0]['fee'] tradeInfo['fee1'] = router[1]['fee'] tradeInfo['fee2'] = router[2]['fee'] tradeInfo['indexIn0'] = router[0]['indexIn'] tradeInfo['indexIn1'] = router[1]['indexIn'] tradeInfo['indexIn2'] = router[2]['indexIn'] tradeInfo['tokenLoan'] = tokenLoan tradeInfo['tokenIn0'] = tokenIn0 tradeInfo['tradeToken0'] = router[0]['outToken'] tradeInfo['tradeToken1'] = router[1]['outToken'] tradeInfo['type'] = 'type3' return tradeInfo def getABAInput(lp0, lp1, lp2, tokenIn0, tokenLoan, fee0, fee1, fee2, lp0InIndex, lp1InIndex, lp2InIndex, minProfit): function = '0x5105a538' inputData = encodeInput(lp0, lp1, lp2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, fee0, fee1, fee2, lp0InIndex, lp1InIndex, lp2InIndex, tokenIn0, tokenLoan, minProfit, 0) inputData = function + inputData return inputData def callABAPending(tradeInfo, hashInfo): tradeInputData = getABAInput(tradeInfo['lp0'], tradeInfo['lp1'],tradeInfo['lp2'], tradeInfo['tokenIn0'], tradeInfo['tokenLoan'], tradeInfo['fee0'], tradeInfo['fee1'],tradeInfo['fee2'], tradeInfo['indexIn0'], tradeInfo['indexIn1'],tradeInfo['indexIn2'], baseTokenInfo[tradeInfo['tokenIn0']]['profitMin']) gasCalInputData = '0x4327f0db' + encodeInput(v5Address, 0x40, (len(tradeInputData) - 2)/2 , tradeInputData) paramsTrade = {} paramsTrade['from'] = myAddress paramsTrade['to'] = '0xEAf90BcB75e7B92900678c4aBD80883b414bEDD6' paramsTrade['data'] = gasCalInputData paramsHash = {} paramsHash['from'] = hashInfo['fromAddress'] paramsHash['to'] = hashInfo['toAddress'] paramsHash['data'] = hashInfo['inputData'] paramsHash['value'] = hex(hashInfo['value']) result = batchCall([paramsHash,paramsTrade]) result = result['result'][1]['Return'] info = w3.debug.decodeOutput(result) r = {} r['gasUsed'] = info[1] r['info'] = info[3:] returnInfo = {'type':2, 'lp0': tradeInfo['lp0'], 'lpLoan':tradeInfo['lp1'], 'tokenIn':tradeInfo['tokenIn0'], 'tokenLoan':tradeInfo['tokenLoan'], 'profit':0, 'sumValue':0} if len(r['info']) != 23 or r['info'][-1] == 0: return returnInfo sumValue = r['info'][3] + r['info'][4] + r['info'][5] + r['info'][6] + r['info'][7] + r['info'][8] returnInfo['sumValue'] = sumValue returnInfo['profit'] = r['info'][-1] returnInfo['gasUsed'] = r['gasUsed'] returnInfo['inputData'] = tradeInputData return returnInfo initTime = time.time() pendingInitTime = time.time() topLpInfo = readAny('topLP') lpRouterInfo = readAny('abcd') lpRouter256Info = readAny('256Router') r = w3.provider.make_request('eth_newPendingTransactionFilter',[]) filterId = r['result'] printTime(filterId) nowBlockLpRes = {} dataUsed = [] while True: try: hsArry = w3.provider.make_request('eth_getFilterChanges', [filterId]) hsArry = hsArry['result'] nowBlockLpRes = {} blockNumber = w3.eth.blockNumber baseGasPrice = getBaseGasPrice(blockNumber) * 1.5 if baseGasPrice < 3 * 1e9: baseGasPrice = 3 * 1e9 if hsArry: for hsI in hsArry: tradeInfoArray = [] #printTime('hsI OK') hsResult = w3.new.getTransaction(hsI) #printTime('hsResult OK') hashInfoExp = { 'blockHash': None, 'blockNumber': None, 'from': '0x7a5ddf8a2a924e4faa9d76b97b1363c864062df5', 'gas': '0x5208', 'gasPrice': '0x5968f26e', 'maxFeePerGas': '0x5968f26e', 'maxPriorityFeePerGas': '0x59682f00', 'hash': '0xe5eb2fb4ce91e96501e6ee6423198f3395341bab744cdad7eb2e354ac9fec8ac', 'input': '0x', 'nonce': '0x3', 'to': '0x92be6de0ae6d89a2378795553ecb4cdb820e0d7b', 'transactionIndex': None, 'value': '0x2386f26fc10000', 'type': '0x2', } hashInfo = gethashInfo(hsResult) if not hashInfo: continue if hashInfo['function'] not in swapFunction: continue if hashInfo['gasPrice'] > baseGasPrice * 5 or hashInfo['gasPrice'] > 20 * 1e9: continue #printTime(hsI) traceResult = w3.debug.traceCall(hashInfo['fromAddress'], hashInfo['toAddress'], hashInfo['inputData'], hashInfo['value']) #printTime('traceCall OK') if not traceResult: continue if 'error' in traceResult: continue if 'calls' not in traceResult: continue tradeInfo = w3.debug.transferDecodeFromCalldata(traceResult['calls']) #printTime('transferDecodeFromCalldata OK') if not tradeInfo: continue lpArray = calLpInTradeInfo(tradeInfo) if not lpArray: continue #printTime('calLpInTradeInfo OK', len(lpArray)) lpRouterArray = findLpArrayRouter(lpArray, lpRouter256Info) if not lpRouterArray: continue #printTime('findLpArrayRouter OK', len(lpRouterArray)) onlyLp = calOnlyLpInRouterArray(lpRouterArray) #printTime('calOnlyLpInRouterArray OK', len(onlyLp)) # 获取余额 lpResArray = getLpArrayResAfterTrade(hashInfo['fromAddress'], hashInfo['toAddress'], hashInfo['inputData'], hashInfo['value'], onlyLp) # 余额进行缓存 for lpResI in lpResArray: nowBlockLpRes[lpResI] = lpResArray[lpResI] #printTime('RES OK') #计算每一个路由的利润 for lpRouter in lpRouterArray: tradeInfo = calRouterProfit(lpRouter) if tradeInfo: type = tradeInfo['type'] if type == 'type3': result = callABAPending(tradeInfo, hashInfo) if result['profit'] < tradeMinProfit: continue sumValue = result['sumValue'] if sumValue in dataUsed: continue tokenLoanETHPrice = baseTokenInfo[tradeInfo['tokenLoan']]['price'] * 10 ** baseTokenInfo[WETH]['decimals'] / 10 ** \ baseTokenInfo[tradeInfo['tokenLoan']]['decimals'] result['ethProfit'] = result['profit'] * tokenLoanETHPrice result['ethProfit-E18'] = result['profit'] * tokenLoanETHPrice / 1e18 result['tureProfit'] = result['ethProfit'] - result['gasUsed'] * int(hsResult['gasPrice'],16) result['maxPrice'] = result['ethProfit'] / result['gasUsed'] if result['tureProfit'] < tradeMinProfit: continue tradeInfoArray.append(result) maxProfitInfo = {'tureProfit' : 0} for tradeInfoI in tradeInfoArray: if tradeInfoI['tureProfit'] > maxProfitInfo['tureProfit']: maxProfitInfo = tradeInfoI if maxProfitInfo['tureProfit'] > 0: printTime(maxProfitInfo['lp0'], maxProfitInfo['lpLoan'], maxProfitInfo['tureProfit'] / 1e18, hashInfo['hash']) tradeParams = {} tradeParams['to'] = v5Address tradeParams['data'] = maxProfitInfo['inputData'] tradeParams['gas'] = hex(int(1e6)) tradeParams['value'] = hex(0) tradeParams['type'] = hsResult['type'] if tradeParams['type'] == '0x2': tradeParams['maxFeePerGas'] = hsResult['maxFeePerGas'] tradeParams['maxPriorityFeePerGas'] = hsResult['maxPriorityFeePerGas'] else: tradeParams['gasPrice'] = hsResult['gasPrice'] params = {} params['method'] = 'sendTransaction' params['params'] = tradeParams try: hs = requests.post(url='http://127.0.0.1:410/operation', json=params).text if len(hs)>50: printTime(blockNumber, 'https://www.oklink.com/en/ethw/tx/' + str(hs)) printTime('-' * 50) except: hs = 'err seed' pendingInitTime = time.time() time.sleep(0.0005) except BaseException as err: printTime(traceback.format_exc()) printTime('loop', err) time.sleep(20) try: r = w3.provider.make_request('eth_newPendingTransactionFilter',[]) filterId = r['result'] printTime('filterId',filterId) except: time.sleep(10)