from web3 import Web3, HTTPProvider, WebsocketProvider, IPCProvider import time, datetime, traceback, random, json, requests from web3.middleware import geth_poa_middleware import re import os from web3._utils.module import attach_modules from osTools import * from config import * from sqlTools import * class debug(): def __init__(self): self.decodeCCAddress = '0x0000004885B7FF4bfc4dDB48e921cc25c4c877e1' self.decodeAbi = json.loads(open('abi/decode.json').read()) self.decodeContract = w3.eth.contract(address=self.decodeCCAddress, abi=self.decodeAbi) def traceCall(self, fromAdd, toAdd , data, value = 0 , blockNumber = 'latest'): if type(blockNumber) == int: blockNumber = hex(blockNumber) value = hex(int(value)) try: r = w3.provider.make_request('debug_traceCall', [ { 'from': fromAdd, 'to': toAdd, 'data': data, 'value':value, }, blockNumber, { "tracer": "callTracer", "timeout" : '0.1s' } ]) return r['result'] except BaseException as err: print('trace err', r) return False def traceTransaction(self, hash): try: return w3.provider.make_request('debug_traceTransaction', [hash, { "tracer": "callTracer", "timeout" : '1s' }])['result'] except: return False def functionDecodeFromCallData(self, data): tradeInfo = [] for call in (data): try: #print(call['input']) if 'calls' in call: tradeInfo = tradeInfo + self.functionDecodeFromCallData(call['calls']) inputData = call['input'] function = inputData[0:10] if function == '0x60806040': continue #空input无效 if inputData == '0x': continue callType = call['type'] toAdd = call['to'] #空地址调用无效 if toAdd[:38] == '0x000000000000000000000000000000000000': continue fromAdd = call['from'] functionInput, decodeInput = self.decodeContract.decode_function_input(inputData) outPut = self.decodeOutput(call['output']) print(fromAdd, toAdd, functionInput, decodeInput, outPut) if str(functionInput) == '': #printTime(toAdd, fromAdd, decodeInput['dst'], decodeInput['wad']) tradeInfo.append({ 'token': toAdd.lower(), 'from': fromAdd.lower(), 'to': decodeInput['dst'].lower(), 'amount': decodeInput['wad']}) if str(functionInput) == '': #printTime(toAdd, decodeInput['src'], decodeInput['dst'], decodeInput['wad']) tradeInfo.append({ 'token': toAdd.lower(), 'from': decodeInput['src'].lower(), 'to': decodeInput['dst'].lower(), 'amount': decodeInput['wad']}) #print(functionInput, decodeInput, toAdd, outPut) except: #print('err', inputData, toAdd) continue return tradeInfo def decodeOutput(self, outputData): info = [] outputData = outputData[2:] i = 0 iMax = len(outputData) / 64 while i < iMax: r = outputData[(0 + 64 * i):(64 + 64 * i)] if int(r[:24], 16) == 0 and int(r[24:28], 16) != 0: r = '0x' + r[24:] else : r = int(r, 16) info.append(r) i = i + 1 return info def transferDecodeFromCalldata(self, calldata): tradeInfo = [] for call in (calldata): if 'calls' in call: tradeInfo = tradeInfo + self.transferDecodeFromCalldata(call['calls']) inputData = call['input'] function = inputData[0:10] toAdd = call['to'] fromAdd = call['from'] if 'value' in call: value = int(call['value'],16) if value != 0 : tradeInfo.append({ 'token': '0xethw', 'from': fromAdd.lower(), 'to': toAdd.lower(), 'amount': value}) try: #'' if function == '0x23b872dd': tradeInfo.append({ 'token':toAdd, 'from':'0x' + inputData[34:74], 'to': '0x' + inputData[34 + 64:74+ 64], 'amount':int(inputData[34 + 64 *2 :74+ 64 *2 ],16)}) #'' if function == '0xa9059cbb': tradeInfo.append({ 'token':toAdd, 'from':fromAdd, 'to': '0x' + inputData[34 :74], 'amount':int(inputData[34 + 64 :74+ 64],16)}) except: print('trace err', inputData) return tradeInfo def transferDecodeHashFromLogs(self, hs): r = w3.eth.getTransactionReceipt(hs) tradeInfo = [] for logI in r['logs']: toAdd = logI['address'].lower() data = logI['data'] if len(logI['topics']) == 3 and logI['topics'][0].hex() == '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef': tradeInfo.append({ 'token':toAdd, 'from':'0x' + logI['topics'][1].hex()[26:], 'to': '0x' + logI['topics'][2].hex()[26:], 'amount':int(data,16)}) if len(logI['topics']) == 2 and logI['topics'][ 0].hex() == '0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c': tradeInfo.append({ 'token': '0xeth', 'from': '0x', 'to': '0x' + logI['topics'][1].hex()[26:], 'amount': int(data, 16)}) if len(logI['topics']) == 2 and logI['topics'][ 0].hex() == '0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65': tradeInfo.append({ 'token': '0xeth', 'from': '0x', 'to': '0x' + logI['topics'][1].hex()[26:], 'amount': int(data, 16)}) return tradeInfo def transferDecodeHashFromTrace2(self, data): tradeInfo = [] for call in data: try: if 'calls' in call: tradeInfoi = self.transferDecodeHashFromTrace2(call['calls']) if tradeInfoi: tradeInfo = tradeInfo + tradeInfoi inputData = call['input'] function = inputData[0:10] callType = call['type'] toAdd = call['to'] value = int(call['value'],16) fromAdd = call['from'] if value > 1e9: tradeInfo.append({ 'token': '0xethw', 'from': fromAdd.lower(), 'to': toAdd.lower(), 'amount': value}) continue functionInput, decodeInput = self.decodeContract.decode_function_input(inputData) outPut = self.decodeOutput(call['output']) if str(functionInput) == '': tradeInfo.append({ 'token': toAdd.lower(), 'from': fromAdd.lower(), 'to': decodeInput['dst'].lower(), 'amount': decodeInput['wad']}) if str(functionInput) == '': #print(toAdd, decodeInput['src'], decodeInput['dst'], decodeInput['wad']) tradeInfo.append({ 'token': toAdd.lower(), 'from': decodeInput['src'].lower(), 'to': decodeInput['dst'].lower(), 'amount': decodeInput['wad']}) if str(functionInput) == '': #print(toAdd, decodeInput['src'], decodeInput['dst'], decodeInput['wad']) tradeInfo.append({ 'token': toAdd.lower(), 'from': fromAdd.lower(), 'to': toAdd.lower(), 'amount': decodeInput['wad']}) except: continue return tradeInfo def transferDecodeHashFromTrace(self, hs): try: r = self.traceTransaction(hs) tradeInfo = [] value = int(r['value'], 16) fromAdd = r['from'] toAdd = r['to'] if value > 1e9: tradeInfo.append({ 'token': '0xethw', 'from': fromAdd.lower(), 'to': toAdd.lower(), 'amount': value}) if 'calls' in r: tradeInfo = tradeInfo + self.transferDecodeFromCalldata(r['calls']) return tradeInfo except: return [] class dex(): def __init__(self): toolsddress = '0xDE93d2cd45b7E0056671A542FfB4343DFd67dA51' toolsAbi = json.loads(open('abi/tools.json').read()) self.abi = toolsAbi self.contractAddress = w3.toChecksumAddress(toolsddress) self.contract = w3.eth.contract(address=self.contractAddress, abi=self.abi) def getTokenBalance(self, address, token, block = 'latest'): address = address.replace('0x', '') data = "0x70a08231000000000000000000000000" + address r = web3Call(myAddress, token, data, block) r = int(r, 16) return r def getERC20Info(self, address): address = w3.toChecksumAddress(address) abi = json.loads(open('abi/ERC20.json').read()) contractAddress = w3.toChecksumAddress(address) contract = w3.eth.contract(address=contractAddress, abi=abi) decimals = contract.functions.decimals().call() name = contract.functions.name().call() symbol = contract.functions.symbol().call() try: name = re.sub(r'[^A-Za-z0-9 ]+', '', name) except: name = 'T' + address[2:6] try: symbol = re.sub(r'[^A-Za-z0-9 ]+', '', symbol) except: symbol = 'T' + address[2:6] return {'name': name, 'symbol': symbol, 'decimals': decimals} def getFactory(self, address, block = 'latest'): address = w3.toChecksumAddress(address) info = self.contract.functions.getFactory(address).call(block_identifier = block) return info def getTotalPairV2(self, address, block = 'latest'): address = w3.toChecksumAddress(address) info = self.contract.functions.getTotalPair(address,).call(block_identifier = block) return info def getPairAddSV2(self, factoryAddr, token0, token1, block = 'latest'): addressNew = factoryAddr data = {} inputData = '0x8979b282' + encodeInput(0x60, token0, token1, addressNew) info = web3Call(toolsAddress, toolsAddress, inputData, block) info = w3.debug.decodeOutput(info) for i in range(0, len(addressNew)): fee = topFactoryFee[addressNew[i].lower()] address = info[i + 2] if address == 0: continue data[address] = fee return data def getPairFromIdSInfoV2(self, facrotyAddress, ids, block = 'latest'): facrotyAddress = w3.toChecksumAddress(facrotyAddress) info = self.contract.functions.getPairIdSInfo(facrotyAddress, ids).call(block_identifier = block) return info def getPairSBalance(self, addressNew, block = 'latest'): inputData = '0xd94ccee1' + encodeInput(0x20, addressNew) r = web3Call(myAddress, toolsAddress, inputData, block) r = w3.debug.decodeOutput(r) info = {} length = len(addressNew) for index in range(0, length): lpAddress = addressNew[index] r0 = r[index + 3] r1 = r[index + 4 + length] info[lpAddress] = [r0, r1] return info def getPairAddV3AllFee(self, token0Address , token1Address, block = 'latest'): fee = [100,500,3000,10000] data = {} token0Address = w3.toChecksumAddress(token0Address) token1Address = w3.toChecksumAddress(token1Address) for feeI in fee: try: info = self.contract.functions.getPoolV3(token0Address, token1Address, feeI).call(block_identifier = block) if info != '0x0000000000000000000000000000000000000000': data[info] = feeI except: info = '0x' return data def getPairAddV3(self, token0Address, token1Address, fee, block = 'latest'): token0Address = w3.toChecksumAddress(token0Address) token1Address = w3.toChecksumAddress(token1Address) info = self.contract.functions.getPoolV3(token0Address, token1Address, fee).call(block_identifier = block) return info def getPairInfoFromIdV3(self, ids, block = 'latest'): info = self.contract.functions.getPairInfoV3(ids).call(block_identifier = block) return info def getAmountOutV3(self, tokenIn, tokenOut, fee, amountIn, block = 'latest'): tokenIn = w3.toChecksumAddress(tokenIn) tokenOut = w3.toChecksumAddress(tokenOut) fee = int(fee) amountIn = int(amountIn) try: info = self.contract.functions.getAmountOutV3(tokenIn, tokenOut, fee, amountIn, 0).call(block_identifier = block) except: info = 0 return info def getAmountInV3(self, tokenIn, tokenOut, fee, amountOut, block = 'latest'): tokenIn = w3.toChecksumAddress(tokenIn) tokenOut = w3.toChecksumAddress(tokenOut) fee = int(fee) amountOut = int(amountOut) try: info = self.contract.functions.getAmountOutV3(tokenIn, tokenOut, fee, amountOut, 0).call(block_identifier = block) except: info = 0 return info class new(): def resultManager(self, result): if 'error' in result: raise NameError(result['error']) if 'result' in result: return result['result'] return False def getBlock(self, blockNumber = 'pending', state = False): if blockNumber == 'pending' or blockNumber == 'latest': blockNumber = blockNumber elif type(blockNumber) == str and blockNumber[:2] != '0x': blockNumber = int(blockNumber) elif type(blockNumber) == int: blockNumber = hex(blockNumber) r = w3.provider.make_request('eth_getBlockByNumber', params=[blockNumber, state]) return self.resultManager(r) def getTransaction(self, hash): r = w3.provider.make_request('eth_getTransactionByHash', params=[hash]) return self.resultManager(r) def getTransactionReceipt(self, hash): r = w3.provider.make_request('eth_getTransactionReceipt', params=[hash]) return self.resultManager(r) def blcokNumber(self): r = w3.provider.make_request('eth_blockNumber', params=[]) return int(self.resultManager(r),16) def sendTransaction(self, fromAdd, toAdd, inputData, nonce, gasPrice, gasLimit): params = {} params['from'] = fromAdd params['to'] = toAdd params['data'] = inputData params['nonce'] = hex(int(nonce)) params['gasPrice'] = hex(int(gasPrice)) params['gas'] = hex(int(gasLimit)) params['value'] = hex(0) params['chainId'] = hex(10001) r = w3.provider.make_request('eth_sendTransaction', params=[params]) try: hs = self.resultManager(r) printTime('https://www.oklink.com/en/ethw/tx/' + str(hs)) return str(hs) except BaseException as err: printTime('sendTransaction err', params['from'], params['nonce'], err) return False def getTransactionCount(self, address, blockNumber = "latest"): r = w3.provider.make_request('eth_getTransactionCount', [address, blockNumber]) return self.resultManager(r) def getPendingTxpool(): try: data = json.dumps({ 'jsonrpc': '2.0', 'method': 'txpool_content', 'params': [], 'id': int(time.time() * 1000) }) headers = {'Content-type': 'application/json'} rspnow = requests.post(url, data=data, headers=headers).json() transactionArray = [] for x in rspnow['result']['pending']: addressTransaction = (rspnow['result']['pending'][x]) for addressTransactioni in addressTransaction.values(): transactionArray.append(addressTransactioni) return transactionArray except BaseException as err: print(traceback.format_exc()) print(err) def getBaseGasPrice(blockNumber = 'pending'): try: return int(w3.new.getBlock(blockNumber)['baseFeePerGas'],16) except: return w3.eth.gasPrice def getTokenTradeFromBlock(blockNumber): tokenArray = [] info = w3.eth.getBlock(blockNumber, True) info = (info['transactions']) for hsI in info: try: hsInfo = {} hsInfo['block'] = hsI['blockNumber'] hsInfo['gasUsed'] = hsI['gas'] hsInfo['fromAdd'] = hsI['from'].lower() hsInfo['toAdd'] = str(hsI['to']).lower() hsInfo['input'] = hsI['input'] hsInfo['value'] = hsI['value'] hsInfo['nonce'] = hsI['nonce'] # 对比nonce hsInfo['function'] = hsInfo['input'][:10] hsInfo['hs'] = hsI['hash'].hex() # 创建合约 if hsInfo['gasUsed'] < 90000: continue if hsInfo['function'] == '0x77c46431' or hsInfo['function'] == '0x60806040': continue if hsInfo['input'] == '0x': continue if len(hsInfo['input']) < 76: continue if len(hsInfo['input']) > 64 * 64: continue # opensea if hsInfo['toAdd'] == '0x00000000006c3852cbef3e08e8df289169ede581': continue # X2Y2 if hsInfo['toAdd'] == '0x74312363e45dcaba76c59ec49a7aa8a65a67eed3': continue tradeInfo = w3.debug.transferDecodeHashFromLogs(hsInfo['hs']) #tradeInfo = w3.debug.transferDecodeHashFromTrace(hsInfo['hs']) if tradeInfo: # 进行了token交易或者转载两次 if len(tradeInfo) < 2: continue # 是否来来回交易 tokenAyyay = [] tradeType = False for tradeI in tradeInfo: token = tradeI['token'] fromAdd = tradeI['from'] to = tradeI['to'] if token not in tokenAyyay: tokenAyyay.append(token) for tradeII in tradeInfo: fromAddI = tradeII['from'] toI = tradeII['to'] if fromAdd == toI or to == fromAddI: tradeType = True break if not tradeType: continue # 是否有两个币交易过 if len(tokenAyyay) < 2: continue for tradeI in tradeInfo: token = tradeI['token'] if token == '0xeth': continue if token in tokenArray: continue tokenArray.append(token) except BaseException as err: continue return tokenArray def web3Call(fromAddress, toAddress = None, inputData = None, blockNumber = 'latest'): if type(fromAddress) == dict: input = fromAddress else: input = {'from': fromAddress, 'to':toAddress, 'data':inputData} if type(blockNumber) == int: blockNumber = hex(blockNumber) r = w3.provider.make_request('eth_call', params=[input, blockNumber]) if 'result' in r: return r['result'] else: raise NameError(r) def encodeInput(*array): data = '' for i in array: if type(i) == str: if len(i) > 64: i = i.replace('0x', '') times = int(len(i) / 64 ) + 1 i = i.ljust(64*times, '0') else: i = i.replace('0x', '').rjust(64, '0') data = data + i elif type(i) == int: i = hex((i)).replace('0x', '').rjust(64, '0') data = data + i elif type(i) == float: i = hex(int(i)).replace('0x', '').rjust(64, '0') data = data + i elif type(i) == list: data = data + hex(len(i)).replace('0x', '').rjust(64, '0') for j in i: data = data + encodeInput(j) return data def encodeFunction( string): string = w3.toBytes(text=string) string = w3.sha3(string) string = w3.toHex(string) string = string[:10] return string def batchCall(paramsDataArray ,blockNumber = 'latest'): if blockNumber == 'pending' or blockNumber == 'latest': blockNumber = blockNumber elif type(blockNumber) == str and blockNumber[:2] != '0x': blockNumber = int(blockNumber) elif type(blockNumber) == int: blockNumber = hex(blockNumber) if type(paramsDataArray) != list: paramsDataArray = [paramsDataArray] r = w3.provider.make_request('eth_batchCall', [{"Block": blockNumber, "Calls": paramsDataArray}]) return r def decodeBatchCall(result): info = [] for i in result: if 'Return' in i: info.append(w3.debug.decodeOutput(i['Return'])) return info #url = 'http://3.227.34.41:18545' #w3 = Web3(WebsocketProvider('ws://127.0.0.1:8546')) w3= Web3(IPCProvider('/ethereum_pow_800/data/geth.ipc')) attach_modules(w3, {"debug": (debug,)}) attach_modules(w3, {"dex": (dex,)}) attach_modules(w3, {"new": (new,)}) printTime('Web3:OK', ) printTime('Now Block Number:', w3.eth.blockNumber, 'Now Gas:', getBaseGasPrice())