def estimateGas(web3_ins: Web3, fun_with_args: str, tx_args: Dict, contract_abi: List[Dict], contract_address: str) -> int: c = web3_ins.eth.contract(abi=contract_abi, address=contract_address) f = f"c.functions.{fun_with_args}.estimateGas({tx_args})" try: return eval(f) except: raise finally: logger.info("estimategas_contract_fun:{}".format(f))
def getWhiteTokens(tokens_file: str = "files/white_tokens.json", redownload: bool = False) -> Dict: tmr = timer() next(tmr) logger.info("Loading tokens ...") with open(tokens_file, "a+") as rwop: tokens = {} rwop.seek(0) data = rwop.read() if data and not redownload: tokens = json.loads(data) else: tokens = downloadtokens() rwop.truncate(0) rwop.write(json.dumps(tokens, indent=4)) logger.info(f"white_tokens_num: {len(tokens)} time_use: {next(tmr)}") return tokens
def getAllPairAddress(eth_http:str, pairs_file:str="files/all_pair_address.json", redownload:bool=False, programStatus:ProgramStatus=ProgramStatus()) -> List[str]: tmr = timer() next(tmr) logger.info("Loading all pair address ...") with open(pairs_file, "a+") as rwop: all_pairs_address = [] rwop.seek(0) data = rwop.read() if data and not redownload: all_pairs_address = json.loads(data) else: all_pairs_address = get_allPairAddress(eth_http=eth_http, programStatus=programStatus) rwop.truncate(0) rwop.write(json.dumps(all_pairs_address, indent=4)) logger.info(f"pairs_address_num: {len(all_pairs_address)} time_use: {next(tmr)}") return all_pairs_address
def __init__(self, eth_http: str, pairs: List[Dict], white_tokens: Dict, reserve_min_amount: int, fallback_fun: Callable[[List[Dict]], None]): threading.Thread.__init__(self) self.__lock = threading.Lock() self.__eth_http = eth_http self.__all_pairs = pairs self.__white_tokens = white_tokens self.__reserve_min_amount = reserve_min_amount self.__fallback_fun = fallback_fun self.__timer = timer() self.__white_pairs_change = True next(self.__timer) self.__white_pairs_index, self.__white_pairs_list = Liquidity.__filterPairs( self.__all_pairs, self.__white_tokens) logger.info( f"Liquidity white_pairs_num: {len(self.__white_pairs_list)} time_use: {next(self.__timer)}" )
def __updateReserves(self, web3_ins: Web3, batch_provider_ins: BatchHTTPProvider) -> None: next(self.__timer) get_reserves(web3_ins, batch_provider_ins, self.__white_pairs_list) pairs_len = len(self.__white_pairs_list) num = 0 for i in range(0, pairs_len): num += self.__disablePair(i) self.__saveToFile() logger.info(f"__updateReserves all_pair_num: {pairs_len}") logger.info(f"__updateReserves disable_pair_num: {num}") logger.info(f"__updateReserves enable_pair_num: {pairs_len-num}") logger.info(f"__updateReserves time_use: {next(self.__timer)}")
def main(pairs:List[Dict])->None: pairs = randSelect(pairs, dfsUsePairNum) logger.info(f"pairs num_use: {len(pairs)}") next(tmr) currentPairs = [] path = [tokenIn] bestTrades = [] trades = findArb( pairs=pairs, tokenIn=tokenIn, tokenOut=tokenOut, maxHops=maxHops, currentPairs=currentPairs, path=path, bestTrades=bestTrades, programStatus=programStatus, count=10, ) logger.info(f"dfs time_use: {next(tmr)}") for trade in trades: amountsOut = trade["amountsOut"] # in/out amount_in = amountsOut[0] amount_out = amountsOut[-1] logger.info(f"--- path0: {trade['path'][0]['symbol']} path-1: {trade['path'][-1]['symbol']}") #a = getAmountsOut(web3_ins=web3_ins, amount_in=amount_in, token_address_path=[d["address"] for d in trade["path"]]) # amount out on slide point amount_out_slide_point = int(amount_out*(1-slidePoint)) # min profit profit_slide_point = amount_out_slide_point - amount_in # swapExactTokensForTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) # exactAmountIn, amountOutMin fun_args = { "amountIn":amount_in, "amountOutMin":amount_out_slide_point, "path":[p["address"] for p in trade["path"]], "to": f"'{address_tx_sender}'", "deadline":int(time.time()+100), } fun_with_args = "swapExactTokensForTokensSupportingFeeOnTransferTokens({amountIn}, {amountOutMin}, {path}, {to}, {deadline})".format(**fun_args) tx_args = { "from": address_tx_sender } try: gas = estimateGas( web3_ins=web3_ins, fun_with_args=fun_with_args, tx_args=tx_args, contract_abi=router_abi.abi(), contract_address=address_router_contract) logger.info(f"gasUsed: {gas}") except: logger.error(f"fun estimateGas get exception:{traceback.format_exc()}") return gas_fee = gasPrice*gas logger.info(f"gasFee: {gas_fee/pow(10,18)} Eth") logger.info(f"theoryProfit: {trade['profit']/pow(10,18)} Eth") logger.info(f"profitSlidePoint: {profit_slide_point/pow(10,18)} Eth") profit_fee_on = int(profit_slide_point-gas_fee)/pow(10, startToken['decimal']) tag = "Insufficient" if profit_fee_on >= minProfit: tag = "Satisfy" logger.info(json.dumps(trade, cls=JsonCustomEncoder)) logger.info(f"---- {tag} ProfitFeeOn ----: {profit_fee_on} Eth") break
if __name__ == "__main__": usage = "usage: python3 main.py [options] arg" parser = OptionParser(usage=usage,description="command descibe") parser.add_option("--redownload_tokens", action='store_true', dest="redownload_tokens", default=False, help="redownload tokens") parser.add_option("--redownload_pairs_address", action='store_true', dest="redownload_pairs_address", default=False, help="redownload pairs address") parser.add_option("--redownload_pairs_info", action='store_true', dest="redownload_pairs_info", default=False, help="redownload pairs info") (options, args) = parser.parse_args() white_tokens = getWhiteTokens(redownload=options.redownload_tokens) all_pair_info = getAllPairInfo( eth_http=ethereum_http, redownload_pairinfo=options.redownload_pairs_info, redownload_pairaddress=options.redownload_pairs_address, programStatus=programStatus, ) t = Liquidity( eth_http=ethereum_http, pairs=all_pair_info, white_tokens=white_tokens, reserve_min_amount=reserveMinAmount, fallback_fun=main, ) t.start() t.join() logger.info("---- exit ----")
def run(self): sync_topic = pair_abi.topic("Sync") while programStatus.running(): try: web3_ins = Web3(Web3.HTTPProvider(self.__eth_http)) batch_provider = BatchHTTPProvider(self.__eth_http) # update event from latest block latest_block = web3_ins.eth.getBlock("latest") logger.info(f"latest_block: {latest_block.number}") with self.__lock: self.__updateReserves(web3_ins, batch_provider) attached_pair_contract = web3_ins.eth.contract( abi=pair_abi.abi()) event_filter = attached_pair_contract.events.Sync( ).createFilter(fromBlock=latest_block.number, toBlock="latest", topics=[sync_topic]) block_filter = web3_ins.eth.filter("latest") # all events for latest block events = event_filter.get_all_entries() if events: with self.__lock: blk_events_count = {} for event in events: self.__dealEvent(event, blk_events_count) logger.info( f"Block liquidity_update_num(keys:{len(blk_events_count.keys())}): {json.dumps(blk_events_count)}" ) while programStatus.running(): blocks = block_filter.get_new_entries() events = event_filter.get_new_entries() if events: with self.__lock: blk_events_count = {} for event in events: self.__dealEvent(event, blk_events_count) logger.info( f"Block liquidity_update_num(keys:{len(blk_events_count.keys())}): {json.dumps(blk_events_count)}" ) if not blocks: self.__saveToFile() continue logger.info(f"new blocks: {[b.hex() for b in blocks]}") with self.__lock: # deepcopy self.__white_pairs_list x = [] for d in self.__white_pairs_list: if not d["enable"]: continue x1 = {} for k, v in d.items(): v1 = v if type(v) == dict: v1 = {tk: tv for tk, tv in v.items()} x1.update({k: v1}) x.append(x1) try: self.__fallback_fun(x) except: logger.error( f"exec __fallback_fun(x) get exception:{traceback.format_exc()}" ) except: logger.error( f"exec Liquidity get exception:{traceback.format_exc()}") logger.warning("reconnect ...") time.sleep(3)