From 06b4f02210a11ee7e9c81d4dea50bd3f5f205f0e Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 4 May 2024 22:36:38 +0300 Subject: [PATCH 001/131] Fix the `last_updated_block` key error --- fastlane_bot/events/async_event_update_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane_bot/events/async_event_update_utils.py b/fastlane_bot/events/async_event_update_utils.py index 831b704d8..c31f33f68 100644 --- a/fastlane_bot/events/async_event_update_utils.py +++ b/fastlane_bot/events/async_event_update_utils.py @@ -213,7 +213,7 @@ def _get_new_pool_data( for pool in mgr.pool_data: all_keys.update(pool.keys()) if "last_updated_block" not in all_keys: - all_keys.update("last_updated_block") + all_keys.update(["last_updated_block"]) pool_data_keys: frozenset = frozenset(all_keys) new_pool_data: List[Dict] = [] for idx, pool in tokens_and_fee_df.iterrows(): From f5446afc22ba20baaba04fdb1915ad330aa1eae3 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Thu, 2 May 2024 18:26:44 +0300 Subject: [PATCH 002/131] Clean up some code related to `mgr.pool_data` --- fastlane_bot/events/utils.py | 53 ------------------------------------ main.py | 17 +++++------- 2 files changed, 7 insertions(+), 63 deletions(-) diff --git a/fastlane_bot/events/utils.py b/fastlane_bot/events/utils.py index 468ac82cd..283c3e0f7 100644 --- a/fastlane_bot/events/utils.py +++ b/fastlane_bot/events/utils.py @@ -1059,36 +1059,6 @@ def handle_subsequent_iterations( ) -def verify_state_changed(bot: CarbonBot, initial_state: List[Dict[str, Any]], mgr: Any): - """ - Verifies that the state has changed. - - Parameters - ---------- - bot : CarbonBot - The bot object. - initial_state : Dict[str, Any] - The initial state. - mgr : Any - The manager object. - - """ - # Compare the initial state to the final state, and update the state if it has changed - final_state = mgr.pool_data.copy() - final_state_bancor_pol = [ - final_state[i] - for i in range(len(final_state)) - if final_state[i]["exchange_name"] == mgr.cfg.BANCOR_POL_NAME - ] - # assert bot.db.state == final_state, "\n *** bot failed to update state *** \n" - if initial_state != final_state_bancor_pol: - mgr.cfg.logger.debug("[events.utils.verify_state_changed] State has changed...") - else: - mgr.cfg.logger.warning( - "[events.utils.verify_state_changed] State has not changed... This may indicate an error" - ) - - def handle_duplicates(mgr: Any): """ Handles the duplicates in the pool data. @@ -1105,29 +1075,6 @@ def handle_duplicates(mgr: Any): assert len(cids) == len(set(cids)), "duplicate cid's exist in the pool data" -def get_pools_for_exchange(exchange: str, mgr: Any) -> [Any]: - """ - Handles the initial iteration of the bot. - - Parameters - ---------- - mgr : Any - The manager object. - exchange : str - The exchange for which to get pools - - Returns - ------- - List[Any] - A list of pools for the specified exchange. - """ - return [ - idx - for idx, pool in enumerate(mgr.pool_data) - if pool["exchange_name"] == exchange - ] - - def handle_initial_iteration( backdate_pools: bool, current_block: int, diff --git a/main.py b/main.py index 42410df32..000692c20 100644 --- a/main.py +++ b/main.py @@ -42,7 +42,6 @@ init_bot, get_cached_events, handle_subsequent_iterations, - verify_state_changed, handle_duplicates, get_latest_events, get_start_block, @@ -310,17 +309,10 @@ def run(mgr, args, tenderly_uri=None) -> None: handle_static_pools_update(mgr) while True: try: - # Save initial state of pool data to assert whether it has changed - initial_state = mgr.pool_data.copy() - # ensure 'last_updated_block' is in pool_data for all pools - for idx, pool in enumerate(mgr.pool_data): + for pool in mgr.pool_data: if "last_updated_block" not in pool: pool["last_updated_block"] = last_block_queried - mgr.pool_data[idx] = pool - if not pool["last_updated_block"]: - pool["last_updated_block"] = last_block_queried - mgr.pool_data[idx] = pool # Get current block number, then adjust to the block number reorg_delay blocks ago to avoid reorgs start_block, replay_from_block = get_start_block( @@ -427,7 +419,12 @@ def run(mgr, args, tenderly_uri=None) -> None: bot = init_bot(mgr) # Verify that the state has changed - verify_state_changed(bot=bot, initial_state=initial_state, mgr=mgr) + if any(pool["exchange_name"] != mgr.cfg.BANCOR_POL_NAME for pool in mgr.pool_data): + mgr.cfg.logger.debug("[main] State has changed") + else: + mgr.cfg.logger.warning( + "[main] State has not changed, this may indicate an error" + ) # Verify that the minimum profit in BNT is respected verify_min_bnt_is_respected(bot=bot, mgr=mgr) From 09911ca2911490c9ed34a9742d951640fb3079f4 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Thu, 2 May 2024 18:41:35 +0300 Subject: [PATCH 003/131] Cosmetic --- main.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/main.py b/main.py index 000692c20..38c4bbc5d 100644 --- a/main.py +++ b/main.py @@ -422,9 +422,7 @@ def run(mgr, args, tenderly_uri=None) -> None: if any(pool["exchange_name"] != mgr.cfg.BANCOR_POL_NAME for pool in mgr.pool_data): mgr.cfg.logger.debug("[main] State has changed") else: - mgr.cfg.logger.warning( - "[main] State has not changed, this may indicate an error" - ) + mgr.cfg.logger.warning("[main] State has not changed, this may indicate an error") # Verify that the minimum profit in BNT is respected verify_min_bnt_is_respected(bot=bot, mgr=mgr) From a986cfc69de8ac061e5b751faba2bd30c3d8544d Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Thu, 2 May 2024 18:44:39 +0300 Subject: [PATCH 004/131] Remove unneeded checks --- fastlane_bot/events/utils.py | 22 ---------------------- main.py | 10 ---------- 2 files changed, 32 deletions(-) diff --git a/fastlane_bot/events/utils.py b/fastlane_bot/events/utils.py index 283c3e0f7..8f2e66618 100644 --- a/fastlane_bot/events/utils.py +++ b/fastlane_bot/events/utils.py @@ -1679,28 +1679,6 @@ def delete_tenderly_forks(forks_to_cleanup: List[str], mgr: Any) -> List[str]: return forks_to_keep -def verify_min_bnt_is_respected(bot: CarbonBot, mgr: Any): - """ - Verifies that the bot respects the min profit. Used for testing. - - Parameters - ---------- - bot : CarbonBot - The bot object. - mgr : Any - The manager object. - - """ - # Verify MIN_PROFIT_BNT is set and respected - assert ( - bot.ConfigObj.DEFAULT_MIN_PROFIT_GAS_TOKEN - == mgr.cfg.DEFAULT_MIN_PROFIT_GAS_TOKEN - ), "bot failed to update min profit" - mgr.cfg.logger.debug( - "[events.utils.verify_min_bnt_is_respected] Bot successfully updated min profit" - ) - - def handle_target_token_addresses(static_pool_data: pd.DataFrame, target_tokens: List): """ Get the addresses of the target tokens. diff --git a/main.py b/main.py index 38c4bbc5d..6e90eb421 100644 --- a/main.py +++ b/main.py @@ -47,7 +47,6 @@ get_start_block, set_network_to_mainnet_if_replay, set_network_to_tenderly_if_replay, - verify_min_bnt_is_respected, handle_target_token_addresses, get_current_block, handle_tenderly_event_exchanges, @@ -418,15 +417,6 @@ def run(mgr, args, tenderly_uri=None) -> None: # Re-initialize the bot bot = init_bot(mgr) - # Verify that the state has changed - if any(pool["exchange_name"] != mgr.cfg.BANCOR_POL_NAME for pool in mgr.pool_data): - mgr.cfg.logger.debug("[main] State has changed") - else: - mgr.cfg.logger.warning("[main] State has not changed, this may indicate an error") - - # Verify that the minimum profit in BNT is respected - verify_min_bnt_is_respected(bot=bot, mgr=mgr) - if args.use_specific_exchange_for_target_tokens is not None: target_tokens = bot.get_tokens_in_exchange( exchange_name=args.use_specific_exchange_for_target_tokens From 02a5b54a5b6d937c35563207e621e077ff72c3a4 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Mon, 6 May 2024 06:57:21 +0300 Subject: [PATCH 005/131] Fix function `async_update_pools_from_contracts` --- fastlane_bot/events/async_event_update_utils.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/fastlane_bot/events/async_event_update_utils.py b/fastlane_bot/events/async_event_update_utils.py index c31f33f68..19a898eb5 100644 --- a/fastlane_bot/events/async_event_update_utils.py +++ b/fastlane_bot/events/async_event_update_utils.py @@ -212,8 +212,6 @@ def _get_new_pool_data( all_keys = set() for pool in mgr.pool_data: all_keys.update(pool.keys()) - if "last_updated_block" not in all_keys: - all_keys.update(["last_updated_block"]) pool_data_keys: frozenset = frozenset(all_keys) new_pool_data: List[Dict] = [] for idx, pool in tokens_and_fee_df.iterrows(): @@ -394,6 +392,10 @@ def async_update_pools_from_contracts(mgr: Any, current_block: int): mgr, current_block, tokens_and_fee_df, tokens_df ) + if len(new_pool_data) == 0: + mgr.cfg.logger.info("No pools found in contracts") + return + new_pool_data_df = pd.DataFrame(new_pool_data).sort_values( "last_updated_block", ascending=False ) @@ -410,6 +412,10 @@ def async_update_pools_from_contracts(mgr: Any, current_block: int): ] ) + if new_pool_data_df.empty: + mgr.cfg.logger.info("No valid pools found in contracts") + return + new_pool_data_df["descr"] = ( new_pool_data_df["exchange_name"] + " " From bd3c2106cd5fdc7d6a5516559745f772b38a2016 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Mon, 6 May 2024 07:08:06 +0300 Subject: [PATCH 006/131] Remove unused exception `AsyncUpdateRetryException` and all related code --- fastlane_bot/exceptions.py | 7 --- fastlane_bot/tests/test_068_exceptions.py | 54 ----------------------- main.py | 25 +---------- 3 files changed, 2 insertions(+), 84 deletions(-) delete mode 100644 fastlane_bot/tests/test_068_exceptions.py diff --git a/fastlane_bot/exceptions.py b/fastlane_bot/exceptions.py index ab225a2a2..11b84a8eb 100644 --- a/fastlane_bot/exceptions.py +++ b/fastlane_bot/exceptions.py @@ -19,13 +19,6 @@ def __str__(self): f"create this file.") -class AsyncUpdateRetryException(Exception): - """ - Exception raised when async_update_pools_from_contracts fails and needs to be retried. - """ - pass - - class FlashloanUnavailableException(Exception): """ Exception raised when not configured to use self_fund on a blockchain that does not support Flashloans. diff --git a/fastlane_bot/tests/test_068_exceptions.py b/fastlane_bot/tests/test_068_exceptions.py deleted file mode 100644 index 8316197f7..000000000 --- a/fastlane_bot/tests/test_068_exceptions.py +++ /dev/null @@ -1,54 +0,0 @@ -# ------------------------------------------------------------ -# Auto generated test file `test_068_exceptions.py` -# ------------------------------------------------------------ -# source file = NBTest_068_exceptions.py -# test id = 068 -# test comment = exceptions -# ------------------------------------------------------------ - - -import pytest - -from fastlane_bot.exceptions import AsyncUpdateRetryException - - -@pytest.mark.parametrize( - "message, id", - [ - ("Failed to update, retrying...", 'happy-1'), - ("Update failed at step 3, retrying...", 'happy-2'), - ("Temporary network issue, attempt retry...", 'happy-3'), - ], -) -def test_aync_update_retry_exception_with_message(message, id): - # Act - exception = AsyncUpdateRetryException(message) - - # Assert - assert str(exception) == message, f"Test case {id} failed: The exception message does not match the expected message." - -@pytest.mark.parametrize( - "message, id", - [ - ("", 'edge-1'), - ], -) -def test_aync_update_retry_exception_with_empty_message(message, id): - # Act - exception = AsyncUpdateRetryException(message) - - # Assert - assert str(exception) == message, f"Test case {id} failed: The exception message should be empty." - -@pytest.mark.parametrize( - "message, id", - [ - ('happy-1', 'happy-1'), - (None, 'happy-2'), - ('3', 'happy-3'), - ], -) -def test_aync_update_retry_exception_raises(message, id): - # Act & Assert - with pytest.raises(AsyncUpdateRetryException, match=message): - raise AsyncUpdateRetryException(message) \ No newline at end of file diff --git a/main.py b/main.py index 6e90eb421..cb61544f2 100644 --- a/main.py +++ b/main.py @@ -6,7 +6,7 @@ Licensed under MIT """ -from fastlane_bot.exceptions import AsyncUpdateRetryException, ReadOnlyException, FlashloanUnavailableException +from fastlane_bot.exceptions import ReadOnlyException, FlashloanUnavailableException from fastlane_bot.events.version_utils import check_version_requirements from fastlane_bot.tools.cpc import T @@ -370,7 +370,7 @@ def run(mgr, args, tenderly_uri=None) -> None: f"Adding {len(mgr.pools_to_add_from_contracts)} new pools from contracts, " f"{len(mgr.pool_data)} total pools currently exist. Current block: {current_block}." ) - _run_async_update_with_retries(mgr, current_block=current_block) + async_update_pools_from_contracts(mgr, current_block=current_block) mgr.pools_to_add_from_contracts = [] # Increment the loop index @@ -538,27 +538,6 @@ def run(mgr, args, tenderly_uri=None) -> None: break -def _run_async_update_with_retries(mgr, current_block, max_retries=5): - failed_async_calls = 0 - - while failed_async_calls < max_retries: - try: - async_update_pools_from_contracts(mgr, current_block) - return # Successful execution - except AsyncUpdateRetryException as e: - failed_async_calls += 1 - mgr.cfg.logger.error(f"Attempt {failed_async_calls} failed: {e}") - mgr.update_remaining_pools() - - # Handling failure after retries - mgr.cfg.logger.error( - f"[main run.py] async_update_pools_from_contracts failed after " - f"{len(mgr.pools_to_add_from_contracts)} attempts. List of failed pools: {mgr.pools_to_add_from_contracts}" - ) - - raise AsyncUpdateRetryException("[main.py] async_update_pools_from_contracts failed after maximum retries.") - - if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument( From 1847eb78e86f5c910a3728b74813d577f60c686b Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Mon, 6 May 2024 07:14:58 +0300 Subject: [PATCH 007/131] Remove unused function `update_remaining_pools` --- fastlane_bot/events/managers/manager.py | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/fastlane_bot/events/managers/manager.py b/fastlane_bot/events/managers/manager.py index cf98a614e..998356c53 100644 --- a/fastlane_bot/events/managers/manager.py +++ b/fastlane_bot/events/managers/manager.py @@ -244,23 +244,3 @@ def handle_trading_fee_updated(self): pool["fee_float"] = pool["fee"] / 1e6 pool["descr"] = self.pool_descr_from_info(pool) self.pool_data[idx] = pool - - - def update_remaining_pools(self): - remaining_pools = [] - all_events = [pool[2] for pool in self.pools_to_add_from_contracts] - for event in all_events: - addr = self.web3.to_checksum_address(event["address"]) - ex_name = self.exchange_name_from_event(event) - if not ex_name: - self.cfg.logger.warning("[update_remaining_pools] ex_name not found from event") - continue - - key, key_value = self.get_key_and_value(event, addr, ex_name) - pool_info = self.get_pool_info(key, key_value, ex_name) - - if not pool_info: - remaining_pools.append((addr, ex_name, event, key, key_value)) - - random.shuffle(remaining_pools) - self.pools_to_add_from_contracts = remaining_pools From d35ac20a9189f4f54542a5397443675a7ba639bc Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 4 May 2024 00:04:19 +0300 Subject: [PATCH 008/131] Filter out erronous trade instructions --- fastlane_bot/bot.py | 33 ++++++---------------------- fastlane_bot/helpers/routehandler.py | 7 +----- 2 files changed, 8 insertions(+), 32 deletions(-) diff --git a/fastlane_bot/bot.py b/fastlane_bot/bot.py index 0a153d6c9..9d9f347da 100644 --- a/fastlane_bot/bot.py +++ b/fastlane_bot/bot.py @@ -241,36 +241,17 @@ def _convert_trade_instructions( List[Dict[str, Any]] The trade instructions. """ - errorless_trade_instructions_dicts = [ - {k: v for k, v in trade_instructions_dic[i].items() if k != "error"} - for i in range(len(trade_instructions_dic)) - ] - result = ( - { - **ti, + return [ + TradeInstruction(**{ + **{k: v for k, v in ti.items() if k != "error"}, "raw_txs": "[]", "pair_sorting": "", "ConfigObj": self.ConfigObj, "db": self.db, - } - for ti in errorless_trade_instructions_dicts - if ti is not None - ) - result = self._add_strategy_id_to_trade_instructions_dic(result) - result = [TradeInstruction(**ti) for ti in result] - return result - - def _add_strategy_id_to_trade_instructions_dic( - self, trade_instructions_dic: Generator - ) -> List[Dict[str, Any]]: - lst = [] - for ti in trade_instructions_dic: - cid = ti["cid"].split('-')[0] - ti["strategy_id"] = self.db.get_pool( - cid=cid - ).strategy_id - lst.append(ti) - return lst + "strategy_id": self.db.get_pool(cid=ti["cid"].split('-')[0]).strategy_id + }) + for ti in trade_instructions_dic if ti["error"] is None + ] def _get_deadline(self, block_number) -> int: """ diff --git a/fastlane_bot/helpers/routehandler.py b/fastlane_bot/helpers/routehandler.py index 7bfca0d1a..f42a52562 100644 --- a/fastlane_bot/helpers/routehandler.py +++ b/fastlane_bot/helpers/routehandler.py @@ -109,14 +109,9 @@ class TxRouteHandler: trade_instructions: List[TradeInstruction] def __post_init__(self): - self.contains_carbon = True - self.ConfigObj = self.trade_instructions[0].ConfigObj - if not self.trade_instructions: - raise ValueError("No trade instructions found.") if len(self.trade_instructions) < 2: raise ValueError("Length of trade instructions must be greater than 1.") - if sum([1 if self.trade_instructions[i]._is_carbon else 0 for i in range(len(self.trade_instructions))]) == 0: - self.contains_carbon = False + self.ConfigObj = self.trade_instructions[0].ConfigObj @staticmethod def custom_data_encoder( From da1260f6bde5ff9ae2cbf3945c854034eef20d39 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 4 May 2024 08:40:14 +0300 Subject: [PATCH 009/131] Clean up routerhandler.py --- fastlane_bot/helpers/routehandler.py | 67 +++++--------- .../tests/test_051_BalancerFlashloans.py | 89 +------------------ 2 files changed, 25 insertions(+), 131 deletions(-) diff --git a/fastlane_bot/helpers/routehandler.py b/fastlane_bot/helpers/routehandler.py index f42a52562..260910289 100644 --- a/fastlane_bot/helpers/routehandler.py +++ b/fastlane_bot/helpers/routehandler.py @@ -317,54 +317,31 @@ def generate_flashloan_struct(self, trade_instructions_objects: List[TradeInstru :return: list """ - return self._get_flashloan_struct(trade_instructions_objects=trade_instructions_objects) - - def _get_flashloan_platform_id(self, tkn: str) -> int: - """ - Returns the platform ID to take the flashloan from - :param tkn: str - - :return: - int - """ - - if self.ConfigObj.NETWORK not in ["ethereum", "tenderly"]: - return 7 - - # Using Bancor V3 to flashloan BNT, ETH, WBTC, LINK, USDC, USDT - if tkn in [self.ConfigObj.BNT_ADDRESS, self.ConfigObj.ETH_ADDRESS, self.ConfigObj.WBTC_ADDRESS, - self.ConfigObj.LINK_ADDRESS, self.ConfigObj.BNT_ADDRESS, self.ConfigObj.ETH_ADDRESS, - self.ConfigObj.WBTC_ADDRESS, self.ConfigObj.LINK_ADDRESS]: - return 2 + is_FL_NATIVE_permitted = self.ConfigObj.NETWORK == self.ConfigObj.NETWORK_ETHEREUM + + if trade_instructions_objects[0].tknin_is_native and not is_FL_NATIVE_permitted: + source_token = self.ConfigObj.WRAPPED_GAS_TOKEN_ADDRESS + elif trade_instructions_objects[0].tknin_is_native and is_FL_NATIVE_permitted: + source_token = self.ConfigObj.NATIVE_GAS_TOKEN_ADDRESS + elif trade_instructions_objects[0].tknin_is_wrapped: + source_token = self.ConfigObj.WRAPPED_GAS_TOKEN_ADDRESS else: - return 7 + source_token = trade_instructions_objects[0].tknin_address - def _get_flashloan_struct(self, trade_instructions_objects: List[TradeInstruction]) -> list: - """ - Turns an object containing trade instructions into a struct with flashloan tokens and amounts ready to send to the smart contract. - :param flash_tokens: an object containing flashloan tokens in the format {tkn: {"tkn": tkn_address, "flash_amt": tkn_amt}} - """ - flash_tokens = self._extract_single_flashloan_token(trade_instructions=trade_instructions_objects) - flashloans = [] - balancer = {"platformId": 7, "sourceTokens": [], "sourceAmounts": []} - has_balancer = False - - for tkn in flash_tokens.keys(): - platform_id = self._get_flashloan_platform_id(tkn) - source_token = flash_tokens[tkn]["tkn"] - source_amounts = abs(flash_tokens[tkn]["flash_amt"]) - if platform_id == 7: - has_balancer = True - balancer["sourceTokens"].append(source_token) - balancer["sourceAmounts"].append(source_amounts) - else: - source_token = self.wrapped_gas_token_to_native(source_token) - flashloans.append( - {"platformId": platform_id, "sourceTokens": [source_token], "sourceAmounts": [source_amounts]}) - if has_balancer: - flashloans.append(balancer) + platformId = 2 if self.ConfigObj.NETWORK in ["ethereum", "tenderly"] and source_token in [ + self.ConfigObj.BNT_ADDRESS, + self.ConfigObj.ETH_ADDRESS, + self.ConfigObj.WBTC_ADDRESS, + self.ConfigObj.LINK_ADDRESS + ] else 7 - return flashloans + return [ + { + "platformId": platformId, + "sourceTokens": [self.wrapped_gas_token_to_native(source_token)], + "sourceAmounts": [abs(trade_instructions_objects[0].amtin_wei)] + } + ] def native_gas_token_to_wrapped(self, tkn: str): """ diff --git a/fastlane_bot/tests/test_051_BalancerFlashloans.py b/fastlane_bot/tests/test_051_BalancerFlashloans.py index 9449bc1d1..ff066fc12 100644 --- a/fastlane_bot/tests/test_051_BalancerFlashloans.py +++ b/fastlane_bot/tests/test_051_BalancerFlashloans.py @@ -264,95 +264,12 @@ def test_test_extract_flashloan_tokens(): exchange_override = 'carbon_v1' ) - ti9 = TradeInstruction( - cid='4083388403051261561560495289181218537544', - tknin='0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', - amtin=5, - tknout='0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - amtout=10000, - ConfigObj=cfg, - db = db, - tknin_dec_override = 18, - tknout_dec_override = 6, - tknin_addr_override = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', - tknout_addr_override = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - exchange_override = 'bancor_v3' - ) - - ti10 = TradeInstruction( - cid='4083388403051261561560495289181218537544', - tknin='0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - amtin=10000, - tknout='0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', - amtout=5.7, - ConfigObj=cfg, - db = db, - tknout_dec_override = 6, - tknin_dec_override = 18, - tknout_addr_override = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', - tknin_addr_override = '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', - exchange_override = 'carbon_v1' - ) - - ti11 = TradeInstruction( - cid='4083388403051261561560495289181218537544', - tknin='0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C', - amtin=50000, - tknout='0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - amtout=20000, - ConfigObj=cfg, - db = db, - tknin_dec_override = 18, - tknout_dec_override = 6, - tknin_addr_override = '0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C', - tknout_addr_override = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - exchange_override = 'bancor_v3' - ) - - ti12 = TradeInstruction( - cid='4083388403051261561560495289181218537544', - tknin='0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - amtin=20000, - tknout='0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C', - amtout=50115, - ConfigObj=cfg, - db = db, - tknout_dec_override = 6, - tknin_dec_override = 18, - tknout_addr_override = '0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C', - tknin_addr_override = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - exchange_override = 'carbon_v1' - ) instructions = [ti1, ti2] instructions2 = [ti3, ti4, ti5, ti6, ti7, ti8] - instructions3 = [ti3, ti4, ti5, ti6, ti7, ti8, ti9, ti10, ti11, ti12] route_handler = TxRouteHandler(instructions) - route_handler2 = TxRouteHandler(instructions2) - route_handler3 = TxRouteHandler(instructions3) - - - flashloan_tokens = route_handler._extract_flashloan_tokens(instructions) - flashloan_tokens2 = route_handler._extract_flashloan_tokens(instructions2) - flashloan_tokens3 = route_handler._extract_flashloan_tokens(instructions3) - + flashloan_tokens = route_handler._extract_flashloan_tokens(instructions2) - flashloan_struct = route_handler._get_flashloan_struct(instructions2) - flashloan_struct2 = route_handler._get_flashloan_struct(instructions3) - - - flash_struct3 = route_handler.generate_flashloan_struct(instructions3) - assert len(flashloan_tokens2.keys()) == 2 - assert flashloan_tokens2['0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48']["flash_amt"] == 5000000000, f"expected flashloan amount of 5000000000, found {flashloan_tokens2['0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48']['flash_amt']}" - #assert flashloan_tokens2['0xdAC17F958D2ee523a2206206994597C13D831ec7']["flash_amt"] == 2000000000, f"expected flashloan amount of 2000000000, found {flashloan_tokens2['0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48']['flash_amt']}" - # assert len(flash_struct3) == 3, f"[Advanced Routing NBTest044] wrong number of flash tokens length, expected 3, got {len(flash_struct3)}" - # assert flash_struct3[0]['platformId'] == 2, f"[Balancer Flashloan Support [NBTest049]] wrong platformId, expected 2, got {flash_struct3[0]['platformId']}" - # assert flash_struct3[1]['platformId'] == 2, f"[Balancer Flashloan Support [NBTest049]] wrong platformId, expected 2, got {flash_struct3[1]['platformId']}" - # assert flash_struct3[2]['platformId'] == 7, f"[Balancer Flashloan Support [NBTest049]] wrong platformId, expected 7, got {flash_struct3[2]['platformId']}" - - # for flashloan in flash_struct3: - # assert len(flashloan['sourceTokens']) == len(flashloan['sourceAmounts']), f"[Balancer Flashloan Support [NBTest049]] number of source tokens does not match source amounts, tkns: {len(flashloan['sourceTokens'])} amts: {len(flashloan['sourceAmounts'])}" + assert len(flashloan_tokens.keys()) == 2 + assert flashloan_tokens['0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48']["flash_amt"] == 5000000000, f"expected flashloan amount of 5000000000, found {flashloan_tokens2['0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48']['flash_amt']}" # - - - - \ No newline at end of file From f21a4acf8d6cecf3e41cf07abfeff9fc5f704bda Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 4 May 2024 08:56:17 +0300 Subject: [PATCH 010/131] Cleanup routerhandler.py --- fastlane_bot/helpers/routehandler.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fastlane_bot/helpers/routehandler.py b/fastlane_bot/helpers/routehandler.py index 260910289..b6ce13c3a 100644 --- a/fastlane_bot/helpers/routehandler.py +++ b/fastlane_bot/helpers/routehandler.py @@ -17,7 +17,6 @@ __DATE__ = "02/May/2023" import decimal -import math from _decimal import Decimal from dataclasses import dataclass from typing import List, Any, Dict, Tuple @@ -793,10 +792,10 @@ def _swap_token0_in( """ amount_in = amount_in * (Decimal(str(1)) - fee) - price_next = Decimal(str(math.floor(( - int(liquidity * self.ConfigObj.Q96 * sqrt_price) - / int(liquidity * self.ConfigObj.Q96 + amount_in * decimal_tkn0_modifier * sqrt_price))) - )) + price_next = Decimal( + int(liquidity * self.ConfigObj.Q96 * sqrt_price) + // int(liquidity * self.ConfigObj.Q96 + amount_in * decimal_tkn0_modifier * sqrt_price) + ) amount_out = self._calc_amount1(liquidity, sqrt_price, price_next) / self.ConfigObj.Q96 return Decimal(amount_out / decimal_tkn1_modifier) From 701801daed576f1f16372d36735e52c7fee7e16e Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 4 May 2024 10:02:46 +0300 Subject: [PATCH 011/131] Minor --- fastlane_bot/helpers/routehandler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane_bot/helpers/routehandler.py b/fastlane_bot/helpers/routehandler.py index b6ce13c3a..52fe0908a 100644 --- a/fastlane_bot/helpers/routehandler.py +++ b/fastlane_bot/helpers/routehandler.py @@ -308,7 +308,7 @@ def get_custom_address( else: return pool.tkn0_address - def generate_flashloan_struct(self, trade_instructions_objects: List[TradeInstruction]) -> list: + def generate_flashloan_struct(self, trade_instructions_objects: List[TradeInstruction]) -> List[Dict]: """ Generates the flashloan struct for submitting FlashLoanAndArbV2 transactions :param trade_instructions_objects: a list of TradeInstruction objects From 98648c656f857bb573e966d865f62e6fff3fe9c0 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 4 May 2024 10:06:34 +0300 Subject: [PATCH 012/131] Fix test 051 --- fastlane_bot/tests/test_051_BalancerFlashloans.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane_bot/tests/test_051_BalancerFlashloans.py b/fastlane_bot/tests/test_051_BalancerFlashloans.py index ff066fc12..9fff5bd3f 100644 --- a/fastlane_bot/tests/test_051_BalancerFlashloans.py +++ b/fastlane_bot/tests/test_051_BalancerFlashloans.py @@ -271,5 +271,5 @@ def test_test_extract_flashloan_tokens(): flashloan_tokens = route_handler._extract_flashloan_tokens(instructions2) assert len(flashloan_tokens.keys()) == 2 - assert flashloan_tokens['0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48']["flash_amt"] == 5000000000, f"expected flashloan amount of 5000000000, found {flashloan_tokens2['0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48']['flash_amt']}" + assert flashloan_tokens['0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48']["flash_amt"] == 5000000000, f"expected flashloan amount of 5000000000, found {flashloan_tokens['0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48']['flash_amt']}" # - From b8580a631b8e6bbdd7a781cb53f2135fd3bcab53 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 4 May 2024 10:09:52 +0300 Subject: [PATCH 013/131] Remove unused code and corresponding test --- fastlane_bot/helpers/routehandler.py | 31 -- .../tests/test_051_BalancerFlashloans.py | 275 ------------------ 2 files changed, 306 deletions(-) delete mode 100644 fastlane_bot/tests/test_051_BalancerFlashloans.py diff --git a/fastlane_bot/helpers/routehandler.py b/fastlane_bot/helpers/routehandler.py index 52fe0908a..ff9a41864 100644 --- a/fastlane_bot/helpers/routehandler.py +++ b/fastlane_bot/helpers/routehandler.py @@ -403,37 +403,6 @@ def _extract_single_flashloan_token(self, trade_instructions: List[TradeInstruct return flash_tokens - def _extract_flashloan_tokens(self, trade_instructions: List[TradeInstruction]) -> Dict: - """ - Generate a list of the flashloan tokens and amounts. - :param trade_instructions: A list of trade instruction objects - """ - token_change = {} - flash_tokens = {} - for trade in trade_instructions: - tknin_address = self.wrapped_gas_token_to_native(trade.tknin_address) - tknout_address = self.wrapped_gas_token_to_native(trade.tknout_address) - - token_change[tknin_address] = {"tkn": tknin_address, "amtin": 0, "amtout": 0, "balance": 0} - token_change[tknout_address] = {"tkn": tknout_address, "amtin": 0, "amtout": 0, "balance": 0} - - for trade in trade_instructions: - tknin_address = self.wrapped_gas_token_to_native(trade.tknin_address) - tknout_address = self.wrapped_gas_token_to_native(trade.tknout_address) - - token_change[tknin_address]["amtin"] = token_change[tknin_address]["amtin"] + trade.amtin_wei - token_change[tknin_address]["balance"] = token_change[tknin_address]["balance"] - trade.amtin_wei - token_change[tknout_address]["amtout"] = token_change[tknout_address]["amtout"] + trade.amtout_wei - token_change[tknout_address]["balance"] = token_change[tknout_address]["balance"] + trade.amtout_wei - - if token_change[tknin_address]["balance"] < 0: - flash_tokens[tknin_address] = {"tkn": trade._tknin_address, - "flash_amt": token_change[tknin_address]["amtin"], - "decimals": trade.tknin_decimals} - - return flash_tokens - - def get_arb_contract_args( self, trade_instructions: List[TradeInstruction], deadline: int ) -> Tuple[List[RouteStruct], int]: diff --git a/fastlane_bot/tests/test_051_BalancerFlashloans.py b/fastlane_bot/tests/test_051_BalancerFlashloans.py deleted file mode 100644 index 9fff5bd3f..000000000 --- a/fastlane_bot/tests/test_051_BalancerFlashloans.py +++ /dev/null @@ -1,275 +0,0 @@ -# ------------------------------------------------------------ -# Auto generated test file `test_051_BalancerFlashloans.py` -# ------------------------------------------------------------ -# source file = NBTest_051_BalancerFlashloans.py -# test id = 051 -# test comment = BalancerFlashloans -# ------------------------------------------------------------ - - - -""" -This module contains the tests for the exchanges classes -""" -from fastlane_bot import Bot, Config -from fastlane_bot.bot import CarbonBot -from fastlane_bot.tools.cpc import ConstantProductCurve as CPC -from fastlane_bot.events.exchanges import UniswapV2, UniswapV3, CarbonV1, BancorV3 -from fastlane_bot.events.interface import QueryInterface -from fastlane_bot.helpers import TradeInstruction, TxRouteHandler -from fastlane_bot.events.managers.manager import Manager -from fastlane_bot.events.interface import QueryInterface -from joblib import Parallel, delayed -import math -import json -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(CPC)) -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(Bot)) -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(UniswapV2)) -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(UniswapV3)) -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(CarbonV1)) -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(BancorV3)) -from fastlane_bot.testing import * - -#plt.style.use('seaborn-dark') -plt.rcParams['figure.figsize'] = [12,6] -from fastlane_bot import __VERSION__ -require("3.0", __VERSION__) - - - -C = cfg = Config.new(config=Config.CONFIG_MAINNET) -cfg.DEFAULT_MIN_PROFIT_GAS_TOKEN = 0.00001 -assert (C.NETWORK == C.NETWORK_MAINNET) -assert (C.PROVIDER == C.PROVIDER_ALCHEMY) -setup_bot = CarbonBot(ConfigObj=C) -pools = None - -with open('fastlane_bot/tests/_data/latest_pool_data_testing.json') as f: - pools = json.load(f) - - -pools = [pool for pool in pools] -pools[0] -static_pools = pools -state = pools -exchanges = list({ex['exchange_name'] for ex in state}) -db = QueryInterface(state=state, ConfigObj=C, exchanges=exchanges) -setup_bot.db = db - -static_pool_data_filename = "static_pool_data" - -static_pool_data = pd.read_csv(f"fastlane_bot/data/{static_pool_data_filename}.csv", low_memory=False) - -uniswap_v2_event_mappings = pd.read_csv("fastlane_bot/data/uniswap_v2_event_mappings.csv", low_memory=False) - -tokens = pd.read_csv("fastlane_bot/data/tokens.csv", low_memory=False) - -exchanges = "carbon_v1,bancor_v3,uniswap_v3,uniswap_v2,sushiswap_v2" - -exchanges = exchanges.split(",") - - -alchemy_max_block_fetch = 20 -static_pool_data["cid"] = [ - cfg.w3.keccak(text=f"{row['descr']}").hex() - for index, row in static_pool_data.iterrows() - ] -static_pool_data = [ - row for index, row in static_pool_data.iterrows() - if row["exchange_name"] in exchanges -] - -static_pool_data = pd.DataFrame(static_pool_data) -static_pool_data['exchange_name'].unique() -mgr = Manager( - web3=cfg.w3, - w3_async=cfg.w3_async, - cfg=cfg, - pool_data=static_pool_data.to_dict(orient="records"), - SUPPORTED_EXCHANGES=exchanges, - alchemy_max_block_fetch=alchemy_max_block_fetch, - uniswap_v2_event_mappings=uniswap_v2_event_mappings, - tokens=tokens.to_dict(orient="records"), -) - -start_time = time.time() -Parallel(n_jobs=-1, backend="threading")( - delayed(mgr.add_pool_to_exchange)(row) for row in mgr.pool_data -) -cfg.logger.info(f"Time taken to add initial pools: {time.time() - start_time}") - -mgr.deduplicate_pool_data() -cids = [pool["cid"] for pool in mgr.pool_data] -assert len(cids) == len(set(cids)), "duplicate cid's exist in the pool data" -def init_bot(mgr: Manager) -> CarbonBot: - """ - Initializes the bot. - - Parameters - ---------- - mgr : Manager - The manager object. - - Returns - ------- - CarbonBot - The bot object. - """ - mgr.cfg.logger.info("Initializing the bot...") - bot = CarbonBot(ConfigObj=mgr.cfg) - bot.db = db - bot.db.mgr = mgr - assert isinstance( - bot.db, QueryInterface - ), "QueryInterface not initialized correctly" - return bot -bot = init_bot(mgr) -bot.db.remove_unmapped_uniswap_v2_pools() -bot.db.remove_zero_liquidity_pools() -bot.db.remove_unsupported_exchanges() -tokens = bot.db.get_tokens() -ADDRDEC = {t.address: (t.address, int(t.decimals)) for t in tokens if not math.isnan(t.decimals)} -flashloan_tokens = bot.RUN_FLASHLOAN_TOKENS -CCm = bot.get_curves() -pools = db.get_pool_data_with_tokens() - -arb_mode = "multi_pairwise" - - -# ------------------------------------------------------------ -# Test 051 -# File test_051_BalancerFlashloans.py -# Segment Test_extract_flashloan_tokens -# ------------------------------------------------------------ -def test_test_extract_flashloan_tokens(): -# ------------------------------------------------------------ - - # + - ti1 = TradeInstruction( - cid='4083388403051261561560495289181218537544', - tknin='0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - amtin=5000, - tknout='0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', - amtout=1, - ConfigObj=cfg, - db = db, - tknin_dec_override = 6, - tknout_dec_override = 8, - tknin_addr_override = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - tknout_addr_override = '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', - exchange_override = 'bancor_v3' - ) - - ti2 = TradeInstruction( - cid='4083388403051261561560495289181218537544', - tknin='0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', - amtin=1, - tknout='0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - amtout=5005, - ConfigObj=cfg, - db = db, - tknout_dec_override = 8, - tknin_dec_override = 6, - tknout_addr_override = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - tknin_addr_override = '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', - exchange_override = 'carbon_v1' - ) - - ti3 = TradeInstruction( - cid='4083388403051261561560495289181218537544', - tknin='0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - amtin=5000, - tknout='0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', - amtout=1, - ConfigObj=cfg, - db = db, - tknin_dec_override = 6, - tknout_dec_override = 8, - tknin_addr_override = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - tknout_addr_override = '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', - exchange_override = 'bancor_v3' - ) - - ti4 = TradeInstruction( - cid='4083388403051261561560495289181218537544', - tknin='0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', - amtin=0.2, - tknout='0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - amtout=1000, - ConfigObj=cfg, - db = db, - tknout_dec_override = 8, - tknin_dec_override = 6, - tknout_addr_override = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - tknin_addr_override = '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', - exchange_override = 'carbon_v1' - ) - ti5 = TradeInstruction( - cid='4083388403051261561560495289181218537544', - tknin='0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', - amtin=0.3, - tknout='0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - amtout=2000, - ConfigObj=cfg, - db = db, - tknout_dec_override = 8, - tknin_dec_override = 6, - tknout_addr_override = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - tknin_addr_override = '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', - exchange_override = 'carbon_v1' - ) - - ti6 = TradeInstruction( - cid='4083388403051261561560495289181218537544', - tknin='0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', - amtin=0.5, - tknout='0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - amtout=3005, - ConfigObj=cfg, - db = db, - tknout_dec_override = 8, - tknin_dec_override = 6, - tknout_addr_override = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - tknin_addr_override = '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', - exchange_override = 'carbon_v1' - ) - - ti7 = TradeInstruction( - cid='4083388403051261561560495289181218537544', - tknin='0xdAC17F958D2ee523a2206206994597C13D831ec7', - amtin=2000, - tknout='0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', - amtout=1.5, - ConfigObj=cfg, - db = db, - tknin_dec_override = 6, - tknout_dec_override = 18, - tknin_addr_override = '0xdAC17F958D2ee523a2206206994597C13D831ec7', - tknout_addr_override = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', - exchange_override = 'bancor_v3' - ) - - ti8 = TradeInstruction( - cid='4083388403051261561560495289181218537544', - tknin='0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', - amtin=1.5, - tknout='0xdAC17F958D2ee523a2206206994597C13D831ec7', - amtout=3005, - ConfigObj=cfg, - db = db, - tknout_dec_override = 18, - tknin_dec_override = 6, - tknout_addr_override = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', - tknin_addr_override = '0xdAC17F958D2ee523a2206206994597C13D831ec7', - exchange_override = 'carbon_v1' - ) - - instructions = [ti1, ti2] - instructions2 = [ti3, ti4, ti5, ti6, ti7, ti8] - - route_handler = TxRouteHandler(instructions) - flashloan_tokens = route_handler._extract_flashloan_tokens(instructions2) - - assert len(flashloan_tokens.keys()) == 2 - assert flashloan_tokens['0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48']["flash_amt"] == 5000000000, f"expected flashloan amount of 5000000000, found {flashloan_tokens['0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48']['flash_amt']}" - # - From e0259e861aec5cf18f136677f9cfb9d87d233271 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 4 May 2024 10:13:25 +0300 Subject: [PATCH 014/131] Remove unused code --- fastlane_bot/helpers/routehandler.py | 30 ---------------------------- 1 file changed, 30 deletions(-) diff --git a/fastlane_bot/helpers/routehandler.py b/fastlane_bot/helpers/routehandler.py index ff9a41864..98c9d3236 100644 --- a/fastlane_bot/helpers/routehandler.py +++ b/fastlane_bot/helpers/routehandler.py @@ -373,36 +373,6 @@ def wrapped_gas_token_to_native(self, tkn: str): else: return tkn - def _extract_single_flashloan_token(self, trade_instructions: List[TradeInstruction]) -> Dict: - """ - Generate a flashloan tokens and amounts. - :param trade_instructions: A list of trade instruction objects - """ - - is_FL_NATIVE_permitted = False - if self.ConfigObj.NETWORK in [self.ConfigObj.NETWORK_ETHEREUM]: - is_FL_NATIVE_permitted = True - - if trade_instructions[0].tknin_is_native and not is_FL_NATIVE_permitted: - tknin_address = self.ConfigObj.WRAPPED_GAS_TOKEN_ADDRESS - self.ConfigObj.logger.info( - f"[routehandler._extract_single_flashloan_token] Not permitted to flashloan NATIVE - Switching to WRAPPED") - elif trade_instructions[0].tknin_is_native and is_FL_NATIVE_permitted: - tknin_address = self.ConfigObj.NATIVE_GAS_TOKEN_ADDRESS - elif trade_instructions[0].tknin_is_wrapped: - tknin_address = self.ConfigObj.WRAPPED_GAS_TOKEN_ADDRESS - else: - tknin_address = trade_instructions[0].tknin_address - flash_tokens = { - tknin_address: - { - "tkn": tknin_address, - "flash_amt": trade_instructions[0].amtin_wei, - "decimals": trade_instructions[0].tknin_decimals} - } - - return flash_tokens - def get_arb_contract_args( self, trade_instructions: List[TradeInstruction], deadline: int ) -> Tuple[List[RouteStruct], int]: From f4c8673b86e39f4dbeb4fa59e715a8d7a9199df7 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 4 May 2024 10:13:57 +0300 Subject: [PATCH 015/131] Remove unused code --- fastlane_bot/helpers/routehandler.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/fastlane_bot/helpers/routehandler.py b/fastlane_bot/helpers/routehandler.py index 98c9d3236..eb5ec13ed 100644 --- a/fastlane_bot/helpers/routehandler.py +++ b/fastlane_bot/helpers/routehandler.py @@ -373,22 +373,6 @@ def wrapped_gas_token_to_native(self, tkn: str): else: return tkn - def get_arb_contract_args( - self, trade_instructions: List[TradeInstruction], deadline: int - ) -> Tuple[List[RouteStruct], int]: - """ - Gets the arguments needed to instantiate the `ArbContract` class. - - Returns - ------- - List[Any] - The arguments needed to instantiate the `ArbContract` class. - """ - route_struct = self.get_route_structs( - trade_instructions=trade_instructions, deadline=deadline - ) - return route_struct - @staticmethod def _get_trade_dicts_from_objects(trade_instructions: List[TradeInstruction]) -> List[Dict[str, Any]]: return [ From cc04e6ec4b338f3ade2895d78c095f534dba875a Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 4 May 2024 18:26:44 +0300 Subject: [PATCH 016/131] Fix function `generate_flashloan_struct` --- fastlane_bot/helpers/routehandler.py | 53 ++++++++++++++-------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/fastlane_bot/helpers/routehandler.py b/fastlane_bot/helpers/routehandler.py index eb5ec13ed..9399f6560 100644 --- a/fastlane_bot/helpers/routehandler.py +++ b/fastlane_bot/helpers/routehandler.py @@ -327,20 +327,30 @@ def generate_flashloan_struct(self, trade_instructions_objects: List[TradeInstru else: source_token = trade_instructions_objects[0].tknin_address - platformId = 2 if self.ConfigObj.NETWORK in ["ethereum", "tenderly"] and source_token in [ + if self.ConfigObj.NETWORK in [ + self.ConfigObj.NETWORK_ETHEREUM, + self.ConfigObj.NETWORK_TENDERLY + ] and source_token in [ self.ConfigObj.BNT_ADDRESS, self.ConfigObj.ETH_ADDRESS, self.ConfigObj.WBTC_ADDRESS, self.ConfigObj.LINK_ADDRESS - ] else 7 - - return [ - { - "platformId": platformId, - "sourceTokens": [self.wrapped_gas_token_to_native(source_token)], - "sourceAmounts": [abs(trade_instructions_objects[0].amtin_wei)] - } - ] + ]: + return [ + { + "platformId": 2, + "sourceTokens": [self.wrapped_gas_token_to_native(source_token)], + "sourceAmounts": [abs(trade_instructions_objects[0].amtin_wei)] + } + ] + else: + return [ + { + "platformId": 7, + "sourceTokens": [source_token], + "sourceAmounts": [abs(trade_instructions_objects[0].amtin_wei)] + } + ] def native_gas_token_to_wrapped(self, tkn: str): """ @@ -349,29 +359,18 @@ def native_gas_token_to_wrapped(self, tkn: str): The token address returns: str The token address, converted to wrapped gas token if the input was the native gas token - """ return self.ConfigObj.WRAPPED_GAS_TOKEN_ADDRESS if tkn == self.ConfigObj.NATIVE_GAS_TOKEN_ADDRESS else tkn def wrapped_gas_token_to_native(self, tkn: str): """ - Checks if a Token is a wrapped gas token and converts it to the native gas token. - - This is only relevant on the Ethereum network - - :param tkn: the token address - - returns: - the token address + This function returns the native gas token address if the input token is the wrapped gas token, otherwise it returns the input token address. + :param tkn: str + The token address + returns: str + The token address, converted to native gas token if the input was the wrapped gas token """ - - if self.ConfigObj.NETWORK not in ["ethereum", "tenderly"]: - return tkn - - if tkn in [self.ConfigObj.WRAPPED_GAS_TOKEN_ADDRESS, self.ConfigObj.WRAPPED_GAS_TOKEN_ADDRESS]: - return self.ConfigObj.NATIVE_GAS_TOKEN_ADDRESS if tkn == self.ConfigObj.WRAPPED_GAS_TOKEN_ADDRESS else self.ConfigObj.NATIVE_GAS_TOKEN_ADDRESS - else: - return tkn + return self.ConfigObj.NATIVE_GAS_TOKEN_ADDRESS if tkn == self.ConfigObj.WRAPPED_GAS_TOKEN_ADDRESS else tkn @staticmethod def _get_trade_dicts_from_objects(trade_instructions: List[TradeInstruction]) -> List[Dict[str, Any]]: From f47e12cf3cd0ac4f2d631a9a200d392f1ff72036 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 4 May 2024 18:56:07 +0300 Subject: [PATCH 017/131] Cleanup routerhandler.py --- fastlane_bot/helpers/routehandler.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/fastlane_bot/helpers/routehandler.py b/fastlane_bot/helpers/routehandler.py index 9399f6560..dcdbd5bf7 100644 --- a/fastlane_bot/helpers/routehandler.py +++ b/fastlane_bot/helpers/routehandler.py @@ -262,17 +262,12 @@ def get_route_structs( assert not deadline is None, "deadline cannot be None" - pools = [ - self._cid_to_pool(trade_instruction.cid, trade_instruction.db) - for trade_instruction in trade_instructions - ] - return [ self._to_route_struct( min_target_amount=trade_instruction.amtout_wei, deadline=deadline, target_address=trade_instruction.get_real_tkn_out, - custom_address=self.get_custom_address(pool), + custom_address=self.get_custom_address(trade_instruction.db.get_pool(cid=trade_instruction.cid)), platform_id=trade_instruction.platform_id, customInt=trade_instruction.custom_int, customData=trade_instruction.custom_data, @@ -280,7 +275,7 @@ def get_route_structs( source_amount=trade_instruction.amtin_wei, exchange_name=trade_instruction.exchange_name, ) - for trade_instruction, pool in zip(trade_instructions, pools) + for trade_instruction in trade_instructions ] def get_custom_address( @@ -1368,9 +1363,6 @@ def calculate_trade_outputs( def _from_wei_to_decimals(self, tkn0_amt: Decimal, tkn0_decimals: int) -> Decimal: return Decimal(str(tkn0_amt)) / Decimal("10") ** Decimal(str(tkn0_decimals)) - def _cid_to_pool(self, cid: str, db: any) -> Pool: - return db.get_pool(cid=cid) - # TODO: Those functions should probably be private; also -- are they needed at # all? Most of them seem to be extremely trivial From db20110551b04f2f26cb6bc5f3d3e0f4947eb535 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 4 May 2024 20:51:26 +0300 Subject: [PATCH 018/131] Cleanup --- fastlane_bot/helpers/routehandler.py | 5 ++--- fastlane_bot/tests/test_042_TestBancorV3ModeTwoHop.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/fastlane_bot/helpers/routehandler.py b/fastlane_bot/helpers/routehandler.py index dcdbd5bf7..ed4f2d7d1 100644 --- a/fastlane_bot/helpers/routehandler.py +++ b/fastlane_bot/helpers/routehandler.py @@ -439,11 +439,10 @@ def aggregate_bancor_v3_trades(calculated_trade_instructions: List[TradeInstruct for idx, trade in enumerate(calculated_trade_instructions): if idx > 0: - if trade.exchange_name == "bancor_v3" and calculated_trade_instructions[ - idx - 1].exchange_name == "bancor_v3": + if trade.exchange_name == calculated_trade_instructions[idx - 1].exchange_name == "bancor_v3": trade_before = calculated_trade_instructions[idx - 1] # This checks for a two-hop trade through BNT and combines them - if trade_before.tknout_address in "0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C" and trade.tknin_address in "0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C": + if trade_before.tknout_address == trade.tknin_address == trade.ConfigObj.BNT_ADDRESS: new_trade_instruction = TradeInstruction(ConfigObj=trade.ConfigObj, cid=trade_before.cid, amtin=trade_before.amtin, amtout=trade.amtout, tknin=trade_before.tknin_address, diff --git a/fastlane_bot/tests/test_042_TestBancorV3ModeTwoHop.py b/fastlane_bot/tests/test_042_TestBancorV3ModeTwoHop.py index 012c8b757..b94c8b0dc 100644 --- a/fastlane_bot/tests/test_042_TestBancorV3ModeTwoHop.py +++ b/fastlane_bot/tests/test_042_TestBancorV3ModeTwoHop.py @@ -206,7 +206,7 @@ def test_test_trade_merge(): ) assert len(calculated_trade_instructions) == 3 # Aggregate multiple Bancor V3 trades into a single trade - calculated_trade_instructions = TxRouteHandler.aggregate_bancor_v3_trades( + calculated_trade_instructions = tx_route_handler.aggregate_bancor_v3_trades( calculated_trade_instructions ) assert len(calculated_trade_instructions) == 2 From db7fb0822c880dce5b6e1a4391e375de4996b457 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sun, 5 May 2024 14:24:28 +0300 Subject: [PATCH 019/131] Simplify and improve function `maximize_last_trade_per_tkn` --- fastlane_bot/helpers/routehandler.py | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/fastlane_bot/helpers/routehandler.py b/fastlane_bot/helpers/routehandler.py index ed4f2d7d1..62f3e39f7 100644 --- a/fastlane_bot/helpers/routehandler.py +++ b/fastlane_bot/helpers/routehandler.py @@ -73,21 +73,12 @@ def maximize_last_trade_per_tkn(route_struct: List[Dict[str, Any]]): :param route_struct: the route struct object """ - tkns_traded = [route_struct[0]["sourceToken"]] + tkns_traded = set([route_struct[0]["sourceToken"]]) for j, trade in enumerate(reversed(route_struct)): idx = len(route_struct) - 1 - j - if type(trade) == dict: - if trade["sourceToken"] in tkns_traded: - continue - else: - route_struct[idx]["sourceAmount"] = 0 - tkns_traded.append(trade["sourceToken"]) - elif type(trade) == RouteStruct: - if trade.sourceToken in tkns_traded: - continue - else: - route_struct[idx].sourceAmount = 0 - tkns_traded.append(trade.sourceToken) + if trade["sourceToken"] not in tkns_traded: + tkns_traded.add(trade["sourceToken"]) + route_struct[idx]["sourceAmount"] = 0 @dataclass From 08e3af1a3a86e6ccf41fffda82bb43eb6a4f1828 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sun, 5 May 2024 22:06:24 +0300 Subject: [PATCH 020/131] Cleanup terraformer script add update data files for mantle and linea --- .../linea/solidly_v2_event_mappings.csv | 6 + .../linea/static_pool_data.csv | 167 ++++++++++++++++++ .../data/blockchain_data/linea/tokens.csv | 7 + .../linea/uniswap_v3_event_mappings.csv | 4 + .../mantle/solidly_v2_event_mappings.csv | 1 + .../mantle/static_pool_data.csv | 10 ++ .../data/blockchain_data/mantle/tokens.csv | 4 + .../mantle/uniswap_v2_event_mappings.csv | 2 + .../mantle/uniswap_v3_event_mappings.csv | 7 + run_blockchain_terraformer.py | 74 ++++---- 10 files changed, 240 insertions(+), 42 deletions(-) diff --git a/fastlane_bot/data/blockchain_data/linea/solidly_v2_event_mappings.csv b/fastlane_bot/data/blockchain_data/linea/solidly_v2_event_mappings.csv index be61911f5..5bd049f9a 100644 --- a/fastlane_bot/data/blockchain_data/linea/solidly_v2_event_mappings.csv +++ b/fastlane_bot/data/blockchain_data/linea/solidly_v2_event_mappings.csv @@ -163,3 +163,9 @@ xfai_v0,0x0Ab89ed59d510d64FD3f44e973e13A7909dA3BA7 xfai_v0,0x497d4cBeA7E45C5f2D4146D90e67eBAaee4f8084 xfai_v0,0xa076804861a21dD0ba2ea82C776F1AeFa9d12e57 xfai_v0,0x98E7cF03DeB846899B0Ac164CB77B05b940BF415 +lynex_v2,0x9e1881B7af88c468cf048E265e5AFCd92852767D +lynex_v2,0x9D2495eE468dd08E072514B6924a140632c281B1 +lynex_v2,0xbbD94Eef0109ec29433073E30c6ecE83Fd3C4C52 +lynex_v2,0x2bAbfb5f0f40e77be0a9011f83A6252ECc796D54 +lynex_v2,0xB302D7236E7B53bbB384A25608c4FB55152AC6cC +lynex_v2,0x7a21302BD6D314C1f46797115D704D664e0635D0 diff --git a/fastlane_bot/data/blockchain_data/linea/static_pool_data.csv b/fastlane_bot/data/blockchain_data/linea/static_pool_data.csv index 11ca9dcdd..95da59de1 100644 --- a/fastlane_bot/data/blockchain_data/linea/static_pool_data.csv +++ b/fastlane_bot/data/blockchain_data/linea/static_pool_data.csv @@ -411,3 +411,170 @@ cid,strategy_id,last_updated,last_updated_block,descr,pair_name,exchange_name,fe 0x497d4cBeA7E45C5f2D4146D90e67eBAaee4f8084,0,,1412243,xfai_v0 0x6EF95B6f3b0F39508e3E04054Be96D5eE39eDE0d/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,0x6EF95B6f3b0F39508e3E04054Be96D5eE39eDE0d/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,xfai_v0,0.002,0.002,0x497d4cBeA7E45C5f2D4146D90e67eBAaee4f8084,,0x6EF95B6f3b0F39508e3E04054Be96D5eE39eDE0d,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,13,SIS,WETH,0,0,0,,,,,xfai_v0,volatile,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 0xa076804861a21dD0ba2ea82C776F1AeFa9d12e57,0,,1833872,xfai_v0 0xe7DC30E9Bc08A1Dd1a2909D0f0e1Af4539398F01/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,0xe7DC30E9Bc08A1Dd1a2909D0f0e1Af4539398F01/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,xfai_v0,0.002,0.002,0xa076804861a21dD0ba2ea82C776F1AeFa9d12e57,,0xe7DC30E9Bc08A1Dd1a2909D0f0e1Af4539398F01,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,13,TFS,WETH,0,0,0,,,,,xfai_v0,volatile,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 0x98E7cF03DeB846899B0Ac164CB77B05b940BF415,0,,3673450,xfai_v0 0x43E8809ea748EFf3204ee01F08872F063e44065f/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,0x43E8809ea748EFf3204ee01F08872F063e44065f/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,xfai_v0,0.002,0.002,0x98E7cF03DeB846899B0Ac164CB77B05b940BF415,,0x43E8809ea748EFf3204ee01F08872F063e44065f,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,13,MENDI,WETH,0,0,0,,,,,xfai_v0,volatile,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xEbc78d2b3C7982E9d4e4Bf6294E81B2cd9e0778b,0,,120914,echodex_v3 0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e6/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 2500,0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e6/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,2500,0.0025,0xEbc78d2b3C7982E9d4e4Bf6294E81B2cd9e0778b,,0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e6,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,ECP,WETH,0,0,0,0,0,0,50,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x433f9C64fafB532c3B71b32fFaF6A5796e58Db5D,0,,123594,echodex_v3 0x7d43AABC515C356145049227CeE54B608342c0ad/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 2500,0x7d43AABC515C356145049227CeE54B608342c0ad/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,2500,0.0025,0x433f9C64fafB532c3B71b32fFaF6A5796e58Db5D,,0x7d43AABC515C356145049227CeE54B608342c0ad,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,BUSD,WETH,0,0,0,0,0,0,50,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xEE5Af2e7a33bc7945A39f58f4aAbf67d525F902E,0,,123680,echodex_v3 0x9Dd6EA6f9D1fba5ed640651f06802e32FF455221/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 2500,0x9Dd6EA6f9D1fba5ed640651f06802e32FF455221/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,2500,0.0025,0xEE5Af2e7a33bc7945A39f58f4aAbf67d525F902E,,0x9Dd6EA6f9D1fba5ed640651f06802e32FF455221,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,LIN,WETH,0,0,0,0,0,0,50,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xa266E7f3B3236476bd587521156D520763B393b7,0,,124378,echodex_v3 0xAE7B4Ebf3c7FedA18D5A2a85dC37f40260B40Ac5/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0xAE7B4Ebf3c7FedA18D5A2a85dC37f40260B40Ac5/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,500,0.0005,0xa266E7f3B3236476bd587521156D520763B393b7,,0xAE7B4Ebf3c7FedA18D5A2a85dC37f40260B40Ac5,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,$Mask,WETH,0,0,0,0,0,0,10,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xfd91599a02A4d9DdaDE5419A2898AE4737514B08,0,,125281,echodex_v3 0x265B25e22bcd7f10a5bD6E6410F10537Cc7567e8/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 2500,0x265B25e22bcd7f10a5bD6E6410F10537Cc7567e8/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,2500,0.0025,0xfd91599a02A4d9DdaDE5419A2898AE4737514B08,,0x265B25e22bcd7f10a5bD6E6410F10537Cc7567e8,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,WMATIC,WETH,0,0,0,0,0,0,50,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x547926c48Fc0a95A700148643AEea065DEDc93c2,0,,127312,echodex_v3 0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xEB466342C4d449BC9f53A865D5Cb90586f40521 2500,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xEB466342C4d449BC9f53A865D5Cb90586f40521,echodex_v3,2500,0.0025,0x547926c48Fc0a95A700148643AEea065DEDc93c2,,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,0xEB466342C4d449BC9f53A865D5Cb90586f405215,18,6,4,WETH,AXLUSDC,0,0,0,0,0,0,50,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x7D85A28a9a98acA16Cbb02FCfdfa5E7c86e8e7B5,0,,133103,echodex_v3 0x7d43AABC515C356145049227CeE54B608342c0ad/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 100,0x7d43AABC515C356145049227CeE54B608342c0ad/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,100,0.0001,0x7D85A28a9a98acA16Cbb02FCfdfa5E7c86e8e7B5,,0x7d43AABC515C356145049227CeE54B608342c0ad,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,BUSD,WETH,0,0,0,0,0,0,1,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x555D681FA51953E4c0B076A197b25922A718f5FF,0,,142836,echodex_v3 0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e6/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e6/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,500,0.0005,0x555D681FA51953E4c0B076A197b25922A718f5FF,,0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e6,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,ECP,WETH,0,0,0,0,0,0,10,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x8aA6046C0469bA7D7fabE0CFDd018d52d5f8FF09,0,,144350,echodex_v3 0x7d43AABC515C356145049227CeE54B608342c0ad/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x7d43AABC515C356145049227CeE54B608342c0ad/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,10000,0.01,0x8aA6046C0469bA7D7fabE0CFDd018d52d5f8FF09,,0x7d43AABC515C356145049227CeE54B608342c0ad,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,BUSD,WETH,0,0,0,0,0,0,200,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x3C76F7Db1322b397164aa40E34170170fF99f384,0,,145966,echodex_v3 0x7d43AABC515C356145049227CeE54B608342c0ad/0xEB466342C4d449BC9f53A865D5Cb90586f40521 2500,0x7d43AABC515C356145049227CeE54B608342c0ad/0xEB466342C4d449BC9f53A865D5Cb90586f40521,echodex_v3,2500,0.0025,0x3C76F7Db1322b397164aa40E34170170fF99f384,,0x7d43AABC515C356145049227CeE54B608342c0ad,0xEB466342C4d449BC9f53A865D5Cb90586f405215,18,6,4,BUSD,AXLUSDC,0,0,0,0,0,0,50,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x59CCA671497bcaB95bEd2d93D1Ff6902C5d0955d,0,,152784,echodex_v3 0x7f5373AE26c3E8FfC4c77b7255DF7eC1A9aF52a6/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x7f5373AE26c3E8FfC4c77b7255DF7eC1A9aF52a6/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,10000,0.01,0x59CCA671497bcaB95bEd2d93D1Ff6902C5d0955d,,0x7f5373AE26c3E8FfC4c77b7255DF7eC1A9aF52a6,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,6,18,4,axlUSDT,WETH,0,0,0,0,0,0,200,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x8276DAfA5008547FeF699640088d01160637F774,0,,155353,echodex_v3 0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e6/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e6/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,10000,0.01,0x8276DAfA5008547FeF699640088d01160637F774,,0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e6,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,ECP,WETH,0,0,0,0,0,0,200,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xE4F5Dc6cAb4B23e124d3a73a2CfEE32DC070F72d,0,,156349,echodex_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 2500,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,2500,0.0025,0xE4F5Dc6cAb4B23e124d3a73a2CfEE32DC070F72d,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,6,18,4,USDC,WETH,0,0,0,0,0,0,50,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xf5dD371C44CAc4634aDc8B7CB82B0DEd873d0572,0,,159568,echodex_v3 0x1a35EE4640b0A3B87705B0A4B45D227Ba60Ca2ad/0xEB466342C4d449BC9f53A865D5Cb90586f40521 10000,0x1a35EE4640b0A3B87705B0A4B45D227Ba60Ca2ad/0xEB466342C4d449BC9f53A865D5Cb90586f40521,echodex_v3,10000,0.01,0xf5dD371C44CAc4634aDc8B7CB82B0DEd873d0572,,0x1a35EE4640b0A3B87705B0A4B45D227Ba60Ca2ad,0xEB466342C4d449BC9f53A865D5Cb90586f405215,8,6,4,axlWBTC,AXLUSDC,0,0,0,0,0,0,200,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xf26c909730c07EF0E6CD779D022F81C9c3B708ef,0,,159654,echodex_v3 0x5C7e299CF531eb66f2A1dF637d37AbB78e6200C7/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x5C7e299CF531eb66f2A1dF637d37AbB78e6200C7/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,10000,0.01,0xf26c909730c07EF0E6CD779D022F81C9c3B708ef,,0x5C7e299CF531eb66f2A1dF637d37AbB78e6200C7,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,axlDAI,WETH,0,0,0,0,0,0,200,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xC624a30F89f146529E0A9990e58aD6a84cDb762a,0,,161138,echodex_v3 0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xf5C6825015280CdfD0b56903F9F8B5A2233476F 10000,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xf5C6825015280CdfD0b56903F9F8B5A2233476F,echodex_v3,10000,0.01,0xC624a30F89f146529E0A9990e58aD6a84cDb762a,,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,0xf5C6825015280CdfD0b56903F9F8B5A2233476F5,18,18,4,WETH,WBNB,0,0,0,0,0,0,200,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xb34aFb0FeA2F9b41a154737a80aabB1F455C3DC0,0,,161524,echodex_v3 0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e6/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 100,0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e6/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,100,0.0001,0xb34aFb0FeA2F9b41a154737a80aabB1F455C3DC0,,0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e6,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,ECP,WETH,0,0,0,0,0,0,1,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xb1F8918eF32A9F9dB45f35bA640Ffb7beE05DfF3,0,,170787,echodex_v3 0x7d43AABC515C356145049227CeE54B608342c0ad/0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e 100,0x7d43AABC515C356145049227CeE54B608342c0ad/0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e,echodex_v3,100,0.0001,0xb1F8918eF32A9F9dB45f35bA640Ffb7beE05DfF3,,0x7d43AABC515C356145049227CeE54B608342c0ad,0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e6,18,18,4,BUSD,ECP,0,0,0,0,0,0,1,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xE737171aA0Fb4fDf7846C18B5e3e268425325752,0,,171071,echodex_v3 0x7d43AABC515C356145049227CeE54B608342c0ad/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0x7d43AABC515C356145049227CeE54B608342c0ad/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,500,0.0005,0xE737171aA0Fb4fDf7846C18B5e3e268425325752,,0x7d43AABC515C356145049227CeE54B608342c0ad,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,BUSD,WETH,0,0,0,0,0,0,10,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xD5537E58f30b4AE4342Efb0f2c3B53EB491b1aDa,0,,174861,echodex_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e 100,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e,echodex_v3,100,0.0001,0xD5537E58f30b4AE4342Efb0f2c3B53EB491b1aDa,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e6,6,18,4,USDC,ECP,0,0,0,0,0,0,1,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xAE261A26AaBF8222B4ee9b976d459008a3f3c3D7,0,,175005,echodex_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,10000,0.01,0xAE261A26AaBF8222B4ee9b976d459008a3f3c3D7,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,6,18,4,USDC,WETH,0,0,0,0,0,0,200,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x0cF6B45B9E5400E20782a0c6b7E217814207f109,0,,179750,echodex_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x7d43AABC515C356145049227CeE54B608342c0a 100,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x7d43AABC515C356145049227CeE54B608342c0a,echodex_v3,100,0.0001,0x0cF6B45B9E5400E20782a0c6b7E217814207f109,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0x7d43AABC515C356145049227CeE54B608342c0ad,6,18,4,USDC,BUSD,0,0,0,0,0,0,1,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xC218D620a54CA6bB6d77602f7E4BbecE2070D063,0,,180216,echodex_v3 0xA219439258ca9da29E9Cc4cE5596924745e12B93/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0xA219439258ca9da29E9Cc4cE5596924745e12B93/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,10000,0.01,0xC218D620a54CA6bB6d77602f7E4BbecE2070D063,,0xA219439258ca9da29E9Cc4cE5596924745e12B93,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,6,18,4,USDT,WETH,0,0,0,0,0,0,200,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xAC32D4B67f1E9ec51347828C8bB3dfD6Be94CBa2,0,,194566,echodex_v3 0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e6/0x9Dd6EA6f9D1fba5ed640651f06802e32FF45522 2500,0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e6/0x9Dd6EA6f9D1fba5ed640651f06802e32FF45522,echodex_v3,2500,0.0025,0xAC32D4B67f1E9ec51347828C8bB3dfD6Be94CBa2,,0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e6,0x9Dd6EA6f9D1fba5ed640651f06802e32FF455221,18,18,4,ECP,LIN,0,0,0,0,0,0,50,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xb3791fA86a5482D8C0911B8A38597E7666F68587,0,,195208,echodex_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 100,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,100,0.0001,0xb3791fA86a5482D8C0911B8A38597E7666F68587,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,6,18,4,USDC,WETH,0,0,0,0,0,0,1,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x77A1542EEBd006a99E82068BF3E60741Be73CCad,0,,221946,echodex_v3 0xA219439258ca9da29E9Cc4cE5596924745e12B93/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 2500,0xA219439258ca9da29E9Cc4cE5596924745e12B93/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,2500,0.0025,0x77A1542EEBd006a99E82068BF3E60741Be73CCad,,0xA219439258ca9da29E9Cc4cE5596924745e12B93,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,6,18,4,USDT,WETH,0,0,0,0,0,0,50,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xC31aDd890922E08D94023d225F0f5C653ea1A5FA,0,,222947,echodex_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x5471ea8f739dd37E9B81Be9c5c77754D8AA953E 100,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x5471ea8f739dd37E9B81Be9c5c77754D8AA953E,echodex_v3,100,0.0001,0xC31aDd890922E08D94023d225F0f5C653ea1A5FA,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0x5471ea8f739dd37E9B81Be9c5c77754D8AA953E4,6,18,4,USDC,WAVAX,0,0,0,0,0,0,1,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xaEF8E32D6db8F1b8f6Ee56eF6933fFe807187FE6,0,,229730,echodex_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d 500,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d,echodex_v3,500,0.0005,0xaEF8E32D6db8F1b8f6Ee56eF6933fFe807187FE6,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5,6,18,4,USDC,DAI,0,0,0,0,0,0,10,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x92912a1DFBAbD89219F79b961B34053260Add7c2,0,,255177,echodex_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xA219439258ca9da29E9Cc4cE5596924745e12B9 100,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xA219439258ca9da29E9Cc4cE5596924745e12B9,echodex_v3,100,0.0001,0x92912a1DFBAbD89219F79b961B34053260Add7c2,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0xA219439258ca9da29E9Cc4cE5596924745e12B93,6,6,4,USDC,USDT,0,0,0,0,0,0,1,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x7f489b2F23c093E42d4ff7a6217Aaa248513E192,0,,257350,echodex_v3 0x7d43AABC515C356145049227CeE54B608342c0ad/0xA219439258ca9da29E9Cc4cE5596924745e12B9 2500,0x7d43AABC515C356145049227CeE54B608342c0ad/0xA219439258ca9da29E9Cc4cE5596924745e12B9,echodex_v3,2500,0.0025,0x7f489b2F23c093E42d4ff7a6217Aaa248513E192,,0x7d43AABC515C356145049227CeE54B608342c0ad,0xA219439258ca9da29E9Cc4cE5596924745e12B93,18,6,4,BUSD,USDT,0,0,0,0,0,0,50,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xf533884F2ba3b89099c0d0cadBb314f9De693eB6,0,,270126,echodex_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xd2dDA4b56bEAe9f8E9C4C83D5159FB092F4b825 10000,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xd2dDA4b56bEAe9f8E9C4C83D5159FB092F4b825,echodex_v3,10000,0.01,0xf533884F2ba3b89099c0d0cadBb314f9De693eB6,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0xd2dDA4b56bEAe9f8E9C4C83D5159FB092F4b825a,6,18,4,USDC,lin,0,0,0,0,0,0,200,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x6315BB896d8fC448F256E1FeB12FacaC593f3e78,0,,285702,echodex_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x9Dd6EA6f9D1fba5ed640651f06802e32FF45522 2500,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x9Dd6EA6f9D1fba5ed640651f06802e32FF45522,echodex_v3,2500,0.0025,0x6315BB896d8fC448F256E1FeB12FacaC593f3e78,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0x9Dd6EA6f9D1fba5ed640651f06802e32FF455221,6,18,4,USDC,LIN,0,0,0,0,0,0,50,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xA424eB7109D0BA38F60334DF76F695D93fC9aEdA,0,,434747,echodex_v3 0x53F7B069CAA7Fe942E2f304f3e2987C0B177b1B8/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 100,0x53F7B069CAA7Fe942E2f304f3e2987C0B177b1B8/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,100,0.0001,0xA424eB7109D0BA38F60334DF76F695D93fC9aEdA,,0x53F7B069CAA7Fe942E2f304f3e2987C0B177b1B8,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,PIR,WETH,0,0,0,0,0,0,1,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xA50d0663A417F03Ac4f7E51E0B2f93d44aD9B217,0,,434771,echodex_v3 0x53F7B069CAA7Fe942E2f304f3e2987C0B177b1B8/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0x53F7B069CAA7Fe942E2f304f3e2987C0B177b1B8/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,500,0.0005,0xA50d0663A417F03Ac4f7E51E0B2f93d44aD9B217,,0x53F7B069CAA7Fe942E2f304f3e2987C0B177b1B8,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,PIR,WETH,0,0,0,0,0,0,10,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xF0aF8E4b3A282F52649263068f3a4Fc21f78D3Dc,0,,440197,echodex_v3 0x6Cd70ff7d7415B39485A1424E267eBA435876084/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 100,0x6Cd70ff7d7415B39485A1424E267eBA435876084/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,100,0.0001,0xF0aF8E4b3A282F52649263068f3a4Fc21f78D3Dc,,0x6Cd70ff7d7415B39485A1424E267eBA435876084,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,DICK,WETH,0,0,0,0,0,0,1,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x2b3a385533DE6DFa7f95d5e1721aac3B404E0177,0,,441933,echodex_v3 0x53F7B069CAA7Fe942E2f304f3e2987C0B177b1B8/0x6Cd70ff7d7415B39485A1424E267eBA43587608 10000,0x53F7B069CAA7Fe942E2f304f3e2987C0B177b1B8/0x6Cd70ff7d7415B39485A1424E267eBA43587608,echodex_v3,10000,0.01,0x2b3a385533DE6DFa7f95d5e1721aac3B404E0177,,0x53F7B069CAA7Fe942E2f304f3e2987C0B177b1B8,0x6Cd70ff7d7415B39485A1424E267eBA435876084,18,18,4,PIR,DICK,0,0,0,0,0,0,200,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x1033371e638Cb8E1A43F7555eF551AAa2355C332,0,,501186,echodex_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,500,0.0005,0x1033371e638Cb8E1A43F7555eF551AAa2355C332,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,6,18,4,USDC,WETH,0,0,0,0,0,0,10,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xAf0ce78D294776ec3412e591F1C960007052FCab,0,,515398,echodex_v3 0x9Dd6EA6f9D1fba5ed640651f06802e32FF455221/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0x9Dd6EA6f9D1fba5ed640651f06802e32FF455221/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,500,0.0005,0xAf0ce78D294776ec3412e591F1C960007052FCab,,0x9Dd6EA6f9D1fba5ed640651f06802e32FF455221,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,LIN,WETH,0,0,0,0,0,0,10,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x4b906917ec5E77Af315c1A0BEf73901b585B1e49,0,,595121,echodex_v3 0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5/0xA219439258ca9da29E9Cc4cE5596924745e12B9 100,0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5/0xA219439258ca9da29E9Cc4cE5596924745e12B9,echodex_v3,100,0.0001,0x4b906917ec5E77Af315c1A0BEf73901b585B1e49,,0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5,0xA219439258ca9da29E9Cc4cE5596924745e12B93,18,6,4,DAI,USDT,0,0,0,0,0,0,1,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x54e50B6eA3bbaf9A1dB36C9bEBdc8D3d311eE2c6,0,,603218,echodex_v3 0xA219439258ca9da29E9Cc4cE5596924745e12B93/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0xA219439258ca9da29E9Cc4cE5596924745e12B93/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,500,0.0005,0x54e50B6eA3bbaf9A1dB36C9bEBdc8D3d311eE2c6,,0xA219439258ca9da29E9Cc4cE5596924745e12B93,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,6,18,4,USDT,WETH,0,0,0,0,0,0,10,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x3f4bFa5F3984dE0cB00c8462FB66a9e66310C669,0,,624085,echodex_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e 500,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e,echodex_v3,500,0.0005,0x3f4bFa5F3984dE0cB00c8462FB66a9e66310C669,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e6,6,18,4,USDC,ECP,0,0,0,0,0,0,10,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xC1CDA0F812481b6f934ECDBE900eaf82b00ad3A9,0,,647721,echodex_v3 0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5/0x7d43AABC515C356145049227CeE54B608342c0a 100,0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5/0x7d43AABC515C356145049227CeE54B608342c0a,echodex_v3,100,0.0001,0xC1CDA0F812481b6f934ECDBE900eaf82b00ad3A9,,0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5,0x7d43AABC515C356145049227CeE54B608342c0ad,18,18,4,DAI,BUSD,0,0,0,0,0,0,1,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x0e37c152A9b6D79Fd8ff868437Ed5e18F8f6FCdb,0,,906833,echodex_v3 0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,500,0.0005,0x0e37c152A9b6D79Fd8ff868437Ed5e18F8f6FCdb,,0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,DAI,WETH,0,0,0,0,0,0,10,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xF0D6ba1346A6D4d7dc5abE999a14E1006878560F,0,,1319082,echodex_v3 0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 100,0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,100,0.0001,0xF0D6ba1346A6D4d7dc5abE999a14E1006878560F,,0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,wstETH,WETH,0,0,0,0,0,0,1,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xc64F5A12806aE9C14F78a8632b9235929f9822Ab,0,,2001037,echodex_v3 0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e6/0xA219439258ca9da29E9Cc4cE5596924745e12B9 500,0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e6/0xA219439258ca9da29E9Cc4cE5596924745e12B9,echodex_v3,500,0.0005,0xc64F5A12806aE9C14F78a8632b9235929f9822Ab,,0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e6,0xA219439258ca9da29E9Cc4cE5596924745e12B93,18,6,4,ECP,USDT,0,0,0,0,0,0,10,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xF5E38B7945dCc7EACBcd877eEc31A70B60C878FD,0,,2523959,echodex_v3 0x596B88eA5d6D75E2E2E3f03c5d2C797ECA82258f/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 100,0x596B88eA5d6D75E2E2E3f03c5d2C797ECA82258f/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,100,0.0001,0xF5E38B7945dCc7EACBcd877eEc31A70B60C878FD,,0x596B88eA5d6D75E2E2E3f03c5d2C797ECA82258f,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,ULT,WETH,0,0,0,0,0,0,1,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xC5D07562499A80a2D2d0118ea7006C054177220A,0,,2688359,echodex_v3 0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xe9503fe0Fd65685CB7e5e7B0e4E1B95266DfA7D 100,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xe9503fe0Fd65685CB7e5e7B0e4E1B95266DfA7D,echodex_v3,100,0.0001,0xC5D07562499A80a2D2d0118ea7006C054177220A,,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,0xe9503fe0Fd65685CB7e5e7B0e4E1B95266DfA7D7,18,18,4,WETH,BLOW,0,0,0,0,0,0,1,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x13Ff42D11cBABbf0508495988Ba8d43a33475E1C,0,,3454151,echodex_v3 0x5471ea8f739dd37E9B81Be9c5c77754D8AA953E4/0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e 10000,0x5471ea8f739dd37E9B81Be9c5c77754D8AA953E4/0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e,echodex_v3,10000,0.01,0x13Ff42D11cBABbf0508495988Ba8d43a33475E1C,,0x5471ea8f739dd37E9B81Be9c5c77754D8AA953E4,0x9201f3b9DfAB7C13Cd659ac5695D12D605B5F1e6,18,18,4,WAVAX,ECP,0,0,0,0,0,0,200,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x5C35f878b862D9a165c840b5074fd0CE320f209B,0,,3763536,echodex_v3 0x47ea9Ef2EE9C1048d405cDDE4d80245eb3FFFcBd/0xA219439258ca9da29E9Cc4cE5596924745e12B9 10000,0x47ea9Ef2EE9C1048d405cDDE4d80245eb3FFFcBd/0xA219439258ca9da29E9Cc4cE5596924745e12B9,echodex_v3,10000,0.01,0x5C35f878b862D9a165c840b5074fd0CE320f209B,,0x47ea9Ef2EE9C1048d405cDDE4d80245eb3FFFcBd,0xA219439258ca9da29E9Cc4cE5596924745e12B93,18,6,4,MGC,USDT,0,0,0,0,0,0,200,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x5b196dC0cE6E2ABDCaE1A66377c63dB6E5c2B6A9,0,,3835106,echodex_v3 0x5471ea8f739dd37E9B81Be9c5c77754D8AA953E4/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x5471ea8f739dd37E9B81Be9c5c77754D8AA953E4/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,10000,0.01,0x5b196dC0cE6E2ABDCaE1A66377c63dB6E5c2B6A9,,0x5471ea8f739dd37E9B81Be9c5c77754D8AA953E4,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,WAVAX,WETH,0,0,0,0,0,0,200,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xe6a0C7e4C5BE6a217177800825B02371Ef072ecd,0,,4189308,echodex_v3 0x5FBDF89403270a1846F5ae7D113A989F850d1566/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0x5FBDF89403270a1846F5ae7D113A989F850d1566/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,echodex_v3,500,0.0005,0xe6a0C7e4C5BE6a217177800825B02371Ef072ecd,,0x5FBDF89403270a1846F5ae7D113A989F850d1566,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,FOXY,WETH,0,0,0,0,0,0,10,echodex_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x9e1881B7af88c468cf048E265e5AFCd92852767D,0,,4164070,lynex_v2 0x1Bf74C010E6320bab11e2e5A532b5AC15e0b8aA6/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,0x1Bf74C010E6320bab11e2e5A532b5AC15e0b8aA6/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,lynex_v2,0.0001,0.0001,0x9e1881B7af88c468cf048E265e5AFCd92852767D,,0x1Bf74C010E6320bab11e2e5A532b5AC15e0b8aA6,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,3,weETH,WETH,0,0,0,,,,,lynex_v2,stable,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x9D2495eE468dd08E072514B6924a140632c281B1,0,,4164116,lynex_v2 0x1Bf74C010E6320bab11e2e5A532b5AC15e0b8aA6/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,0x1Bf74C010E6320bab11e2e5A532b5AC15e0b8aA6/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,lynex_v2,0.0025,0.0025,0x9D2495eE468dd08E072514B6924a140632c281B1,,0x1Bf74C010E6320bab11e2e5A532b5AC15e0b8aA6,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,3,weETH,WETH,0,0,0,,,,,lynex_v2,volatile,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xbbD94Eef0109ec29433073E30c6ecE83Fd3C4C52,0,,4174815,lynex_v2 0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8/0xA219439258ca9da29E9Cc4cE5596924745e12B93,0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8/0xA219439258ca9da29E9Cc4cE5596924745e12B93,lynex_v2,0.0025,0.0025,0xbbD94Eef0109ec29433073E30c6ecE83Fd3C4C52,,0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8,0xA219439258ca9da29E9Cc4cE5596924745e12B93,18,6,3,agEUR,USDT,0,0,0,,,,,lynex_v2,volatile,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x2bAbfb5f0f40e77be0a9011f83A6252ECc796D54,0,,4174935,lynex_v2 0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8/0xA219439258ca9da29E9Cc4cE5596924745e12B93,0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8/0xA219439258ca9da29E9Cc4cE5596924745e12B93,lynex_v2,0.0001,0.0001,0x2bAbfb5f0f40e77be0a9011f83A6252ECc796D54,,0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8,0xA219439258ca9da29E9Cc4cE5596924745e12B93,18,6,3,agEUR,USDT,0,0,0,,,,,lynex_v2,stable,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xB302D7236E7B53bbB384A25608c4FB55152AC6cC,0,,4207625,lynex_v2 0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xF3829aF0C018c8c1685B3d3d33B21cC98935fC87,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xF3829aF0C018c8c1685B3d3d33B21cC98935fC87,lynex_v2,0.0025,0.0025,0xB302D7236E7B53bbB384A25608c4FB55152AC6cC,,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,0xF3829aF0C018c8c1685B3d3d33B21cC98935fC87,18,6,3,WETH,XHNY,0,0,0,,,,,lynex_v2,volatile,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x7a21302BD6D314C1f46797115D704D664e0635D0,0,,4216873,lynex_v2 0x8A16b95EA186FE2e0AD6eAb9efB764be7846c50f/0xA219439258ca9da29E9Cc4cE5596924745e12B93,0x8A16b95EA186FE2e0AD6eAb9efB764be7846c50f/0xA219439258ca9da29E9Cc4cE5596924745e12B93,lynex_v2,0.0025,0.0025,0x7a21302BD6D314C1f46797115D704D664e0635D0,,0x8A16b95EA186FE2e0AD6eAb9efB764be7846c50f,0xA219439258ca9da29E9Cc4cE5596924745e12B93,18,6,3,TEUR,USDT,0,0,0,,,,,lynex_v2,volatile,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xC9876e9c4f007024fb39D2990D3D6b2D22CE7b48,0,,782986,metavault_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xA219439258ca9da29E9Cc4cE5596924745e12B9 500,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xA219439258ca9da29E9Cc4cE5596924745e12B9,metavault_v3,500,0.0005,0xC9876e9c4f007024fb39D2990D3D6b2D22CE7b48,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0xA219439258ca9da29E9Cc4cE5596924745e12B93,6,6,4,USDC,USDT,0,0,0,0,0,0,10,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x2270806159759Dd4bcA416aa4e8a1AaDeF48776A,0,,789714,metavault_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 3000,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,metavault_v3,3000,0.003,0x2270806159759Dd4bcA416aa4e8a1AaDeF48776A,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,6,18,4,USDC,WETH,0,0,0,0,0,0,60,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x9ca4eA6F392423b822898f3c1B129620161F5De7,0,,789720,metavault_v3 0xA219439258ca9da29E9Cc4cE5596924745e12B93/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 3000,0xA219439258ca9da29E9Cc4cE5596924745e12B93/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,metavault_v3,3000,0.003,0x9ca4eA6F392423b822898f3c1B129620161F5De7,,0xA219439258ca9da29E9Cc4cE5596924745e12B93,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,6,18,4,USDT,WETH,0,0,0,0,0,0,60,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x3724bE298654cc83b5273B89d33b3099baDb7b30,0,,789753,metavault_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b 3000,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b,metavault_v3,3000,0.003,0x3724bE298654cc83b5273B89d33b3099baDb7b30,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4,6,8,4,USDC,WBTC,0,0,0,0,0,0,60,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x1f9e7Ef95956D6100Edd22be633C819AEcb9b7BE,0,,789771,metavault_v3 0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4/0xA219439258ca9da29E9Cc4cE5596924745e12B9 3000,0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4/0xA219439258ca9da29E9Cc4cE5596924745e12B9,metavault_v3,3000,0.003,0x1f9e7Ef95956D6100Edd22be633C819AEcb9b7BE,,0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4,0xA219439258ca9da29E9Cc4cE5596924745e12B93,8,6,4,WBTC,USDT,0,0,0,0,0,0,60,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x2848973568Af7c89DaC4321Cb3c270A49ed242CC,0,,789954,metavault_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xA219439258ca9da29E9Cc4cE5596924745e12B9 100,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xA219439258ca9da29E9Cc4cE5596924745e12B9,metavault_v3,100,0.0001,0x2848973568Af7c89DaC4321Cb3c270A49ed242CC,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0xA219439258ca9da29E9Cc4cE5596924745e12B93,6,6,4,USDC,USDT,0,0,0,0,0,0,1,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x3E37ED1945eEdB33558FD29C303b59B079d1a0dc,0,,790334,metavault_v3 0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 3000,0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,metavault_v3,3000,0.003,0x3E37ED1945eEdB33558FD29C303b59B079d1a0dc,,0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,8,18,4,WBTC,WETH,0,0,0,0,0,0,60,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xa99CD4E87b9acAc403540F90Db07c9507540f965,0,,838931,metavault_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,metavault_v3,500,0.0005,0xa99CD4E87b9acAc403540F90Db07c9507540f965,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,6,18,4,USDC,WETH,0,0,0,0,0,0,10,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x66b119Aa96A89B1389726CbED7D0AE651A6C82aF,0,,870522,metavault_v3 0xA219439258ca9da29E9Cc4cE5596924745e12B93/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0xA219439258ca9da29E9Cc4cE5596924745e12B93/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,metavault_v3,500,0.0005,0x66b119Aa96A89B1389726CbED7D0AE651A6C82aF,,0xA219439258ca9da29E9Cc4cE5596924745e12B93,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,6,18,4,USDT,WETH,0,0,0,0,0,0,10,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x7297DE153902De72b006B8925413619c895Fa01B,0,,906542,metavault_v3 0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5/0xA219439258ca9da29E9Cc4cE5596924745e12B9 500,0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5/0xA219439258ca9da29E9Cc4cE5596924745e12B9,metavault_v3,500,0.0005,0x7297DE153902De72b006B8925413619c895Fa01B,,0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5,0xA219439258ca9da29E9Cc4cE5596924745e12B93,18,6,4,DAI,USDT,0,0,0,0,0,0,10,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x45390981D05d762510ff360bb401154303B710a7,0,,1076966,metavault_v3 0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,metavault_v3,500,0.0005,0x45390981D05d762510ff360bb401154303B710a7,,0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,8,18,4,WBTC,WETH,0,0,0,0,0,0,10,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xd177f0225Ff602B8D23B30eec8B641190E11B190,0,,1098490,metavault_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 100,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,metavault_v3,100,0.0001,0xd177f0225Ff602B8D23B30eec8B641190E11B190,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,6,18,4,USDC,WETH,0,0,0,0,0,0,1,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xF0a58649DB533Ac138E41Ae5A4869F10Af461DA8,0,,1157801,metavault_v3 0x5471ea8f739dd37E9B81Be9c5c77754D8AA953E4/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0x5471ea8f739dd37E9B81Be9c5c77754D8AA953E4/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,metavault_v3,500,0.0005,0xF0a58649DB533Ac138E41Ae5A4869F10Af461DA8,,0x5471ea8f739dd37E9B81Be9c5c77754D8AA953E4,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,WAVAX,WETH,0,0,0,0,0,0,10,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x9b531d28289EA4a1ec37eD563ac43955CEF809a5,0,,1167586,metavault_v3 0x93F4d0ab6a8B4271f4a28Db399b5E30612D21116/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0x93F4d0ab6a8B4271f4a28Db399b5E30612D21116/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,metavault_v3,500,0.0005,0x9b531d28289EA4a1ec37eD563ac43955CEF809a5,,0x93F4d0ab6a8B4271f4a28Db399b5E30612D21116,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,STONE,WETH,0,0,0,0,0,0,10,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x84e9251D4ca44304e4C5E98327D32777db8ea4B0,0,,1263816,metavault_v3 0xA219439258ca9da29E9Cc4cE5596924745e12B93/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 100,0xA219439258ca9da29E9Cc4cE5596924745e12B93/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,metavault_v3,100,0.0001,0x84e9251D4ca44304e4C5E98327D32777db8ea4B0,,0xA219439258ca9da29E9Cc4cE5596924745e12B93,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,6,18,4,USDT,WETH,0,0,0,0,0,0,1,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xD6F1e4d5Be885D43DC4177f3aB285A4d0D430017,0,,2098877,metavault_v3 0x0018D96C579121a94307249d47F053E2D687b5e7/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x0018D96C579121a94307249d47F053E2D687b5e7/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,metavault_v3,10000,0.01,0xD6F1e4d5Be885D43DC4177f3aB285A4d0D430017,,0x0018D96C579121a94307249d47F053E2D687b5e7,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,MVX,WETH,0,0,0,0,0,0,200,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x3b5A9fe99E401C2C9e2336E7524C3993366A8491,0,,2864077,metavault_v3 0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 3000,0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,metavault_v3,3000,0.003,0x3b5A9fe99E401C2C9e2336E7524C3993366A8491,,0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,wstETH,WETH,0,0,0,0,0,0,60,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x05C5F5bF992051D7Ec686726b8AD814f2D0ADd25,0,,2975630,metavault_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8 3000,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8,metavault_v3,3000,0.003,0x05C5F5bF992051D7Ec686726b8AD814f2D0ADd25,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F,6,18,4,USDC,wstETH,0,0,0,0,0,0,60,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xDdBE0e16536D3257E5609f30BF0880D5C13A6B9b,0,,3090237,metavault_v3 0xA219439258ca9da29E9Cc4cE5596924745e12B93/0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8 3000,0xA219439258ca9da29E9Cc4cE5596924745e12B93/0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8,metavault_v3,3000,0.003,0xDdBE0e16536D3257E5609f30BF0880D5C13A6B9b,,0xA219439258ca9da29E9Cc4cE5596924745e12B93,0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F,6,18,4,USDT,wstETH,0,0,0,0,0,0,60,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xE9c8ab71A62649A95F0B6793C0bb9bb6157079f4,0,,3194529,metavault_v3 0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4/0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8 3000,0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4/0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8,metavault_v3,3000,0.003,0xE9c8ab71A62649A95F0B6793C0bb9bb6157079f4,,0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4,0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F,8,18,4,WBTC,wstETH,0,0,0,0,0,0,60,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xeaF6fa74b16E229a20C239276B5199ba871aE3a3,0,,3699722,metavault_v3 0xB97F21D1f2508fF5c73E7B5AF02847640B1ff75d/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0xB97F21D1f2508fF5c73E7B5AF02847640B1ff75d/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,metavault_v3,500,0.0005,0xeaF6fa74b16E229a20C239276B5199ba871aE3a3,,0xB97F21D1f2508fF5c73E7B5AF02847640B1ff75d,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,LAB,WETH,0,0,0,0,0,0,10,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x0320520CaFcef95776912e9030170573fb47DC3B,0,,3706265,metavault_v3 0x60D01EC2D5E98Ac51C8B4cF84DfCCE98D527c747/0xA219439258ca9da29E9Cc4cE5596924745e12B9 500,0x60D01EC2D5E98Ac51C8B4cF84DfCCE98D527c747/0xA219439258ca9da29E9Cc4cE5596924745e12B9,metavault_v3,500,0.0005,0x0320520CaFcef95776912e9030170573fb47DC3B,,0x60D01EC2D5E98Ac51C8B4cF84DfCCE98D527c747,0xA219439258ca9da29E9Cc4cE5596924745e12B93,18,6,4,IZI,USDT,0,0,0,0,0,0,10,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xcC8eBB7BB51D78b03E15971f7c4BdD9a0fD9fA85,0,,3963300,metavault_v3 0x1a51b19CE03dbE0Cb44C1528E34a7EDD7771E9Af/0x63349BA5E1F71252eCD56E8F950D1A518B400b6 3000,0x1a51b19CE03dbE0Cb44C1528E34a7EDD7771E9Af/0x63349BA5E1F71252eCD56E8F950D1A518B400b6,metavault_v3,3000,0.003,0xcC8eBB7BB51D78b03E15971f7c4BdD9a0fD9fA85,,0x1a51b19CE03dbE0Cb44C1528E34a7EDD7771E9Af,0x63349BA5E1F71252eCD56E8F950D1A518B400b60,18,18,4,LYNX,oLYNX,0,0,0,0,0,0,60,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x2057f8B47C249b3a14D8F2E204Ca620a8bf0d470,0,,3971537,metavault_v3 0x1a51b19CE03dbE0Cb44C1528E34a7EDD7771E9Af/0x63349BA5E1F71252eCD56E8F950D1A518B400b6 10000,0x1a51b19CE03dbE0Cb44C1528E34a7EDD7771E9Af/0x63349BA5E1F71252eCD56E8F950D1A518B400b6,metavault_v3,10000,0.01,0x2057f8B47C249b3a14D8F2E204Ca620a8bf0d470,,0x1a51b19CE03dbE0Cb44C1528E34a7EDD7771E9Af,0x63349BA5E1F71252eCD56E8F950D1A518B400b60,18,18,4,LYNX,oLYNX,0,0,0,0,0,0,200,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x1A3a6427E6edC6f66473DA61c84a624587F27252,0,,4071214,metavault_v3 0xbAACD8E57387eB5db90229c312F0e867f66041D0/0xe9945Bab095157E632BCd0605c8ED8d9BAfd639 500,0xbAACD8E57387eB5db90229c312F0e867f66041D0/0xe9945Bab095157E632BCd0605c8ED8d9BAfd639,metavault_v3,500,0.0005,0x1A3a6427E6edC6f66473DA61c84a624587F27252,,0xbAACD8E57387eB5db90229c312F0e867f66041D0,0xe9945Bab095157E632BCd0605c8ED8d9BAfd639D,18,18,4,MANA,LINA,0,0,0,0,0,0,10,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x29Cc66f0c2dd8f368273098b5256dDD1E53e8880,0,,4071397,metavault_v3 0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xe9945Bab095157E632BCd0605c8ED8d9BAfd639 500,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xe9945Bab095157E632BCd0605c8ED8d9BAfd639,metavault_v3,500,0.0005,0x29Cc66f0c2dd8f368273098b5256dDD1E53e8880,,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,0xe9945Bab095157E632BCd0605c8ED8d9BAfd639D,18,18,4,WETH,LINA,0,0,0,0,0,0,10,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x41F8FC661862468D1eec22588DF4C5f24Ce194DC,0,,4071406,metavault_v3 0xbAACD8E57387eB5db90229c312F0e867f66041D0/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0xbAACD8E57387eB5db90229c312F0e867f66041D0/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,metavault_v3,500,0.0005,0x41F8FC661862468D1eec22588DF4C5f24Ce194DC,,0xbAACD8E57387eB5db90229c312F0e867f66041D0,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,MANA,WETH,0,0,0,0,0,0,10,metavault_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xA9A1Fb9F6664A0B6BFB1F52724fd7b23842248C5,0,,2967911,nile_v2 0x2416092f143378750bb29b79eD961ab195CcEea5/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,0x2416092f143378750bb29b79eD961ab195CcEea5/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,nile_v2,0.0001,0.0001,0xA9A1Fb9F6664A0B6BFB1F52724fd7b23842248C5,,0x2416092f143378750bb29b79eD961ab195CcEea5,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,3,EZETH,WETH,0,0,0,,,,,nile_v2,stable,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xAb87191e323fa2F42a5Ace5735644bdF15b64658,0,,1468,pancakeswap_v3 0x32226588378236Fd0c7c4053999F88aC0e5cAc77/0x3652Fc6EDcbD76161b8554388867d3dAb65eCA9 100,0x32226588378236Fd0c7c4053999F88aC0e5cAc77/0x3652Fc6EDcbD76161b8554388867d3dAb65eCA9,pancakeswap_v3,100,0.0001,0xAb87191e323fa2F42a5Ace5735644bdF15b64658,,0x32226588378236Fd0c7c4053999F88aC0e5cAc77,0x3652Fc6EDcbD76161b8554388867d3dAb65eCA93,18,18,4,A,B,0,0,0,0,0,0,1,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xd5539D0360438a66661148c633A9F0965E482845,0,,260063,pancakeswap_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,500,0.0005,0xd5539D0360438a66661148c633A9F0965E482845,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,6,18,4,USDC,WETH,0,0,0,0,0,0,10,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x86f3336AD51501bd3187771E05B08Bd58c346644,0,,273597,pancakeswap_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 2500,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,2500,0.0025,0x86f3336AD51501bd3187771E05B08Bd58c346644,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,6,18,4,USDC,WETH,0,0,0,0,0,0,50,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x586733678b9aC9Da43dD7CB83bbB41d23677Dfc3,0,,273769,pancakeswap_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 100,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,100,0.0001,0x586733678b9aC9Da43dD7CB83bbB41d23677Dfc3,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,6,18,4,USDC,WETH,0,0,0,0,0,0,1,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x37613Ae9371C7ce78d544516DEA2379E2653BA2D,0,,274238,pancakeswap_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xA219439258ca9da29E9Cc4cE5596924745e12B9 500,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xA219439258ca9da29E9Cc4cE5596924745e12B9,pancakeswap_v3,500,0.0005,0x37613Ae9371C7ce78d544516DEA2379E2653BA2D,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0xA219439258ca9da29E9Cc4cE5596924745e12B93,6,6,4,USDC,USDT,0,0,0,0,0,0,10,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x6a72F4F191720c411Cd1fF6A5EA8DeDEC3A64771,0,,287028,pancakeswap_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xA219439258ca9da29E9Cc4cE5596924745e12B9 100,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xA219439258ca9da29E9Cc4cE5596924745e12B9,pancakeswap_v3,100,0.0001,0x6a72F4F191720c411Cd1fF6A5EA8DeDEC3A64771,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0xA219439258ca9da29E9Cc4cE5596924745e12B93,6,6,4,USDC,USDT,0,0,0,0,0,0,1,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x42c9e266b226bbF0B11c14416FaaBFce29C96B78,0,,287687,pancakeswap_v3 0xA219439258ca9da29E9Cc4cE5596924745e12B93/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0xA219439258ca9da29E9Cc4cE5596924745e12B93/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,10000,0.01,0x42c9e266b226bbF0B11c14416FaaBFce29C96B78,,0xA219439258ca9da29E9Cc4cE5596924745e12B93,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,6,18,4,USDT,WETH,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xA48E0630B7b9dCb250112143C9D0fe47d26CB1e4,0,,295206,pancakeswap_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d 100,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d,pancakeswap_v3,100,0.0001,0xA48E0630B7b9dCb250112143C9D0fe47d26CB1e4,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5,6,18,4,USDC,DAI,0,0,0,0,0,0,1,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xbD3bc396C9393e63bBc935786Dd120B17F58Df4c,0,,295208,pancakeswap_v3 0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,500,0.0005,0xbD3bc396C9393e63bBc935786Dd120B17F58Df4c,,0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,8,18,4,WBTC,WETH,0,0,0,0,0,0,10,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x77eAeCAb5E71FA069a060637075063C521c44ecA,0,,312139,pancakeswap_v3 0x0D1E753a25eBda689453309112904807625bEFBe/0x176211869cA2b568f2A7D4EE941E073a821EE1f 10000,0x0D1E753a25eBda689453309112904807625bEFBe/0x176211869cA2b568f2A7D4EE941E073a821EE1f,pancakeswap_v3,10000,0.01,0x77eAeCAb5E71FA069a060637075063C521c44ecA,,0x0D1E753a25eBda689453309112904807625bEFBe,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,18,6,4,Cake,USDC,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x25F0A7aea13e75E8DC8F15481158FAE7d61a1560,0,,321614,pancakeswap_v3 0x0D1E753a25eBda689453309112904807625bEFBe/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 100,0x0D1E753a25eBda689453309112904807625bEFBe/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,100,0.0001,0x25F0A7aea13e75E8DC8F15481158FAE7d61a1560,,0x0D1E753a25eBda689453309112904807625bEFBe,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,Cake,WETH,0,0,0,0,0,0,1,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xE817A59F8A030544Ff65F47536abA272F6d63059,0,,328070,pancakeswap_v3 0x0D1E753a25eBda689453309112904807625bEFBe/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x0D1E753a25eBda689453309112904807625bEFBe/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,10000,0.01,0xE817A59F8A030544Ff65F47536abA272F6d63059,,0x0D1E753a25eBda689453309112904807625bEFBe,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,Cake,WETH,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x116a59c17b94eEd07b7BEC70A490c3DfFCCf98db,0,,340187,pancakeswap_v3 0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 2500,0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,2500,0.0025,0x116a59c17b94eEd07b7BEC70A490c3DfFCCf98db,,0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,DAI,WETH,0,0,0,0,0,0,50,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xF778209441dE096657A8f50f2253Af321Db3d0E8,0,,341268,pancakeswap_v3 0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4/0xA219439258ca9da29E9Cc4cE5596924745e12B9 2500,0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4/0xA219439258ca9da29E9Cc4cE5596924745e12B9,pancakeswap_v3,2500,0.0025,0xF778209441dE096657A8f50f2253Af321Db3d0E8,,0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4,0xA219439258ca9da29E9Cc4cE5596924745e12B93,8,6,4,WBTC,USDT,0,0,0,0,0,0,50,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xBB1261B00d8a082cf11405675E9eE772FA9b3621,0,,360820,pancakeswap_v3 0xC935B31C345D59A2396F7fEaC277FC1C981abC38/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0xC935B31C345D59A2396F7fEaC277FC1C981abC38/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,10000,0.01,0xBB1261B00d8a082cf11405675E9eE772FA9b3621,,0xC935B31C345D59A2396F7fEaC277FC1C981abC38,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,LNU,WETH,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xB59CB56330d1FC5c6240b8C7fc2DbEB09fD7a5dB,0,,374819,pancakeswap_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b 500,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b,pancakeswap_v3,500,0.0005,0xB59CB56330d1FC5c6240b8C7fc2DbEB09fD7a5dB,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4,6,8,4,USDC,WBTC,0,0,0,0,0,0,10,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xBA07B94b83774BE315f248dD6567F94B20405efE,0,,401768,pancakeswap_v3 0x0D1E753a25eBda689453309112904807625bEFBe/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0x0D1E753a25eBda689453309112904807625bEFBe/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,500,0.0005,0xBA07B94b83774BE315f248dD6567F94B20405efE,,0x0D1E753a25eBda689453309112904807625bEFBe,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,Cake,WETH,0,0,0,0,0,0,10,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x12d4AA3e6c8E73574d03bC007a25721a1C7C6871,0,,401778,pancakeswap_v3 0x0D1E753a25eBda689453309112904807625bEFBe/0x176211869cA2b568f2A7D4EE941E073a821EE1f 100,0x0D1E753a25eBda689453309112904807625bEFBe/0x176211869cA2b568f2A7D4EE941E073a821EE1f,pancakeswap_v3,100,0.0001,0x12d4AA3e6c8E73574d03bC007a25721a1C7C6871,,0x0D1E753a25eBda689453309112904807625bEFBe,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,18,6,4,Cake,USDC,0,0,0,0,0,0,1,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xc72a9E1A8f751776d6579405791e84DFC2a76057,0,,402631,pancakeswap_v3 0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xf1E11408b29611c03E242244A3f37ACF66C2e3f 2500,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xf1E11408b29611c03E242244A3f37ACF66C2e3f,pancakeswap_v3,2500,0.0025,0xc72a9E1A8f751776d6579405791e84DFC2a76057,,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,0xf1E11408b29611c03E242244A3f37ACF66C2e3fe,18,18,4,WETH,LEDG,0,0,0,0,0,0,50,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xe555Cc5c593ee5ab0006d8D7d98E311f0c72197c,0,,464805,pancakeswap_v3 0x02e47D464c3bB564964fce162e6c8F38eA744f5a/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x02e47D464c3bB564964fce162e6c8F38eA744f5a/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,10000,0.01,0xe555Cc5c593ee5ab0006d8D7d98E311f0c72197c,,0x02e47D464c3bB564964fce162e6c8F38eA744f5a,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,TV,WETH,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x32Cb485D5840a7Ce79a33E307a6FFa3E3560e54F,0,,503996,pancakeswap_v3 0x02e47D464c3bB564964fce162e6c8F38eA744f5a/0xcc22F6AA610D1b2a0e89EF228079cB3e1831b1D 10000,0x02e47D464c3bB564964fce162e6c8F38eA744f5a/0xcc22F6AA610D1b2a0e89EF228079cB3e1831b1D,pancakeswap_v3,10000,0.01,0x32Cb485D5840a7Ce79a33E307a6FFa3E3560e54F,,0x02e47D464c3bB564964fce162e6c8F38eA744f5a,0xcc22F6AA610D1b2a0e89EF228079cB3e1831b1D1,18,18,4,TV,LVC,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x852dD3e3f40a5658ccB7a90C6798cF2a5DCB6F7f,0,,513776,pancakeswap_v3 0xcc22F6AA610D1b2a0e89EF228079cB3e1831b1D1/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0xcc22F6AA610D1b2a0e89EF228079cB3e1831b1D1/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,10000,0.01,0x852dD3e3f40a5658ccB7a90C6798cF2a5DCB6F7f,,0xcc22F6AA610D1b2a0e89EF228079cB3e1831b1D1,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,LVC,WETH,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xB90dFef14BA53666090fF1926c46Be00Cb40619F,0,,534869,pancakeswap_v3 0x0D1E753a25eBda689453309112904807625bEFBe/0xA219439258ca9da29E9Cc4cE5596924745e12B9 10000,0x0D1E753a25eBda689453309112904807625bEFBe/0xA219439258ca9da29E9Cc4cE5596924745e12B9,pancakeswap_v3,10000,0.01,0xB90dFef14BA53666090fF1926c46Be00Cb40619F,,0x0D1E753a25eBda689453309112904807625bEFBe,0xA219439258ca9da29E9Cc4cE5596924745e12B93,18,6,4,Cake,USDT,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xfA9833196a930729b82E124fdB5708F16c1b8B5d,0,,551050,pancakeswap_v3 0x246c82fD3798Af4cc38973c429C18e807016a4BD/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0x246c82fD3798Af4cc38973c429C18e807016a4BD/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,500,0.0005,0xfA9833196a930729b82E124fdB5708F16c1b8B5d,,0x246c82fD3798Af4cc38973c429C18e807016a4BD,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,TM,WETH,0,0,0,0,0,0,10,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x4C39bc30daCD5339D916486E68EcB67B4341e569,0,,559101,pancakeswap_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x808d7c71ad2ba3FA531b068a2417C63106BC094 10000,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x808d7c71ad2ba3FA531b068a2417C63106BC094,pancakeswap_v3,10000,0.01,0x4C39bc30daCD5339D916486E68EcB67B4341e569,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0x808d7c71ad2ba3FA531b068a2417C63106BC0949,6,18,4,USDC,STG,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xE99d539b903E9bf24e01342034F4c1C3419018b0,0,,609481,pancakeswap_v3 0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 2500,0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,2500,0.0025,0xE99d539b903E9bf24e01342034F4c1C3419018b0,,0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,8,18,4,WBTC,WETH,0,0,0,0,0,0,50,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xBC0e1B76F21b04114de725583FF213b3134B2E6E,0,,612764,pancakeswap_v3 0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5/0xA219439258ca9da29E9Cc4cE5596924745e12B9 500,0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5/0xA219439258ca9da29E9Cc4cE5596924745e12B9,pancakeswap_v3,500,0.0005,0xBC0e1B76F21b04114de725583FF213b3134B2E6E,,0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5,0xA219439258ca9da29E9Cc4cE5596924745e12B93,18,6,4,DAI,USDT,0,0,0,0,0,0,10,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x5cC5495075931AEb1FC9A7F76B29C6317b6040c9,0,,612781,pancakeswap_v3 0x0D1E753a25eBda689453309112904807625bEFBe/0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d 2500,0x0D1E753a25eBda689453309112904807625bEFBe/0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d,pancakeswap_v3,2500,0.0025,0x5cC5495075931AEb1FC9A7F76B29C6317b6040c9,,0x0D1E753a25eBda689453309112904807625bEFBe,0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5,18,18,4,Cake,DAI,0,0,0,0,0,0,50,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x74EC66075A71CFB1b223F10beFA99f7bEE6D3946,0,,639994,pancakeswap_v3 0x2314342912d9968fd3B40a542Bdb1fC6b918f35E/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0x2314342912d9968fd3B40a542Bdb1fC6b918f35E/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,500,0.0005,0x74EC66075A71CFB1b223F10beFA99f7bEE6D3946,,0x2314342912d9968fd3B40a542Bdb1fC6b918f35E,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,$MENDI,WETH,0,0,0,0,0,0,10,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x85164B6d8a74bA481AB6D02D2C4e779ECCBAF982,0,,658564,pancakeswap_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xEB466342C4d449BC9f53A865D5Cb90586f40521 100,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xEB466342C4d449BC9f53A865D5Cb90586f40521,pancakeswap_v3,100,0.0001,0x85164B6d8a74bA481AB6D02D2C4e779ECCBAF982,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0xEB466342C4d449BC9f53A865D5Cb90586f405215,6,6,4,USDC,AXLUSDC,0,0,0,0,0,0,1,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x5089E61e6c71D118790793ad78Fa98327e240359,0,,875694,pancakeswap_v3 0x8cE74e606481BBC7078aF4781f9eB67afC85a0Ce/0xA219439258ca9da29E9Cc4cE5596924745e12B9 100,0x8cE74e606481BBC7078aF4781f9eB67afC85a0Ce/0xA219439258ca9da29E9Cc4cE5596924745e12B9,pancakeswap_v3,100,0.0001,0x5089E61e6c71D118790793ad78Fa98327e240359,,0x8cE74e606481BBC7078aF4781f9eB67afC85a0Ce,0xA219439258ca9da29E9Cc4cE5596924745e12B93,18,6,4,stETH,USDT,0,0,0,0,0,0,1,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xD043EefA7554fe85f84521963331320EC6BdCd26,0,,933283,pancakeswap_v3 0x808d7c71ad2ba3FA531b068a2417C63106BC0949/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x808d7c71ad2ba3FA531b068a2417C63106BC0949/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,10000,0.01,0xD043EefA7554fe85f84521963331320EC6BdCd26,,0x808d7c71ad2ba3FA531b068a2417C63106BC0949,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,STG,WETH,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x811a565985669A1303b173C76CE3EFdf1Ec77aa3,0,,942810,pancakeswap_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x2F0b4300074aFC01726262d4cc9c1D2619d7297 500,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x2F0b4300074aFC01726262d4cc9c1D2619d7297,pancakeswap_v3,500,0.0005,0x811a565985669A1303b173C76CE3EFdf1Ec77aa3,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0x2F0b4300074aFC01726262d4cc9c1D2619d7297a,6,18,4,USDC,WUSK,0,0,0,0,0,0,10,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x33DB696Ef1f3080b846B28f1a890879cd6Df0a7D,0,,1043558,pancakeswap_v3 0x41b94c5867f7F6217C9a30520Cb3e793B1ee1b97/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x41b94c5867f7F6217C9a30520Cb3e793B1ee1b97/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,10000,0.01,0x33DB696Ef1f3080b846B28f1a890879cd6Df0a7D,,0x41b94c5867f7F6217C9a30520Cb3e793B1ee1b97,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,6,18,4,axlTIA,WETH,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x3f63a467C54c96538bD36A7DF1b9E7C4719DcaC9,0,,1067145,pancakeswap_v3 0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 100,0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,100,0.0001,0x3f63a467C54c96538bD36A7DF1b9E7C4719DcaC9,,0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,wstETH,WETH,0,0,0,0,0,0,1,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x479efE59d00d5064B4170f1705D444448623cEf4,0,,1241270,pancakeswap_v3 0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xf5C6825015280CdfD0b56903F9F8B5A2233476F 10000,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xf5C6825015280CdfD0b56903F9F8B5A2233476F,pancakeswap_v3,10000,0.01,0x479efE59d00d5064B4170f1705D444448623cEf4,,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,0xf5C6825015280CdfD0b56903F9F8B5A2233476F5,18,18,4,WETH,WBNB,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xf84d0dB5DFb6eAE50951607749d8b16B26F6F929,0,,1408235,pancakeswap_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8 10000,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8,pancakeswap_v3,10000,0.01,0xf84d0dB5DFb6eAE50951607749d8b16B26F6F929,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F,6,18,4,USDC,wstETH,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xbc2EE5e6535d25aEE9A90ef33E7E80A4145E064a,0,,2356666,pancakeswap_v3 0x1bE3735Dd0C0Eb229fB11094B6c277192349EBbf/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x1bE3735Dd0C0Eb229fB11094B6c277192349EBbf/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,10000,0.01,0xbc2EE5e6535d25aEE9A90ef33E7E80A4145E064a,,0x1bE3735Dd0C0Eb229fB11094B6c277192349EBbf,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,LUBE,WETH,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xAdc1D10eDA12F36792b5ea3902b6b6c0dDb58060,0,,2421084,pancakeswap_v3 0x21d624c846725ABe1e1e7d662E9fB274999009Aa/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x21d624c846725ABe1e1e7d662E9fB274999009Aa/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,10000,0.01,0xAdc1D10eDA12F36792b5ea3902b6b6c0dDb58060,,0x21d624c846725ABe1e1e7d662E9fB274999009Aa,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,CRYSTAL,WETH,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x90375306810C6E8B2efa8294835C78B499D7c691,0,,2525920,pancakeswap_v3 0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,500,0.0005,0x90375306810C6E8B2efa8294835C78B499D7c691,,0xB5beDd42000b71FddE22D3eE8a79Bd49A568fC8F,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,wstETH,WETH,0,0,0,0,0,0,10,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xc014414696F332C96C471634620344143325D2C0,0,,2542229,pancakeswap_v3 0xA219439258ca9da29E9Cc4cE5596924745e12B93/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0xA219439258ca9da29E9Cc4cE5596924745e12B93/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,500,0.0005,0xc014414696F332C96C471634620344143325D2C0,,0xA219439258ca9da29E9Cc4cE5596924745e12B93,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,6,18,4,USDT,WETH,0,0,0,0,0,0,10,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x5AFda31027C3E6A03c77a113FFC031B564AbbF05,0,,2561630,pancakeswap_v3 0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 100,0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,100,0.0001,0x5AFda31027C3E6A03c77a113FFC031B564AbbF05,,0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,8,18,4,WBTC,WETH,0,0,0,0,0,0,1,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xb62ca7B0FFD46584b72b697a96524EA5426ae8F0,0,,2674814,pancakeswap_v3 0x1C7F152e3dB82F92C0e4446A2922975E5d0eFCfE/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0x1C7F152e3dB82F92C0e4446A2922975E5d0eFCfE/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,500,0.0005,0xb62ca7B0FFD46584b72b697a96524EA5426ae8F0,,0x1C7F152e3dB82F92C0e4446A2922975E5d0eFCfE,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,SCB,WETH,0,0,0,0,0,0,10,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x24A5f822C39bC28d7BAD70F78D267ac619C99A6c,0,,2733685,pancakeswap_v3 0x4Fa0dE5d9217722A37247808c08Cde1C976879b9/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x4Fa0dE5d9217722A37247808c08Cde1C976879b9/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,10000,0.01,0x24A5f822C39bC28d7BAD70F78D267ac619C99A6c,,0x4Fa0dE5d9217722A37247808c08Cde1C976879b9,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,LUCIA,WETH,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x21C7eB0B952809F8146D60d5D6b91E748bae74A6,0,,2772543,pancakeswap_v3 0x0A224Fa31903Bd0AF7b985DD7c07f6806C4b81a6/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x0A224Fa31903Bd0AF7b985DD7c07f6806C4b81a6/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,10000,0.01,0x21C7eB0B952809F8146D60d5D6b91E748bae74A6,,0x0A224Fa31903Bd0AF7b985DD7c07f6806C4b81a6,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,ZOOMER,WETH,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xa93F1c84B74e0bB2345C92118eB2276f8F9f59d5,0,,2818098,pancakeswap_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x617FeED96d21F938Da4e725e8D460af6De2FaFe 500,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x617FeED96d21F938Da4e725e8D460af6De2FaFe,pancakeswap_v3,500,0.0005,0xa93F1c84B74e0bB2345C92118eB2276f8F9f59d5,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0x617FeED96d21F938Da4e725e8D460af6De2FaFe0,6,18,4,USDC,Wrapped BTC,0,0,0,0,0,0,10,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x1947B87d35E9f1cd53CEDe1aD6F7be44C12212B8,0,,2862693,pancakeswap_v3 0xA219439258ca9da29E9Cc4cE5596924745e12B93/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 100,0xA219439258ca9da29E9Cc4cE5596924745e12B93/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,100,0.0001,0x1947B87d35E9f1cd53CEDe1aD6F7be44C12212B8,,0xA219439258ca9da29E9Cc4cE5596924745e12B93,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,6,18,4,USDT,WETH,0,0,0,0,0,0,1,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x20398c516B25A43cC9d8E2309Ca4ad35Ce2710F6,0,,2865294,pancakeswap_v3 0x98b6D1ebae3B228e5D947f14dA602Ac16f7ee60B/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0x98b6D1ebae3B228e5D947f14dA602Ac16f7ee60B/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,500,0.0005,0x20398c516B25A43cC9d8E2309Ca4ad35Ce2710F6,,0x98b6D1ebae3B228e5D947f14dA602Ac16f7ee60B,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,Linea Network,WETH,0,0,0,0,0,0,10,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x08DCab368C76CD5cB8269c5382F695229fF1cBE4,0,,3123406,pancakeswap_v3 0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xEB466342C4d449BC9f53A865D5Cb90586f40521 10000,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xEB466342C4d449BC9f53A865D5Cb90586f40521,pancakeswap_v3,10000,0.01,0x08DCab368C76CD5cB8269c5382F695229fF1cBE4,,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,0xEB466342C4d449BC9f53A865D5Cb90586f405215,18,6,4,WETH,AXLUSDC,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xfDe733b5DE5B5a06C68353e01E4c1D3415C89560,0,,3144647,pancakeswap_v3 0x2416092f143378750bb29b79eD961ab195CcEea5/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0x2416092f143378750bb29b79eD961ab195CcEea5/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,500,0.0005,0xfDe733b5DE5B5a06C68353e01E4c1D3415C89560,,0x2416092f143378750bb29b79eD961ab195CcEea5,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,EZETH,WETH,0,0,0,0,0,0,10,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x024c4c6fcE11C45C1D661033822EAe0D0Bc96615,0,,3233157,pancakeswap_v3 0x2598c30330D5771AE9F983979209486aE26dE875/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x2598c30330D5771AE9F983979209486aE26dE875/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,10000,0.01,0x024c4c6fcE11C45C1D661033822EAe0D0Bc96615,,0x2598c30330D5771AE9F983979209486aE26dE875,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,AI,WETH,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xF6a295bf3fD7E55A4A61724C7fd4f0A598fd3093,0,,3520453,pancakeswap_v3 0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xEB466342C4d449BC9f53A865D5Cb90586f40521 100,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xEB466342C4d449BC9f53A865D5Cb90586f40521,pancakeswap_v3,100,0.0001,0xF6a295bf3fD7E55A4A61724C7fd4f0A598fd3093,,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,0xEB466342C4d449BC9f53A865D5Cb90586f405215,18,6,4,WETH,AXLUSDC,0,0,0,0,0,0,1,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x3Ac591750A0D16A6dC03CeB8E0B0d135963F4b0b,0,,3575741,pancakeswap_v3 0xe026D1D034cCdDD1E7c2510e56B14fdcf3505c9e/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0xe026D1D034cCdDD1E7c2510e56B14fdcf3505c9e/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,500,0.0005,0x3Ac591750A0D16A6dC03CeB8E0B0d135963F4b0b,,0xe026D1D034cCdDD1E7c2510e56B14fdcf3505c9e,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,FOXY,WETH,0,0,0,0,0,0,10,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x158681DFDC01d29c2E9C35D45DCD6d5844bd2c81,0,,3603433,pancakeswap_v3 0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xeaBd9aD114F9FdEFf34a588618441D2aDcE6027 500,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xeaBd9aD114F9FdEFf34a588618441D2aDcE6027,pancakeswap_v3,500,0.0005,0x158681DFDC01d29c2E9C35D45DCD6d5844bd2c81,,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,0xeaBd9aD114F9FdEFf34a588618441D2aDcE60277,18,18,4,WETH,BLACKBONK,0,0,0,0,0,0,10,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x96F8d07B34e15c0f9338e79fD038F0f7A0C3a676,0,,3622291,pancakeswap_v3 0x5FBDF89403270a1846F5ae7D113A989F850d1566/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x5FBDF89403270a1846F5ae7D113A989F850d1566/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,10000,0.01,0x96F8d07B34e15c0f9338e79fD038F0f7A0C3a676,,0x5FBDF89403270a1846F5ae7D113A989F850d1566,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,FOXY,WETH,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xF36b19A9cA8D0302270531b950d5AAA3f3EFc34f,0,,3622617,pancakeswap_v3 0x5aEF68bB3DEB263F170219D0E53DFAae34776E65/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x5aEF68bB3DEB263F170219D0E53DFAae34776E65/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,10000,0.01,0xF36b19A9cA8D0302270531b950d5AAA3f3EFc34f,,0x5aEF68bB3DEB263F170219D0E53DFAae34776E65,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,FOXY,WETH,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x7fD09831872C4F927F6E10cE73F62Bf948413F70,0,,3623569,pancakeswap_v3 0x934ab820E87222F7BEddB3eb28bb2DEFcd5deFFf/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0x934ab820E87222F7BEddB3eb28bb2DEFcd5deFFf/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,500,0.0005,0x7fD09831872C4F927F6E10cE73F62Bf948413F70,,0x934ab820E87222F7BEddB3eb28bb2DEFcd5deFFf,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,FOXY,WETH,0,0,0,0,0,0,10,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x373536b76872ef323fC0e3b33Ea5fF9E76231393,0,,3623878,pancakeswap_v3 0x5FBDF89403270a1846F5ae7D113A989F850d1566/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 2500,0x5FBDF89403270a1846F5ae7D113A989F850d1566/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,2500,0.0025,0x373536b76872ef323fC0e3b33Ea5fF9E76231393,,0x5FBDF89403270a1846F5ae7D113A989F850d1566,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,FOXY,WETH,0,0,0,0,0,0,50,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x0b3110493911E53df8cb4048DC27A8251B912Ee7,0,,3623998,pancakeswap_v3 0x5FBDF89403270a1846F5ae7D113A989F850d1566/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0x5FBDF89403270a1846F5ae7D113A989F850d1566/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,500,0.0005,0x0b3110493911E53df8cb4048DC27A8251B912Ee7,,0x5FBDF89403270a1846F5ae7D113A989F850d1566,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,FOXY,WETH,0,0,0,0,0,0,10,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x1Df9587F03786Aa099Cf36ba64c9B1dCc5702b03,0,,3737793,pancakeswap_v3 0x5FBDF89403270a1846F5ae7D113A989F850d1566/0xA219439258ca9da29E9Cc4cE5596924745e12B9 10000,0x5FBDF89403270a1846F5ae7D113A989F850d1566/0xA219439258ca9da29E9Cc4cE5596924745e12B9,pancakeswap_v3,10000,0.01,0x1Df9587F03786Aa099Cf36ba64c9B1dCc5702b03,,0x5FBDF89403270a1846F5ae7D113A989F850d1566,0xA219439258ca9da29E9Cc4cE5596924745e12B93,18,6,4,FOXY,USDT,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x4cCb40a93d1529FAA48e8dB2cE3634D73D9feeB5,0,,3855031,pancakeswap_v3 0x2416092f143378750bb29b79eD961ab195CcEea5/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 100,0x2416092f143378750bb29b79eD961ab195CcEea5/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,100,0.0001,0x4cCb40a93d1529FAA48e8dB2cE3634D73D9feeB5,,0x2416092f143378750bb29b79eD961ab195CcEea5,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,EZETH,WETH,0,0,0,0,0,0,1,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xC9747FB2E06Da2085B7885e850f0cB5d0527F13A,0,,3885856,pancakeswap_v3 0x1a51b19CE03dbE0Cb44C1528E34a7EDD7771E9Af/0x63349BA5E1F71252eCD56E8F950D1A518B400b6 10000,0x1a51b19CE03dbE0Cb44C1528E34a7EDD7771E9Af/0x63349BA5E1F71252eCD56E8F950D1A518B400b6,pancakeswap_v3,10000,0.01,0xC9747FB2E06Da2085B7885e850f0cB5d0527F13A,,0x1a51b19CE03dbE0Cb44C1528E34a7EDD7771E9Af,0x63349BA5E1F71252eCD56E8F950D1A518B400b60,18,18,4,LYNX,oLYNX,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x1d3a3b759a55a49b0184F203695Cb5693A5b1aAe,0,,4070819,pancakeswap_v3 0xbAACD8E57387eB5db90229c312F0e867f66041D0/0xe9945Bab095157E632BCd0605c8ED8d9BAfd639 500,0xbAACD8E57387eB5db90229c312F0e867f66041D0/0xe9945Bab095157E632BCd0605c8ED8d9BAfd639,pancakeswap_v3,500,0.0005,0x1d3a3b759a55a49b0184F203695Cb5693A5b1aAe,,0xbAACD8E57387eB5db90229c312F0e867f66041D0,0xe9945Bab095157E632BCd0605c8ED8d9BAfd639D,18,18,4,MANA,LINA,0,0,0,0,0,0,10,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xCd1208e15D5b7f6106aEdbf8f9FC3b710843d208,0,,4070852,pancakeswap_v3 0x0D1E753a25eBda689453309112904807625bEFBe/0xbAACD8E57387eB5db90229c312F0e867f66041D 500,0x0D1E753a25eBda689453309112904807625bEFBe/0xbAACD8E57387eB5db90229c312F0e867f66041D,pancakeswap_v3,500,0.0005,0xCd1208e15D5b7f6106aEdbf8f9FC3b710843d208,,0x0D1E753a25eBda689453309112904807625bEFBe,0xbAACD8E57387eB5db90229c312F0e867f66041D0,18,18,4,Cake,MANA,0,0,0,0,0,0,10,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xaD98fffA1BA1BAA1BF87E190AA9B474fE75C4b07,0,,4070893,pancakeswap_v3 0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xe9945Bab095157E632BCd0605c8ED8d9BAfd639 500,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xe9945Bab095157E632BCd0605c8ED8d9BAfd639,pancakeswap_v3,500,0.0005,0xaD98fffA1BA1BAA1BF87E190AA9B474fE75C4b07,,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,0xe9945Bab095157E632BCd0605c8ED8d9BAfd639D,18,18,4,WETH,LINA,0,0,0,0,0,0,10,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xbc57ec102E3C87b19399e82e9287a61fa1135e16,0,,4233547,pancakeswap_v3 0x311eC870e3d7172896CA9f18145bAfc8902c9F3B/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x311eC870e3d7172896CA9f18145bAfc8902c9F3B/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,10000,0.01,0xbc57ec102E3C87b19399e82e9287a61fa1135e16,,0x311eC870e3d7172896CA9f18145bAfc8902c9F3B,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,BTBS,WETH,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xB6989edA09D1fD8D6C192Fd391e9964B918009f7,0,,4275652,pancakeswap_v3 0x636B22bC471c955A8DB60f28D4795066a8201fa3/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x636B22bC471c955A8DB60f28D4795066a8201fa3/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,pancakeswap_v3,10000,0.01,0xB6989edA09D1fD8D6C192Fd391e9964B918009f7,,0x636B22bC471c955A8DB60f28D4795066a8201fa3,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,UNI,WETH,0,0,0,0,0,0,200,pancakeswap_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x142eC7A60d2b339287c79969B1F3bfB1d81aF27f,0,,2390622,secta_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xA219439258ca9da29E9Cc4cE5596924745e12B9 100,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xA219439258ca9da29E9Cc4cE5596924745e12B9,secta_v3,100,0.0001,0x142eC7A60d2b339287c79969B1F3bfB1d81aF27f,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0xA219439258ca9da29E9Cc4cE5596924745e12B93,6,6,4,USDC,USDT,0,0,0,0,0,0,1,secta_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xe331A3A42Fd83A7f44dAeDC7bA212bDeB90Ecf7B,0,,2390738,secta_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 500,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,secta_v3,500,0.0005,0xe331A3A42Fd83A7f44dAeDC7bA212bDeB90Ecf7B,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,6,18,4,USDC,WETH,0,0,0,0,0,0,10,secta_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xE380ad455BF4def3faA94ce0Ff9a0184D8AE1105,0,,2410447,secta_v3 0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xfa1E8B0E8ef1C5F978C2885053D706cFB5e3582 2500,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xfa1E8B0E8ef1C5F978C2885053D706cFB5e3582,secta_v3,2500,0.0025,0xE380ad455BF4def3faA94ce0Ff9a0184D8AE1105,,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,0xfa1E8B0E8ef1C5F978C2885053D706cFB5e35822,18,18,4,WETH,NOW,0,0,0,0,0,0,50,secta_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xB3a65a05eC9dc3A0bb3b18E2F0cf6bb86CD6fdaC,0,,2411126,secta_v3 0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4/0xA219439258ca9da29E9Cc4cE5596924745e12B9 2500,0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4/0xA219439258ca9da29E9Cc4cE5596924745e12B9,secta_v3,2500,0.0025,0xB3a65a05eC9dc3A0bb3b18E2F0cf6bb86CD6fdaC,,0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4,0xA219439258ca9da29E9Cc4cE5596924745e12B93,8,6,4,WBTC,USDT,0,0,0,0,0,0,50,secta_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x3BBaebde931b7F0c9F431246Ea218D6d5404B1Cd,0,,2411647,secta_v3 0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4/0x7d43AABC515C356145049227CeE54B608342c0a 2500,0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4/0x7d43AABC515C356145049227CeE54B608342c0a,secta_v3,2500,0.0025,0x3BBaebde931b7F0c9F431246Ea218D6d5404B1Cd,,0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4,0x7d43AABC515C356145049227CeE54B608342c0ad,8,18,4,WBTC,BUSD,0,0,0,0,0,0,50,secta_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x9569da3d960905D3b81999005bcc4Fdfd397B3B3,0,,2412773,secta_v3 0x7d43AABC515C356145049227CeE54B608342c0ad/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 2500,0x7d43AABC515C356145049227CeE54B608342c0ad/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,secta_v3,2500,0.0025,0x9569da3d960905D3b81999005bcc4Fdfd397B3B3,,0x7d43AABC515C356145049227CeE54B608342c0ad,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,BUSD,WETH,0,0,0,0,0,0,50,secta_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xe7710034C34E5Cd72C90d1c93Ff2f9Bc6A409B95,0,,2557416,secta_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d 100,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d,secta_v3,100,0.0001,0xe7710034C34E5Cd72C90d1c93Ff2f9Bc6A409B95,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5,6,18,4,USDC,DAI,0,0,0,0,0,0,1,secta_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x2A7F1baEEf187494759770228A3Ac0ff0d5A5f32,0,,2566426,secta_v3 0x1bE3735Dd0C0Eb229fB11094B6c277192349EBbf/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x1bE3735Dd0C0Eb229fB11094B6c277192349EBbf/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,secta_v3,10000,0.01,0x2A7F1baEEf187494759770228A3Ac0ff0d5A5f32,,0x1bE3735Dd0C0Eb229fB11094B6c277192349EBbf,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,LUBE,WETH,0,0,0,0,0,0,200,secta_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xC34FA78eabFD8E0a788087C1a73276dF4284ffEd,0,,3221927,secta_v3 0x2Fab0952449378DfdF4625fE37F9603011F189ab/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x2Fab0952449378DfdF4625fE37F9603011F189ab/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,secta_v3,10000,0.01,0xC34FA78eabFD8E0a788087C1a73276dF4284ffEd,,0x2Fab0952449378DfdF4625fE37F9603011F189ab,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,LINE,WETH,0,0,0,0,0,0,200,secta_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xe358f3B4D360E21AE9E84E3d54535F89580eA2E4,0,,3222889,secta_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x2Fab0952449378DfdF4625fE37F9603011F189a 10000,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0x2Fab0952449378DfdF4625fE37F9603011F189a,secta_v3,10000,0.01,0xe358f3B4D360E21AE9E84E3d54535F89580eA2E4,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0x2Fab0952449378DfdF4625fE37F9603011F189ab,6,18,4,USDC,LINE,0,0,0,0,0,0,200,secta_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x907045EEcE2891AC0e9189191abb270d6c121855,0,,3326022,secta_v3 0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,secta_v3,10000,0.01,0x907045EEcE2891AC0e9189191abb270d6c121855,,0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,DAI,WETH,0,0,0,0,0,0,200,secta_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xa3C180264De6B0fD8650DDF214Ff56e42689Cf01,0,,3420074,secta_v3 0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x176211869cA2b568f2A7D4EE941E073a821EE1ff/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,secta_v3,10000,0.01,0xa3C180264De6B0fD8650DDF214Ff56e42689Cf01,,0x176211869cA2b568f2A7D4EE941E073a821EE1ff,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,6,18,4,USDC,WETH,0,0,0,0,0,0,200,secta_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x9cF211b421Af0953353Aef93544FC7224A05609C,0,,3511776,secta_v3 0x48119884e0cfCf90E4035CDCd98fDa4d21966465/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 10000,0x48119884e0cfCf90E4035CDCd98fDa4d21966465/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,secta_v3,10000,0.01,0x9cF211b421Af0953353Aef93544FC7224A05609C,,0x48119884e0cfCf90E4035CDCd98fDa4d21966465,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,AENIL,WETH,0,0,0,0,0,0,200,secta_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xAd6eF2B9aBcDA704Df43E5Bb79f87B6B6a8224d8,0,,3904581,secta_v3 0x43E8809ea748EFf3204ee01F08872F063e44065f/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34 2500,0x43E8809ea748EFf3204ee01F08872F063e44065f/0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34,secta_v3,2500,0.0025,0xAd6eF2B9aBcDA704Df43E5Bb79f87B6B6a8224d8,,0x43E8809ea748EFf3204ee01F08872F063e44065f,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,18,18,4,MENDI,WETH,0,0,0,0,0,0,50,secta_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x6619e72964Ff7F7a2CdE8D5e9232C8a75f258be1,0,,4190473,secta_v3 0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xEb477F63D11f51a46Bfa4e24106a435864b3247 10000,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f/0xEb477F63D11f51a46Bfa4e24106a435864b3247,secta_v3,10000,0.01,0x6619e72964Ff7F7a2CdE8D5e9232C8a75f258be1,,0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f,0xEb477F63D11f51a46Bfa4e24106a435864b32473,18,18,4,WETH,bETH,0,0,0,0,0,0,200,secta_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, diff --git a/fastlane_bot/data/blockchain_data/linea/tokens.csv b/fastlane_bot/data/blockchain_data/linea/tokens.csv index e6c2a4c29..d70fad27d 100644 --- a/fastlane_bot/data/blockchain_data/linea/tokens.csv +++ b/fastlane_bot/data/blockchain_data/linea/tokens.csv @@ -185,3 +185,10 @@ address,decimals,symbol 0x8C56017B172226fE024dEa197748FC1eaccC82B1,18,XFIT 0x1578f35532FA091EcED8638730F9dB829930ce16,18,agEUR 0xe7DC30E9Bc08A1Dd1a2909D0f0e1Af4539398F01,18,TFS +0x1Bf74C010E6320bab11e2e5A532b5AC15e0b8aA6,18,weETH +0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8,18,agEUR +0xF3829aF0C018c8c1685B3d3d33B21cC98935fC87,6,XHNY +0x8A16b95EA186FE2e0AD6eAb9efB764be7846c50f,18,TEUR +0x311eC870e3d7172896CA9f18145bAfc8902c9F3B,18,BTBS +0x636B22bC471c955A8DB60f28D4795066a8201fa3,18,UNI +0xEb477F63D11f51a46Bfa4e24106a435864b32473,18,bETH diff --git a/fastlane_bot/data/blockchain_data/linea/uniswap_v3_event_mappings.csv b/fastlane_bot/data/blockchain_data/linea/uniswap_v3_event_mappings.csv index f2ba9e27e..73f885762 100644 --- a/fastlane_bot/data/blockchain_data/linea/uniswap_v3_event_mappings.csv +++ b/fastlane_bot/data/blockchain_data/linea/uniswap_v3_event_mappings.csv @@ -155,3 +155,7 @@ secta_v3,0x907045EEcE2891AC0e9189191abb270d6c121855 secta_v3,0xa3C180264De6B0fD8650DDF214Ff56e42689Cf01 secta_v3,0x9cF211b421Af0953353Aef93544FC7224A05609C secta_v3,0xAd6eF2B9aBcDA704Df43E5Bb79f87B6B6a8224d8 +echodex_v3,0xe6a0C7e4C5BE6a217177800825B02371Ef072ecd +pancakeswap_v3,0xbc57ec102E3C87b19399e82e9287a61fa1135e16 +pancakeswap_v3,0xB6989edA09D1fD8D6C192Fd391e9964B918009f7 +secta_v3,0x6619e72964Ff7F7a2CdE8D5e9232C8a75f258be1 diff --git a/fastlane_bot/data/blockchain_data/mantle/solidly_v2_event_mappings.csv b/fastlane_bot/data/blockchain_data/mantle/solidly_v2_event_mappings.csv index 763fc2560..c57848fad 100644 --- a/fastlane_bot/data/blockchain_data/mantle/solidly_v2_event_mappings.csv +++ b/fastlane_bot/data/blockchain_data/mantle/solidly_v2_event_mappings.csv @@ -74,3 +74,4 @@ velocimeter_v2,0x3B752bE1bC07bc5A5FF2f3129203f6dC567088bc velocimeter_v2,0xFB5DBe1fc5c115492Bd486796A860d73c3C948B7 velocimeter_v2,0xB45377d54656ac36018dF454950Ebb68B75A08c6 velocimeter_v2,0x06D082d70716A9D4cf83882e7ae3c1ec07A1f3c8 +velocimeter_v2,0xb81c581C1E6084dF0C2a0830A639a69cD3501117 diff --git a/fastlane_bot/data/blockchain_data/mantle/static_pool_data.csv b/fastlane_bot/data/blockchain_data/mantle/static_pool_data.csv index 274a30bff..f6c0851e0 100644 --- a/fastlane_bot/data/blockchain_data/mantle/static_pool_data.csv +++ b/fastlane_bot/data/blockchain_data/mantle/static_pool_data.csv @@ -1214,3 +1214,13 @@ cid,strategy_id,last_updated,last_updated_block,descr,pair_name,exchange_name,fe 0xFB5DBe1fc5c115492Bd486796A860d73c3C948B7,0,,48364886,velocimeter_v2 0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8/0x7e51aD847CDf8729Efc97CFa6E8aFA4D658Cb85b,0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8/0x7e51aD847CDf8729Efc97CFa6E8aFA4D658Cb85b,velocimeter_v2,0.02,0.02,0xFB5DBe1fc5c115492Bd486796A860d73c3C948B7,,0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8,0x7e51aD847CDf8729Efc97CFa6E8aFA4D658Cb85b,18,18,11,WMNT,lz-fMULTI,0,0,0,,,,,velocimeter_v2,volatile,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 0xB45377d54656ac36018dF454950Ebb68B75A08c6,0,,49450176,velocimeter_v2 0x7e51aD847CDf8729Efc97CFa6E8aFA4D658Cb85b/0xdEAddEaDdeadDEadDEADDEAddEADDEAddead1111,0x7e51aD847CDf8729Efc97CFa6E8aFA4D658Cb85b/0xdEAddEaDdeadDEadDEADDEAddEADDEAddead1111,velocimeter_v2,0.02,0.02,0xB45377d54656ac36018dF454950Ebb68B75A08c6,,0x7e51aD847CDf8729Efc97CFa6E8aFA4D658Cb85b,0xdEAddEaDdeadDEadDEADDEAddEADDEAddead1111,18,18,11,lz-fMULTI,WETH,0,0,0,,,,,velocimeter_v2,volatile,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 0x06D082d70716A9D4cf83882e7ae3c1ec07A1f3c8,0,,61896904,velocimeter_v2 0x7e51aD847CDf8729Efc97CFa6E8aFA4D658Cb85b/0x861A6Fc736Cbb12ad57477B535B829239c8347d7,0x7e51aD847CDf8729Efc97CFa6E8aFA4D658Cb85b/0x861A6Fc736Cbb12ad57477B535B829239c8347d7,velocimeter_v2,0.02,0.02,0x06D082d70716A9D4cf83882e7ae3c1ec07A1f3c8,,0x7e51aD847CDf8729Efc97CFa6E8aFA4D658Cb85b,0x861A6Fc736Cbb12ad57477B535B829239c8347d7,18,18,11,lz-fMULTI,MVM,0,0,0,,,,,velocimeter_v2,volatile,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x1d91de696B524838Cb82057A9B7915b32352b4f5,0,,63164155,agni_v3 0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8/0xabBeED1d173541e0546B38b1C0394975be20000 10000,0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8/0xabBeED1d173541e0546B38b1C0394975be20000,agni_v3,10000,0.01,0x1d91de696B524838Cb82057A9B7915b32352b4f5,,0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8,0xabBeED1d173541e0546B38b1C0394975be200000,18,18,4,WMNT,SVL,0,0,0,0,0,0,200,agni_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x18c5EB8bAd84De089cC321a6B1351ecAB75f98BB,0,,63164708,agni_v3 0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8/0xabBeED1d173541e0546B38b1C0394975be20000 500,0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8/0xabBeED1d173541e0546B38b1C0394975be20000,agni_v3,500,0.0005,0x18c5EB8bAd84De089cC321a6B1351ecAB75f98BB,,0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8,0xabBeED1d173541e0546B38b1C0394975be200000,18,18,4,WMNT,SVL,0,0,0,0,0,0,10,agni_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x4aD4eB5c2E7dc0DCf0cE9581dfEcFbEc46A95A06,0,,63221813,butter_v3 0xD1680522C2cEc57192d84021d64813F11DC496fB/0xdEAddEaDdeadDEadDEADDEAddEADDEAddead111 10000,0xD1680522C2cEc57192d84021d64813F11DC496fB/0xdEAddEaDdeadDEadDEADDEAddEADDEAddead111,butter_v3,10000,0.01,0x4aD4eB5c2E7dc0DCf0cE9581dfEcFbEc46A95A06,,0xD1680522C2cEc57192d84021d64813F11DC496fB,0xdEAddEaDdeadDEadDEADDEAddEADDEAddead1111,18,18,4,bETH,WETH,0,0,0,0,0,0,200,butter_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x1E49Ae9AB494AcB31311e92E5580a2fA1e62c139,0,,63221945,butter_v3 0xAc5380724638C9B4b600866e4677954f3F221cf0/0xD1680522C2cEc57192d84021d64813F11DC496f 10000,0xAc5380724638C9B4b600866e4677954f3F221cf0/0xD1680522C2cEc57192d84021d64813F11DC496f,butter_v3,10000,0.01,0x1E49Ae9AB494AcB31311e92E5580a2fA1e62c139,,0xAc5380724638C9B4b600866e4677954f3F221cf0,0xD1680522C2cEc57192d84021d64813F11DC496fB,18,18,4,wbETH,bETH,0,0,0,0,0,0,200,butter_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x1af9FEbebd2Aaa05F81EfdCd5BBF042B3F0cf38F,0,,63382278,cleopatra_v3 0x999890b3A00EA4d60da39A65FA4B70bb0bdb61f7/0xD2B4C9B0d70e3Da1fBDD98f469bD02E77E12FC7 10000,0x999890b3A00EA4d60da39A65FA4B70bb0bdb61f7/0xD2B4C9B0d70e3Da1fBDD98f469bD02E77E12FC7,cleopatra_v3,10000,0.01,0x1af9FEbebd2Aaa05F81EfdCd5BBF042B3F0cf38F,,0x999890b3A00EA4d60da39A65FA4B70bb0bdb61f7,0xD2B4C9B0d70e3Da1fBDD98f469bD02E77E12FC79,18,18,4,neadCleo,AUSD,0,0,0,0,0,0,200,cleopatra_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xaa74910Bf08E6d922bF0bCe45eA5861b669cB55C,0,,63306448,fusionx_v3 0x311eC870e3d7172896CA9f18145bAfc8902c9F3B/0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb 10000,0x311eC870e3d7172896CA9f18145bAfc8902c9F3B/0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb,fusionx_v3,10000,0.01,0xaa74910Bf08E6d922bF0bCe45eA5861b669cB55C,,0x311eC870e3d7172896CA9f18145bAfc8902c9F3B,0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8,18,18,4,BTBS,WMNT,0,0,0,0,0,0,200,fusionx_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xd99882E3404B529D5120Ef16dE6D9a0a11d9c516,0,,63325250,fusionx_v3 0xcDA86A272531e8640cD7F1a92c01839911B90bb0/0xD2B4C9B0d70e3Da1fBDD98f469bD02E77E12FC7 500,0xcDA86A272531e8640cD7F1a92c01839911B90bb0/0xD2B4C9B0d70e3Da1fBDD98f469bD02E77E12FC7,fusionx_v3,500,0.0005,0xd99882E3404B529D5120Ef16dE6D9a0a11d9c516,,0xcDA86A272531e8640cD7F1a92c01839911B90bb0,0xD2B4C9B0d70e3Da1fBDD98f469bD02E77E12FC79,18,18,4,METH,AUSD,0,0,0,0,0,0,10,fusionx_v3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x5EBb830dcF6c9aB3885A782d804bA74367533B57,0,,63216566,merchantmoe_v2 0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8/0xabBeED1d173541e0546B38b1C0394975be200000,0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8/0xabBeED1d173541e0546B38b1C0394975be200000,merchantmoe_v2,0.003,0.003,0x5EBb830dcF6c9aB3885A782d804bA74367533B57,,0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8,0xabBeED1d173541e0546B38b1C0394975be200000,18,18,3,WMNT,SVL,0,0,0,,,,,merchantmoe_v2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0x40021Babb03815A055a2631332D17fc0EF651d6C,0,,63223316,merchantmoe_v2 0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8/0xD75c9FbBDbd6fb6EEDE23132f85D9BA8BAcD0a7e,0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8/0xD75c9FbBDbd6fb6EEDE23132f85D9BA8BAcD0a7e,merchantmoe_v2,0.003,0.003,0x40021Babb03815A055a2631332D17fc0EF651d6C,,0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8,0xD75c9FbBDbd6fb6EEDE23132f85D9BA8BAcD0a7e,18,18,3,WMNT,TVM,0,0,0,,,,,merchantmoe_v2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xb81c581C1E6084dF0C2a0830A639a69cD3501117,0,,63386717,velocimeter_v2 0x7e51aD847CDf8729Efc97CFa6E8aFA4D658Cb85b/0xd27B18915e7acc8FD6Ac75DB6766a80f8D2f5729,0x7e51aD847CDf8729Efc97CFa6E8aFA4D658Cb85b/0xd27B18915e7acc8FD6Ac75DB6766a80f8D2f5729,velocimeter_v2,0.0025,0.0025,0xb81c581C1E6084dF0C2a0830A639a69cD3501117,,0x7e51aD847CDf8729Efc97CFa6E8aFA4D658Cb85b,0xd27B18915e7acc8FD6Ac75DB6766a80f8D2f5729,18,18,11,lz-fMULTI,PENDLE,0,0,0,,,,,velocimeter_v2,volatile,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, diff --git a/fastlane_bot/data/blockchain_data/mantle/tokens.csv b/fastlane_bot/data/blockchain_data/mantle/tokens.csv index 4a02fbd08..f4fb71b9a 100644 --- a/fastlane_bot/data/blockchain_data/mantle/tokens.csv +++ b/fastlane_bot/data/blockchain_data/mantle/tokens.csv @@ -615,3 +615,7 @@ address,decimals,symbol 0x3b19B8EC75BBf85848d133F1a47710EeEd57Bd90,18,oMVM 0x4f74ca4a686203a5D4eBF6E8868c5eBC450bf283,18,sfrxETH 0xf3602C5A7f625181659445C8dDDde73dA15c22e3,18,sFRAX +0xabBeED1d173541e0546B38b1C0394975be200000,18,SVL +0xD1680522C2cEc57192d84021d64813F11DC496fB,18,bETH +0x311eC870e3d7172896CA9f18145bAfc8902c9F3B,18,BTBS +0xD75c9FbBDbd6fb6EEDE23132f85D9BA8BAcD0a7e,18,TVM diff --git a/fastlane_bot/data/blockchain_data/mantle/uniswap_v2_event_mappings.csv b/fastlane_bot/data/blockchain_data/mantle/uniswap_v2_event_mappings.csv index 2bd52166b..91a1978a0 100644 --- a/fastlane_bot/data/blockchain_data/mantle/uniswap_v2_event_mappings.csv +++ b/fastlane_bot/data/blockchain_data/mantle/uniswap_v2_event_mappings.csv @@ -467,3 +467,5 @@ merchantmoe_v2,0xcF18b5874E62f00BdB81F80346598bD32ACa4294 merchantmoe_v2,0x3097a061eE0fc3470e2E84666Eff9e7AbFf6fC93 merchantmoe_v2,0x153bd2051E42f1C5dCF8f08dc836aE1E8316aa7C merchantmoe_v2,0x9E7c8fDEf224cfcbDb8ba187c18E2c025C047A7B +merchantmoe_v2,0x5EBb830dcF6c9aB3885A782d804bA74367533B57 +merchantmoe_v2,0x40021Babb03815A055a2631332D17fc0EF651d6C diff --git a/fastlane_bot/data/blockchain_data/mantle/uniswap_v3_event_mappings.csv b/fastlane_bot/data/blockchain_data/mantle/uniswap_v3_event_mappings.csv index 815f0d7a9..74d1fafd3 100644 --- a/fastlane_bot/data/blockchain_data/mantle/uniswap_v3_event_mappings.csv +++ b/fastlane_bot/data/blockchain_data/mantle/uniswap_v3_event_mappings.csv @@ -671,3 +671,10 @@ puffs_penthouse_v3,0x866B1818D6A221fA2B87A6C10bf60871d09C71A4 puffs_penthouse_v3,0x23d31b3d4A283Fd8E39d64FeeEbc64F6B1eeF874 puffs_penthouse_v3,0x28190bC18bbdc3D340C9A8C80265096E3A7f7EdA puffs_penthouse_v3,0xc0c94deE13fBD76faB0633924f4fA73e12EC3a1A +agni_v3,0x1d91de696B524838Cb82057A9B7915b32352b4f5 +agni_v3,0x18c5EB8bAd84De089cC321a6B1351ecAB75f98BB +butter_v3,0x4aD4eB5c2E7dc0DCf0cE9581dfEcFbEc46A95A06 +butter_v3,0x1E49Ae9AB494AcB31311e92E5580a2fA1e62c139 +cleopatra_v3,0x1af9FEbebd2Aaa05F81EfdCd5BBF042B3F0cf38F +fusionx_v3,0xaa74910Bf08E6d922bF0bCe45eA5861b669cB55C +fusionx_v3,0xd99882E3404B529D5120Ef16dE6D9a0a11d9c516 diff --git a/run_blockchain_terraformer.py b/run_blockchain_terraformer.py index b9f661e7d..aafae8bf5 100644 --- a/run_blockchain_terraformer.py +++ b/run_blockchain_terraformer.py @@ -255,12 +255,7 @@ async def gather(): skip_token_list = ["0xaD67F7a72BA2ca971390B2a1dD907303bD577a4F".lower()] -@dataclass -class TokenManager: - token_dict: Dict - - -def get_all_token_details(web3: Web3, network: str, write_path: str) -> TokenManager: +def get_all_token_details(web3: Web3, network: str, write_path: str) -> dict: """ This function collects the number of decimals and symbol of a token, and formats it for use in a dataframe. :param web3: the Web3 reference @@ -274,16 +269,16 @@ def get_all_token_details(web3: Web3, network: str, write_path: str) -> TokenMan if token_file_exists: token_df = pd.read_csv(token_path, index_col=False) - token_dict = {} + token_manager = {} for idx, row in token_df.iterrows(): address, decimals, symbol = row - token_dict[address] = {"address": address, "decimals": decimals, "symbol": symbol} + token_manager[address] = {"address": address, "decimals": decimals, "symbol": symbol} - return TokenManager(token_dict) + return token_manager url = f"https://tokens.coingecko.com/{coingecko_network_map[network]}/all.json" response = requests.get(url).json()["tokens"] - token_dict = { + token_manager = { "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE": {"address": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", "decimals": 18, "symbol": "ETH"} } if network in ["ethereum", "coinbase_base", "arbitrum_one", "optimism"] else {} @@ -296,7 +291,7 @@ def get_all_token_details(web3: Web3, network: str, write_path: str) -> TokenMan pd.DataFrame( {"token": [address], "symbol": [symbol], "decimals": [decimals]} ).to_csv("token_details.csv") - token_dict[address] = { + token_manager[address] = { "address": address, "decimals": decimals, "symbol": symbol, @@ -304,7 +299,7 @@ def get_all_token_details(web3: Web3, network: str, write_path: str) -> TokenMan except Exception as e: print(f"Failed to get token details for token: {address} with error: {e}") continue - return TokenManager(token_dict=token_dict) + return token_manager def get_token_details_from_contract( @@ -351,23 +346,23 @@ def get_token_details_from_contract( def get_token_details( - tkn: str, token_manager: TokenManager, web3: Web3 + tkn: str, token_manager: dict, web3: Web3 ) -> Tuple[str, int] or Tuple[None, None]: """ :param tkn: the token address - :param token_manager: the token lookup dict + :param token_manager: the token lookup table :param web3: the Web3 object Returns: a Tuple containing the token symbol & decimals, or None, None if the contract call failed. """ tkn = web3.to_checksum_address(tkn) - if tkn in token_manager.token_dict: - symbol = token_manager.token_dict.get(tkn).get("symbol") - decimal = token_manager.token_dict.get(tkn).get("decimals") + if tkn in token_manager: + symbol = token_manager[tkn]["symbol"] + decimal = token_manager[tkn]["decimals"] else: symbol, decimal = get_token_details_from_contract(token=tkn, web3=web3) if type(decimal) == int and type(symbol) == str: - token_manager.token_dict[tkn] = {"address": tkn, "decimals": decimal, "symbol": symbol} + token_manager[tkn] = {"address": tkn, "decimals": decimal, "symbol": symbol} return symbol, decimal @@ -468,12 +463,12 @@ def generate_token_price_map(pool_data: Dict, web3: Web3) -> Dict: def organize_pool_details_uni_v3( - pool_data: Dict, token_manager: TokenManager, exchange: str, web3: Web3 + pool_data: Dict, token_manager: dict, exchange: str, web3: Web3 ) -> Dict: """ This function organizes pool details for Uni V3 pools. :param pool_data: the pool data from the pool creation event - :param token_manager: the token lookup dict + :param token_manager: the token lookup table :param exchange: the exchange name :param web3: the Web3 object @@ -527,13 +522,13 @@ def organize_pool_details_uni_v3( def process_token_details( - tokens: List[str], token_manager: TokenManager, web3: Web3 + tokens: List[str], token_manager: dict, web3: Web3 ) -> Tuple[Dict, str, bool] or Tuple[None, None, bool]: """ This function processes token details & generates the token pair :param tokens: the list of tokens - :param token_manager: the token information dict + :param token_manager: the token lookup table :param web3: the Web3 object returns: tuple containing a dict with token information, the pair name as a string, and a bool that indicates if all tokens were successfully added. @@ -662,12 +657,12 @@ def organize_pool_details_balancer( def organize_pool_details_uni_v2( - pool_data, token_manager: TokenManager, exchange, default_fee, web3 + pool_data, token_manager: dict, exchange, default_fee, web3 ): """ This function organizes pool details for Uni V2 pools. :param pool_data: the pool data from the pool creation event - :param token_addr_lookup: the token lookup dict + :param token_manager: the token lookup table :param exchange: the exchange name :param default_fee: the fee for the exchange :param web3: the Web3 object @@ -724,7 +719,7 @@ def organize_pool_details_solidly_v2( This function organizes pool details for Solidly pools. :param pool_data: the pool data from the pool creation event - :param token_manager: the token lookup dict + :param token_manager: the token lookup table :param exchange: the exchange name :param factory_contract: the exchange's Factory contract - initialized :param web3: the Web3 object @@ -817,7 +812,7 @@ def get_events_recursive(get_logs: any, start_block: int, end_block: int) -> lis def get_uni_v3_pools( - token_manager: TokenManager, + token_manager: dict, exchange: str, factory_contract, start_block: int, @@ -827,7 +822,7 @@ def get_uni_v3_pools( ) -> Tuple[DataFrame, DataFrame]: """ This function retrieves Uniswap V3 pool generation events and organizes them into two Dataframes - :param token_addr_lookup: the dict containing token information + :param token_manager: the token lookup table :param factory_contract: the initialized Factory contract :param start_block: the block number from which to start :param end_block: the block number at which to end @@ -856,7 +851,7 @@ def get_uni_v3_pools( return df, mapdf def get_uni_v2_pools( - token_manager: TokenManager, + token_manager: dict, exchange: str, factory_contract, start_block: int, @@ -867,7 +862,7 @@ def get_uni_v2_pools( ) -> Tuple[DataFrame, DataFrame]: """ This function retrieves Uniswap V2 pool generation events and organizes them into two Dataframes - :param token_addr_lookup: the dict containing token information + :param token_manager: the token lookup table :param factory_contract: the initialized Factory contract :param start_block: the block number from which to start :param end_block: the block number at which to end @@ -898,7 +893,7 @@ def get_uni_v2_pools( return df, mapdf def get_solidly_v2_pools( - token_manager: TokenManager, + token_manager: dict, exchange: str, async_factory_contract, factory_contract, @@ -910,7 +905,7 @@ def get_solidly_v2_pools( ) -> Tuple[DataFrame, DataFrame]: """ This function retrieves Solidly pool generation events and organizes them into two Dataframes - :param token_manager: the dict containing token information + :param token_manager: the token lookup table :param factory_contract: the initialized Factory contract :param start_block: the block number from which to start :param end_block: the block number at which to end @@ -1042,19 +1037,14 @@ def get_last_block_updated(df: pd.DataFrame, exchange: str) -> int: return safe_int(ex_df["last_updated_block"].max()) -def save_token_data(token_dict: TokenManager, write_path: str): +def save_token_data(token_manager: dict, write_path: str): """ Saves token data to a CSV """ token_path = os.path.join(write_path, "tokens.csv") - token_list = [] - - for key in token_dict.token_dict.keys(): - token_list.append(token_dict.token_dict[key]) - - token_df = pd.DataFrame(token_list, columns=["address", "decimals", "symbol"]) + token_df = pd.DataFrame(token_manager.values(), columns=["address", "decimals", "symbol"]) token_df.set_index("address", inplace=True) token_df.to_csv(token_path) @@ -1102,7 +1092,7 @@ def terraform_blockchain(network_name: str): write_path + "/solidly_v2_event_mappings.csv", index_col=False ) - save_token_data(token_dict=token_manager, write_path=write_path) + save_token_data(token_manager=token_manager, write_path=write_path) to_block = web3.eth.block_number @@ -1201,7 +1191,7 @@ def terraform_blockchain(network_name: str): continue exchange_df = pd.concat([exchange_df, u_df]) - save_token_data(token_dict=token_manager, write_path=write_path) + save_token_data(token_manager=token_manager, write_path=write_path) exchange_df.to_csv((write_path + "/static_pool_data.csv"), index=False) univ2_mapdf.to_csv((write_path + "/uniswap_v2_event_mappings.csv"), index=False) @@ -1220,5 +1210,5 @@ def terraform_blockchain(network_name: str): #terraform_blockchain(network_name=ETHEREUM) #terraform_blockchain(network_name=BASE) #terraform_blockchain(network_name=FANTOM) -#terraform_blockchain(network_name=MANTLE) -#terraform_blockchain(network_name=LINEA) +terraform_blockchain(network_name=MANTLE) +terraform_blockchain(network_name=LINEA) From 2db303846d7c5215475cc70a2168d02955f853df Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sun, 5 May 2024 22:06:40 +0300 Subject: [PATCH 021/131] Minor --- run_blockchain_terraformer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/run_blockchain_terraformer.py b/run_blockchain_terraformer.py index aafae8bf5..3c0205724 100644 --- a/run_blockchain_terraformer.py +++ b/run_blockchain_terraformer.py @@ -1210,5 +1210,5 @@ def terraform_blockchain(network_name: str): #terraform_blockchain(network_name=ETHEREUM) #terraform_blockchain(network_name=BASE) #terraform_blockchain(network_name=FANTOM) -terraform_blockchain(network_name=MANTLE) -terraform_blockchain(network_name=LINEA) +#terraform_blockchain(network_name=MANTLE) +#terraform_blockchain(network_name=LINEA) From fefb0cf96ef4af863c97892826b02be346da4bea Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sun, 5 May 2024 22:10:00 +0300 Subject: [PATCH 022/131] Remove unused import --- run_blockchain_terraformer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/run_blockchain_terraformer.py b/run_blockchain_terraformer.py index 3c0205724..eb96b3ba9 100644 --- a/run_blockchain_terraformer.py +++ b/run_blockchain_terraformer.py @@ -1,5 +1,4 @@ import math -from dataclasses import dataclass from typing import Tuple, List, Dict import pandas as pd From eb3e9f85506097dd1cf3efc831c4d61a10124e51 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sun, 5 May 2024 22:06:24 +0300 Subject: [PATCH 023/131] Cleanup terraformer script add update data files for mantle and linea --- run_blockchain_terraformer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/run_blockchain_terraformer.py b/run_blockchain_terraformer.py index eb96b3ba9..d258cda1e 100644 --- a/run_blockchain_terraformer.py +++ b/run_blockchain_terraformer.py @@ -1209,5 +1209,5 @@ def terraform_blockchain(network_name: str): #terraform_blockchain(network_name=ETHEREUM) #terraform_blockchain(network_name=BASE) #terraform_blockchain(network_name=FANTOM) -#terraform_blockchain(network_name=MANTLE) -#terraform_blockchain(network_name=LINEA) +terraform_blockchain(network_name=MANTLE) +terraform_blockchain(network_name=LINEA) From 8c351aec50539905bd2c41d8142bb182d66bd5c7 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sun, 5 May 2024 22:06:40 +0300 Subject: [PATCH 024/131] Minor --- run_blockchain_terraformer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/run_blockchain_terraformer.py b/run_blockchain_terraformer.py index d258cda1e..eb96b3ba9 100644 --- a/run_blockchain_terraformer.py +++ b/run_blockchain_terraformer.py @@ -1209,5 +1209,5 @@ def terraform_blockchain(network_name: str): #terraform_blockchain(network_name=ETHEREUM) #terraform_blockchain(network_name=BASE) #terraform_blockchain(network_name=FANTOM) -terraform_blockchain(network_name=MANTLE) -terraform_blockchain(network_name=LINEA) +#terraform_blockchain(network_name=MANTLE) +#terraform_blockchain(network_name=LINEA) From 8a908669da39b7b765e31693b9cf01059decf951 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Mon, 6 May 2024 09:06:31 +0300 Subject: [PATCH 025/131] Cleanup the terraformer script more deeply --- run_blockchain_terraformer.py | 166 +++++++++++----------------------- 1 file changed, 55 insertions(+), 111 deletions(-) diff --git a/run_blockchain_terraformer.py b/run_blockchain_terraformer.py index eb96b3ba9..f86ef649f 100644 --- a/run_blockchain_terraformer.py +++ b/run_blockchain_terraformer.py @@ -251,7 +251,8 @@ async def gather(): "tkn7_balance", "tkn7_weight", ] -skip_token_list = ["0xaD67F7a72BA2ca971390B2a1dD907303bD577a4F".lower()] + +skip_token_list = set(["0xaD67F7a72BA2ca971390B2a1dD907303bD577a4F"]) def get_all_token_details(web3: Web3, network: str, write_path: str) -> dict: @@ -311,36 +312,31 @@ def get_token_details_from_contract( Returns: a Tuple containing the token symbol & decimals, or None, None if the contract call failed. """ - if token == "0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2": + if token in skip_token_list: + return None, None + elif token == "0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2": symbol = "MKR" decimals = 18 elif token == "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE": symbol = "ETH" decimals = 18 - if token.lower() in skip_token_list: - return None, None else: - contract = web3.eth.contract( - address=web3.to_checksum_address(token), abi=ERC20_ABI - ) + contract = web3.eth.contract(address=token, abi=ERC20_ABI) try: - contract = web3.eth.contract( - address=web3.to_checksum_address(token), abi=ERC20_ABI - ) decimals = contract.caller.decimals() - except: print(f"Cannot get token details for token: {token}") - skip_token_list.append(token.lower()) + skip_token_list.add(token) return None, None try: - symbol = contract.caller.symbol().replace(os.linesep, "") or "???" - # attempt to write to csv - pd.DataFrame( - {"token": [token], "symbol": [symbol], "decimals": [decimals]} - ).to_csv("token_details.csv") - except Exception as e: + symbol = contract.caller.symbol() + except: symbol = "SYMBOL_FAILED" + else: + symbol = symbol.replace(os.linesep, "") or "???" + pd.DataFrame( + {"token": [token], "symbol": [symbol], "decimals": [decimals]} + ).to_csv("token_details.csv") return symbol, decimals @@ -376,28 +372,12 @@ def fix_missing_symbols(symbol: str, addr: str) -> str: """ if addr == "0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2": return "MKR" - elif ( - addr == "0xF1290473E210b2108A85237fbCd7b6eb42Cc654F" - or addr.lower() == "0xF1290473E210b2108A85237fbCd7b6eb42Cc654F".lower() - ): + elif addr == "0xF1290473E210b2108A85237fbCd7b6eb42Cc654F": return "HEDG" else: return symbol -def skip_tokens(addr: str) -> bool: - """ - This function checks against a list of tokens that should be skipped due to problems in their contract, etc. - :param addr: the token address - - retuns: bool - """ - if addr.lower() in skip_token_list: - return True - else: - return False - - def get_token_prices_coingecko(token_list: Dict) -> Dict: """ :param token_list: the list of tokens for which to fetch prices @@ -448,14 +428,11 @@ def generate_token_price_map(pool_data: Dict, web3: Web3) -> Dict: for pool in pool_data: tokens = pool["tokens"] for tkn in tokens: - address = tkn["address"] - if skip_tokens(addr=address): + address = web3.to_checksum_address(tkn["address"]) + if address in skip_token_list: continue - symbol = tkn["symbol"] - symbol = fix_missing_symbols(addr=address, symbol=symbol) - - address = web3.to_checksum_address(address) - token_prices[str(address)] = {"tokenSymbol": str(symbol), "usd": None} + symbol = fix_missing_symbols(addr=address, symbol=tkn["symbol"]) + token_prices[address] = {"tokenSymbol": symbol, "usd": None} token_prices = get_token_prices_coingecko(token_list=token_prices) return token_prices @@ -483,17 +460,15 @@ def organize_pool_details_uni_v3( ) if skip_pool: return None - pair = pair[:-1] - fee = pool_data["args"]["fee"] - description = exchange + " " + pair + " " + str(fee) + fee = pool_data["args"]["fee"] pool_info = { "cid": pool_address, "strategy_id": 0, "last_updated": "", "last_updated_block": last_updated_block, - "descr": description, + "descr": f"{exchange} {pair} {fee}", "pair_name": pair, "exchange_name": exchange, "fee": fee, @@ -516,8 +491,8 @@ def organize_pool_details_uni_v3( "tick_spacing": tick_spacing, "exchange": exchange, } - pool = {**pool_info, **token_info} - return pool + + return {**pool_info, **token_info} def process_token_details( @@ -533,29 +508,26 @@ def process_token_details( returns: tuple containing a dict with token information, the pair name as a string, and a bool that indicates if all tokens were successfully added. """ token_info = {} - pair = "" + addresses = [] for idx, tkn in enumerate(tokens): - tkn_num = "tkn" + str(idx) - address = tkn + address = web3.to_checksum_address(tkn) - if skip_tokens(addr=address): + if address in skip_token_list: return None, None, True - address = web3.to_checksum_address(address) symbol, decimals = get_token_details( token_manager=token_manager, tkn=address, web3=web3 ) if symbol is None: return None, None, True symbol = fix_missing_symbols(addr=address, symbol=symbol) - token_info[tkn_num + "_decimals"] = decimals - token_info[tkn_num + "_address"] = address - token_info[tkn_num + "_symbol"] = symbol - token_info[tkn_num + "_balance"] = 0 + token_info[f"tkn{idx}_decimals"] = decimals + token_info[f"tkn{idx}_address"] = address + token_info[f"tkn{idx}_symbol"] = symbol + token_info[f"tkn{idx}_balance"] = 0 - pair += address + "/" - pair = pair[:-1] + addresses += [address] - return token_info, pair, False + return token_info, "/".join(addresses), False def organize_pool_details_balancer( @@ -570,29 +542,16 @@ def organize_pool_details_balancer( returns: dict of pool information """ - skip_pool = False if pool_data["swapEnabled"] != True: return None - pool_id = pool_data["id"] - pool_type = pool_data["poolType"] - pool_address = pool_data["address"] - pool_address = web3.to_checksum_address(pool_address) token_info = {} - tokens = pool_data["tokens"] + addresses = [] - pair = "" - - for idx, tkn in enumerate(tokens): - tkn_num = "tkn" + str(idx) - address = tkn["address"] - address = web3.to_checksum_address(address) - if skip_tokens(addr=address): - skip_pool = True - break - - symbol = tkn["symbol"] - symbol = fix_missing_symbols(addr=address, symbol=symbol) + for idx, tkn in enumerate(pool_data["tokens"]): + address = web3.to_checksum_address(tkn["address"]) + if address in skip_token_list: + return None # Currently unused - this gets the pool balance, but is only usable accurately on Mainnet # balance = float(tkn["balance"]) @@ -600,39 +559,29 @@ def organize_pool_details_balancer( # tkn_val_usd = balance * tkn_price # pool_total_liquidity_usd += tkn_val_usd - token_info[tkn_num + "_address"] = address - token_info[tkn_num + "_symbol"] = symbol - token_info[tkn_num + "_decimals"] = tkn["decimals"] - token_info[tkn_num + "_weight"] = tkn["weight"] - token_info[tkn_num + "_balance"] = 0 - - pair += address + "/" + token_info[f"tkn{idx}_address"] = address + token_info[f"tkn{idx}_symbol"] = fix_missing_symbols(addr=address, symbol=tkn["symbol"]) + token_info[f"tkn{idx}_decimals"] = tkn["decimals"] + token_info[f"tkn{idx}_weight"] = tkn["weight"] + token_info[f"tkn{idx}_balance"] = 0 - # if pool_total_liquidity_usd < min_usd: - # print(f"pool eliminated due to low liquidity: {pool_total_liquidity_usd} vs min {min_usd}") - # return None - - if skip_pool: - return None + addresses += [address] - pair = pair[:-1] + pair = "/".join(addresses) fee = pool_data["swapFee"] - exchange = "balancer" - - description = exchange + " " + pair + " " + str(fee) pool_info = { - "cid": pool_id, + "cid": pool_data["id"], "strategy_id": 0, "last_updated": "", "last_updated_block": 0, - "descr": description, + "descr": f"balancer {pair} {fee}", "pair_name": pair, - "exchange_name": exchange, + "exchange_name": "balancer", "fee": float(fee) * 10 ** 18, "fee_float": float(fee), - "address": pool_address, - "anchor": pool_id, + "address": web3.to_checksum_address(pool_data["address"]), + "anchor": pool_data["id"], "tkn0_address": token_info["tkn0_address"], "tkn1_address": token_info["tkn1_address"], "tkn0_decimals": token_info["tkn0_decimals"], @@ -648,11 +597,10 @@ def organize_pool_details_balancer( "tick": 0, "tick_spacing": 0, "exchange": "balancer", - "pool_type": pool_type, + "pool_type": pool_data["poolType"], } - pool = {**pool_info, **token_info} - return pool + return {**pool_info, **token_info} def organize_pool_details_uni_v2( @@ -680,14 +628,13 @@ def organize_pool_details_uni_v2( ) if skip_pool: return None - description = exchange + " " + pair pool_info = { "cid": pool_address, "strategy_id": 0, "last_updated": "", "last_updated_block": last_updated_block, - "descr": description, + "descr": f"{exchange} {pair}", "pair_name": pair, "exchange_name": exchange, "fee": default_fee, @@ -706,9 +653,8 @@ def organize_pool_details_uni_v2( "tkn1_balance": 0, "exchange": exchange, } - pool = {**pool_info, **token_info} - return pool + return {**pool_info, **token_info} def organize_pool_details_solidly_v2( @@ -750,14 +696,13 @@ def organize_pool_details_solidly_v2( ) if skip_pool: return None - description = exchange + " " + pair pool_info = { "cid": pool_address, "strategy_id": 0, "last_updated": "", "last_updated_block": last_updated_block, - "descr": description, + "descr": f"{exchange} {pair}", "pair_name": pair, "exchange_name": exchange, "fee": fee_str, @@ -777,9 +722,8 @@ def organize_pool_details_solidly_v2( "exchange": exchange, "pool_type": stable_pool, } - pool = {**pool_info, **token_info} - return pool + return {**pool_info, **token_info} def get_events(contract: any, blockchain: str, exchange: str, start_block: int, end_block: int) -> list: From 02e1868c9f0c3cf900bca24900cfa825799aaca2 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Mon, 6 May 2024 09:14:21 +0300 Subject: [PATCH 026/131] Minor --- run_blockchain_terraformer.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/run_blockchain_terraformer.py b/run_blockchain_terraformer.py index f86ef649f..f761e0db8 100644 --- a/run_blockchain_terraformer.py +++ b/run_blockchain_terraformer.py @@ -426,8 +426,7 @@ def generate_token_price_map(pool_data: Dict, web3: Web3) -> Dict: token_prices = {} for pool in pool_data: - tokens = pool["tokens"] - for tkn in tokens: + for tkn in pool["tokens"]: address = web3.to_checksum_address(tkn["address"]) if address in skip_token_list: continue From e996ec6addf993cefde7674bd845d98643504157 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Mon, 6 May 2024 10:24:18 +0300 Subject: [PATCH 027/131] More cleanup --- run_blockchain_terraformer.py | 133 +++++++--------------------------- 1 file changed, 26 insertions(+), 107 deletions(-) diff --git a/run_blockchain_terraformer.py b/run_blockchain_terraformer.py index f761e0db8..62d7f2840 100644 --- a/run_blockchain_terraformer.py +++ b/run_blockchain_terraformer.py @@ -255,13 +255,12 @@ async def gather(): skip_token_list = set(["0xaD67F7a72BA2ca971390B2a1dD907303bD577a4F"]) -def get_all_token_details(web3: Web3, network: str, write_path: str) -> dict: +def get_all_token_details(network: str, write_path: str) -> dict: """ This function collects the number of decimals and symbol of a token, and formats it for use in a dataframe. - :param web3: the Web3 reference :param network: the network name - :returns: Dict + :returns: the token lookup table """ token_path = os.path.join(write_path, "tokens.csv") @@ -283,9 +282,9 @@ def get_all_token_details(web3: Web3, network: str, write_path: str) -> dict: "decimals": 18, "symbol": "ETH"} } if network in ["ethereum", "coinbase_base", "arbitrum_one", "optimism"] else {} for token in response: - address = web3.to_checksum_address(token.get("address")) - symbol = token.get("symbol") - decimals = token.get("decimals") + address = Web3.to_checksum_address(token["address"]) + symbol = token["symbol"] + decimals = token["decimals"] try: # try to write to csv pd.DataFrame( @@ -350,7 +349,7 @@ def get_token_details( Returns: a Tuple containing the token symbol & decimals, or None, None if the contract call failed. """ - tkn = web3.to_checksum_address(tkn) + tkn = Web3.to_checksum_address(tkn) if tkn in token_manager: symbol = token_manager[tkn]["symbol"] decimal = token_manager[tkn]["decimals"] @@ -378,68 +377,9 @@ def fix_missing_symbols(symbol: str, addr: str) -> str: return symbol -def get_token_prices_coingecko(token_list: Dict) -> Dict: - """ - :param token_list: the list of tokens for which to fetch prices - - Returns token prices using Coingecko API - """ - - max_size = 100 - tkn_addresses = list(token_list.keys()) - tkn_sublists = [ - tkn_addresses[x: x + max_size] for x in range(0, len(tkn_addresses), max_size) - ] - - for tkn_sublist in tkn_sublists: - tokens = ",".join(tkn_sublist) - url = f"https://api.coingecko.com/api/v3/simple/token_price/ethereum?contract_addresses={tokens}&vs_currencies=USD&include_market_cap=false&include_24hr_vol=false&include_24hr_change=false&include_last_updated_at=false" - response = requests.get(url) - - if response.status_code == 200: - data = response.json() - if data is not None: - prices = [] - for tkn in data.keys(): - try: - prices.append((tkn, data[tkn]["usd"])) - except KeyError: - prices.append((tkn, 0)) - continue - - for tkn in prices: - for tkn_addrs in token_list.keys(): - if tkn[0].lower() == tkn_addrs.lower(): - token_list[tkn_addrs]["usd"] = float(tkn[1]) - return token_list - - -def generate_token_price_map(pool_data: Dict, web3: Web3) -> Dict: - """ - This function retrieves token prices from Coingecko - :param pool_data: list of pools - :param web3: the Web3 object - - returns: a dict containing token prices - - """ - token_prices = {} - - for pool in pool_data: - for tkn in pool["tokens"]: - address = web3.to_checksum_address(tkn["address"]) - if address in skip_token_list: - continue - symbol = fix_missing_symbols(addr=address, symbol=tkn["symbol"]) - token_prices[address] = {"tokenSymbol": symbol, "usd": None} - - token_prices = get_token_prices_coingecko(token_list=token_prices) - return token_prices - - def organize_pool_details_uni_v3( - pool_data: Dict, token_manager: dict, exchange: str, web3: Web3 -) -> Dict: + pool_data: dict, token_manager: dict, exchange: str, web3: Web3 +) -> dict: """ This function organizes pool details for Uni V3 pools. :param pool_data: the pool data from the pool creation event @@ -450,7 +390,7 @@ def organize_pool_details_uni_v3( returns: dict of pool information """ pool_address = pool_data["args"]["pool"] - pool_address = web3.to_checksum_address(pool_address) + pool_address = Web3.to_checksum_address(pool_address) last_updated_block = pool_data["blockNumber"] tick_spacing = pool_data["args"]["tickSpacing"] tokens = [pool_data["args"]["token0"], pool_data["args"]["token1"]] @@ -478,7 +418,7 @@ def organize_pool_details_uni_v3( "tkn1_address": token_info["tkn1_address"], "tkn0_decimals": token_info["tkn0_decimals"], "tkn1_decimals": token_info["tkn1_decimals"], - "exchange_id": EXCHANGE_IDS.get("uniswap_v3"), + "exchange_id": EXCHANGE_IDS["uniswap_v3"], "tkn0_symbol": token_info["tkn0_symbol"], "tkn1_symbol": token_info["tkn1_symbol"], "timestamp": 0, @@ -509,7 +449,7 @@ def process_token_details( token_info = {} addresses = [] for idx, tkn in enumerate(tokens): - address = web3.to_checksum_address(tkn) + address = Web3.to_checksum_address(tkn) if address in skip_token_list: return None, None, True @@ -529,15 +469,10 @@ def process_token_details( return token_info, "/".join(addresses), False -def organize_pool_details_balancer( - pool_data: Dict, token_prices: Dict, web3: Web3, min_usd: int = 100000 -): +def organize_pool_details_balancer(pool_data: dict) -> dict: """ This function organizes pool details for Uni V3 pools. :param pool_data: the pool data from the pool creation event - :param token_prices: the token prices - :param web3: the Web3 object - :param min_usd: the minimum pool balance in USD to include the pool returns: dict of pool information """ @@ -548,16 +483,10 @@ def organize_pool_details_balancer( addresses = [] for idx, tkn in enumerate(pool_data["tokens"]): - address = web3.to_checksum_address(tkn["address"]) + address = Web3.to_checksum_address(tkn["address"]) if address in skip_token_list: return None - # Currently unused - this gets the pool balance, but is only usable accurately on Mainnet - # balance = float(tkn["balance"]) - # tkn_price = 0 if token_prices[address]["usd"] is None else float(token_prices[address]["usd"]) - # tkn_val_usd = balance * tkn_price - # pool_total_liquidity_usd += tkn_val_usd - token_info[f"tkn{idx}_address"] = address token_info[f"tkn{idx}_symbol"] = fix_missing_symbols(addr=address, symbol=tkn["symbol"]) token_info[f"tkn{idx}_decimals"] = tkn["decimals"] @@ -579,7 +508,7 @@ def organize_pool_details_balancer( "exchange_name": "balancer", "fee": float(fee) * 10 ** 18, "fee_float": float(fee), - "address": web3.to_checksum_address(pool_data["address"]), + "address": Web3.to_checksum_address(pool_data["address"]), "anchor": pool_data["id"], "tkn0_address": token_info["tkn0_address"], "tkn1_address": token_info["tkn1_address"], @@ -616,7 +545,7 @@ def organize_pool_details_uni_v2( returns: dict of pool information """ pool_address = pool_data["args"]["pair"] - pool_address = web3.to_checksum_address(pool_address) + pool_address = Web3.to_checksum_address(pool_address) last_updated_block = pool_data["blockNumber"] if default_fee == "TBD": return None @@ -644,7 +573,7 @@ def organize_pool_details_uni_v2( "tkn1_address": token_info["tkn1_address"], "tkn0_decimals": token_info["tkn0_decimals"], "tkn1_decimals": token_info["tkn1_decimals"], - "exchange_id": EXCHANGE_IDS.get("uniswap_v2"), + "exchange_id": EXCHANGE_IDS["uniswap_v2"], "tkn0_symbol": token_info["tkn0_symbol"], "tkn1_symbol": token_info["tkn1_symbol"], "timestamp": 0, @@ -667,7 +596,7 @@ def organize_pool_details_solidly_v2( :param exchange: the exchange name :param factory_contract: the exchange's Factory contract - initialized :param web3: the Web3 object - :param web3: the async Web3 object + :param async_web3: the Async Web3 object returns: dict of pool information """ if "pool" in pool_data or "pool" in pool_data["args"]: @@ -676,7 +605,7 @@ def organize_pool_details_solidly_v2( pool_address = pool_data["args"]["pair"] else: print(f"COULD NOT FIND KEY IN EVENT for exchange {exchange}: {pool_data}") - pool_address = web3.to_checksum_address(pool_address) + pool_address = Web3.to_checksum_address(pool_address) last_updated_block = pool_data["blockNumber"] @@ -712,7 +641,7 @@ def organize_pool_details_solidly_v2( "tkn1_address": token_info["tkn1_address"], "tkn0_decimals": token_info["tkn0_decimals"], "tkn1_decimals": token_info["tkn1_decimals"], - "exchange_id": EXCHANGE_IDS.get(exchange), + "exchange_id": EXCHANGE_IDS[exchange], "tkn0_symbol": token_info["tkn0_symbol"], "tkn1_symbol": token_info["tkn1_symbol"], "timestamp": 0, @@ -918,28 +847,18 @@ def get_multichain_addresses(network_name: str) -> pd.DataFrame: """ -def get_balancer_pools(subgraph_url: str, web3: Web3) -> pd.DataFrame: +def get_balancer_pools(subgraph_url: str) -> pd.DataFrame: """ This function gets Balancer pool details from the Balancer subgraph :param subgraph_url: the URL of the Balancer subgraph - :param web3: the Web3 object """ response = requests.post(subgraph_url, json={"query": balancer_subgraph_query}) assert response.status_code == 200, f"Balancer subgraph query failed with {response}" - pool_data = response.json()["data"]["pools"] - - token_prices = generate_token_price_map(pool_data=pool_data, web3=web3) - pools = [] - for pool in pool_data: - pools.append( - organize_pool_details_balancer( - pool_data=pool, token_prices=token_prices, web3=web3 - ) - ) - pools = [pool for pool in pools if pool is not None] - df = pd.DataFrame(pools, columns=dataframe_key) - return df + pool_data_list = response.json()["data"]["pools"] + + pools = [organize_pool_details_balancer(pool_data) for pool_data in pool_data_list] + return pd.DataFrame([pool for pool in pools if pool is not None], columns=dataframe_key) def add_to_exchange_ids(exchange: str, fork: str): @@ -1008,7 +927,7 @@ def terraform_blockchain(network_name: str): path_exists = os.path.exists(write_path) data_path = os.path.normpath(write_path + "/static_pool_data.csv") data_exists = os.path.exists(data_path) - token_manager = get_all_token_details(web3, network=network_name, write_path=write_path) + token_manager = get_all_token_details(network=network_name, write_path=write_path) if not path_exists: os.makedirs(write_path) @@ -1124,7 +1043,7 @@ def terraform_blockchain(network_name: str): elif "balancer" in fork: try: subgraph_url = BALANCER_SUBGRAPH_CHAIN_URL[network_name] - u_df = get_balancer_pools(subgraph_url=subgraph_url, web3=web3) + u_df = get_balancer_pools(subgraph_url=subgraph_url) except Exception as e: print(f"Fetching balancer pools for chain {network_name} failed:\n{e}") continue From 62b4d11cb576b049bb9cc58ce48b6b1d3edf4389 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Mon, 6 May 2024 11:02:07 +0300 Subject: [PATCH 028/131] Update data files for base --- .../solidly_v2_event_mappings.csv | 55 + .../blockchain_data/coinbase_base/tokens.csv | 1304 ++++++++++++++++ .../uniswap_v2_event_mappings.csv | 171 +++ .../uniswap_v3_event_mappings.csv | 1338 +++++++++++++++++ 4 files changed, 2868 insertions(+) diff --git a/fastlane_bot/data/blockchain_data/coinbase_base/solidly_v2_event_mappings.csv b/fastlane_bot/data/blockchain_data/coinbase_base/solidly_v2_event_mappings.csv index c05001617..43067b973 100644 --- a/fastlane_bot/data/blockchain_data/coinbase_base/solidly_v2_event_mappings.csv +++ b/fastlane_bot/data/blockchain_data/coinbase_base/solidly_v2_event_mappings.csv @@ -1276,3 +1276,58 @@ velocimeter_v2,0xD417CAd1A083198837DEC73D2780395F471Cdf31 velocimeter_v2,0xd032d277d7BbdEB51B0a77aF873930296768c2A1 velocimeter_v2,0x91000A718DfeD49ddfc10A74DdF5Cf7399540888 velocimeter_v2,0x6B92Ddab1ed75df684A02CD14A0481b25148f8cf +aerodrome_v2,0x4ceE7cD3d821c514EcE6a01e91A9b418396bd1c1 +aerodrome_v2,0xdd0fC65F9088e7B487a2867c362B7956384D92C7 +aerodrome_v2,0xe4F3dEf72Ae1aD6B4b63FCa4df12ffF5402AE13d +aerodrome_v2,0x3a62a86C481f9Fbe578B3F62B72A27D8f8d6C85b +aerodrome_v2,0x1894416A511251CfDD350B80bE256F4D166dCa0e +aerodrome_v2,0xEb725c1FDd2a1Db9EaCA20a4DC7E78896565D585 +aerodrome_v2,0x10e63a964f65242AC1A97b925813B35cF716fF9d +aerodrome_v2,0x1491d10F4A22d6D1ca7749CC3F68521eB1E386b2 +aerodrome_v2,0x85F742c905658251E9523BAD96C2F80C5E2d7fd3 +aerodrome_v2,0x8A97D8C1F67Cc6EFb1222E7a9A766C6089f8d76c +aerodrome_v2,0x4AA6CF748BeADd0098DBeE669fa812938034682d +aerodrome_v2,0xAaE3d6b4dEce107768EC3fF6D2ba63df28225491 +aerodrome_v2,0xFfC40A46c5EC3531b4c27947423735987d77BDbA +aerodrome_v2,0xf5879DCf41402268d2A84CC9d265D607F588e83f +aerodrome_v2,0xB61eB73C258F9273d136226DE3952eDf48663f71 +aerodrome_v2,0x8291f3f72c71a9843170001B40967A688bfEBb3a +aerodrome_v2,0x86DE2E61Bb83c52569cfA6f9B3d183da11D1195f +aerodrome_v2,0x56237149C37098e1B2dc3aa0cF42764795F42d95 +aerodrome_v2,0x33c3782446dF290bE025A24A0Ac94562E9A995D6 +aerodrome_v2,0x1b3D4586ACF01C4FDc18158CF46B97A4D0D21F20 +aerodrome_v2,0xEAcE394F7B53f28b77F2e2506D70bC7BD07Cd4F3 +aerodrome_v2,0xC4460eCEB0a2b84dfbA4B2c85960C37B3Bf7a80b +aerodrome_v2,0xdF8280565549ED72cC48E8D5297fb1ECd912E9e3 +aerodrome_v2,0x0b8711D0F80Eacb3dE9f653BD554aF3bA654fA1f +aerodrome_v2,0x9D651E2491a57eE801de20a2ddE33747631fC083 +aerodrome_v2,0x3eE99B4D81ea447e905e0a0EF726B6Afc88bB732 +aerodrome_v2,0xb0B2E62fe141E84cFC00A8Fc65757499EF60D586 +aerodrome_v2,0x857E905f530FA733aB8C43203c514dF59713832e +aerodrome_v2,0x41490957E520F66eC73AE0671ce276223c59FAb4 +aerodrome_v2,0x4296b50ADF4e27eb2cf2f71b799f88268E459748 +aerodrome_v2,0xEb1913F806C1f0ec1AFaDD837458dF3eb43b04E6 +aerodrome_v2,0x26638737a80EE07153bdBce7BAA738b3306f87d9 +aerodrome_v2,0x8658F3EeBd8bf693C0A7cfc2a70be5DC613440c1 +aerodrome_v2,0x2701F677d5E551468326EAe3fd2aC5d16a4247A9 +aerodrome_v2,0x56CdB749f2678Ca40e7b3687589F027417A1D554 +aerodrome_v2,0x6656648B3c925d9aC13C456567112F7a5CEF8cE8 +aerodrome_v2,0x1cf2409BbF69b29913242143fB1F0cC9577F4D37 +aerodrome_v2,0xB8743Ff3f4AE10c9a1CC92Daee9d9CEd62C911D9 +aerodrome_v2,0xBE0d0318cCd067D8C91314efEDE8BF93793A7Dc7 +aerodrome_v2,0x33ced6Bb3Dd3e7c7779628BBA53aCC87355aE159 +aerodrome_v2,0x72A8cD630D013BC971e86C3e193Bff2C75e9e50A +aerodrome_v2,0x40ddC3aC4f9672e1e77A0cBe8Fe55F1e62Ea2F14 +aerodrome_v2,0x87d6d16eA835607Eb9a4A00257762f8864A4A6F2 +aerodrome_v2,0x68D899c59D7dA901eeD6a87b4281D499F016758C +aerodrome_v2,0x97796439776dB7fFc3Ce8dcfB2ADBc1fd145C67C +aerodrome_v2,0x371ff4b62D12A2E78e798a885478CAd8BAF97E6e +aerodrome_v2,0x9b0025d10E824E7E2b148953009A40B0C0792F30 +aerodrome_v2,0x7f23010bf37fbaDBcAEa2CBB1E84B37cDb30437C +aerodrome_v2,0xc5aDfb267a95df1233a2b5F7f48041E7Fb384BcA +aerodrome_v2,0x0Da751fFAB2d9deaF89BfcEED570D8cac8C96F05 +aerodrome_v2,0x67721f14cEdf15B4B70692EE359Ec350C59Dab14 +scale_v2,0xB6A20d2D9C8Eaf8197b0584969239d179Bf1B396 +scale_v2,0x48498571dF1B94d08C0C100f068938A7B1B525eE +scale_v2,0x56863cbF405d97b4B89aa9ff1eC1f38E80126010 +scale_v2,0x3da64dAdA8caBf59ed05C6B6A003171B3EFCDb16 diff --git a/fastlane_bot/data/blockchain_data/coinbase_base/tokens.csv b/fastlane_bot/data/blockchain_data/coinbase_base/tokens.csv index dbac2efb0..2b20be9d9 100644 --- a/fastlane_bot/data/blockchain_data/coinbase_base/tokens.csv +++ b/fastlane_bot/data/blockchain_data/coinbase_base/tokens.csv @@ -32041,3 +32041,1307 @@ address,decimals,symbol 0x2fEB15b8185053092a5f6D77B99FC05082A499c6,18,WF 0xcC167Adfa55746055011512e325303624cE466AA,18,THO 0x8Fe2b9EA2C78A9FBEF771A51797bEF9390D2183D,18,STARV3 +0x1fF20056eAf7a5B24671c24543a58d84fb0918aE,18,B1 +0xe11dEA55a9Ca6c4232286E0cE4e5A6871630681b,18,bpzzzzTST +0x076F506Eb6E39d363440A1C1aaCa0F0D40DDecb3,18,BASED +0x7c642BD08f2b8330900278f0C4f1b801EBe50859,18,SIXNINE +0xDD46D9aBE5bc1F3020E4ef5DCe722CAa449DBd50,18,bpzzzzzzTS +0x7cC88702CBDfc0519b5f95964ceEdCDbe60Db66a,18,pzzzTST +0x91FAE4ED0Ebc228ceEF92C7cfD8fDAD777086253,18,bpzzzzzTST +0x4aAe6BF4a393c57543990Bb2F1Dcf407Fa35c8b3,18,bpzzzzTST +0x4364F7311095075123d279C8bB903edc868C0f66,18,BDROP +0x9FE1fbcb5BF0b0CE45A7ad3cDEA1ae8ae49a8fB7,9,QZR +0x365d7a3B7437DabbEbd1BF596baeEdd9F57e7e3d,18,bpxxxxxxTS +0xf305D674a4e1B8C9e81Fe9F24393Ee3Ff9173F0b,18,PEACE +0xd8FACc12Ef96b70469CE5CAbc141dFCa1d2bd42B,18,bpyyyyyTST +0xd1fBA6A5627d2928CC47E0e8a9185B6FfbF04b04,9,$BENTO +0xBa5ECADD909BAaD62f27ABA6bc954fD6a3E88DC4,18,$JUMP +0x79cEad033b8Fb094824430460878B088242D4B4d,18,LIL +0x54ddb5dE08584206Df4DD5b50220764C6aA60fD5,18,bpVERIFY +0x10064082c4F7AF72bBAC828c1be0a847C960d6C6,18,0xBASE❖ +0xEC8C277c038f314B139aB903Eb8d3804077ed6f9,18,SHLONG +0x6a02F704890F507f13d002F2785ca7Ba5BFcc8F7,18,pITest2 +0xC53f46d5D2d6adC7034087816d5325940074Cdf1,18,pITest +0x9a2c7e8880e1D8604b1717CeabeE237Bfa778F07,18,pOHM +0x3Dd79d6BD927615787Cc95F2c7A77C9aC1AF26F4,18,pwBLT +0x6C9730f8a66e8aFaCCF83C9696491022d1521335,9,LARRY +0x20cC61a01C9A1Bc760f7e76723FEA8D49104c121,18,BLUEORIGIN +0x3e4a45A93c00d2a3378C63b01273d92C0B4c39af,18,SAM +0x656761096DED90817e48749dbF587FB5638D91Ff,18,INTI +0xB82679D491D497A042158199220C80Cd34B76200,18,BTCDGN +0x0b7606D95D1f62175Ee026db5425381880A62a94,18,COINBASE +0x4da78059D97f155E18B37765e2e042270f4E0fC4,4,WUF +0x2eb50E7CB1D67A801552d1fc318E915B51780195,18,PRYM +0xeaA49C03897455BF0518E7Ddc6E5129226fF1A74,18,MAR +0xbE81aeA9FAf7B58b596fe44d529302c025B3Fce2,18,Symbol +0x61C50d8529ddd062F206cBD3a5c9DCF30E6B3BA4,18,BotAi +0xc012eD3365287c0856c22bcaD99205c06A857986,18,Dan +0x5B0373a526309FB73e6EF07cEa2D288A837BcF14,12,ITM +0xBa33d66f3B1b33170c30B9307C70E43CB73D40dE,18,BASED +0x16b8839e661B51de71Cfc1996a746ab8e6f84C8D,18,DOGINUS +0x417f42E12321Aee4D890E6cfcfa4842A3F41F4D2,18,HKD +0x59eE82C515b7D01DE1e2c62fa588456f2048171F,18,Moona +0x6476eC977ebA858D9f0b14a7DcEa051Bae5B6bab,18,BABI +0xA82b60E31E59E2ca9e198Ed066e0A946063274A0,9,BASTE +0x0C752564C32d005298B474Be0A213305602394FD,18,RABBY +0x878FC835F527Dcc8F2319783f546c6797415FF8D,18,HABIBI +0x48e75617382EBdaF71D96E5B0497B906042b5f1a,18,HABIBI +0xD0b52C8690E0c62c62355BC5f659f44D77851f00,18,FRIENDS +0x5d615C0Fe1750f6Da4870516fa7b66bA74e6F2D7,18,TFLX +0xAe8b8c672ECE1ca3dea4E19dAD406dD27e9709fE,18,HABIBI +0x99A20A5AaC1D2c6c2F0Df67B25970Caa8EE6C03D,18,TASK +0x67BDA415DD9BedE80Ba444D289fF7AD7b4Bf42C5,18,T69 +0xb7C18989F6F0932a87633772b90c1bC9BD0EC7d1,9,$NYAN +0x7219204037b2e7853bC57BcA4bF74a4428105656,18,$DT +0x34885d09ade6148BC3f5f1514562C1839132567c,18,MMAL +0xb8E75dDb0Fb11066F509352A249268E4a793F58b,18,ROBOTT +0x60874decaa2a9D7beacAfECDa38ADf7dde546AD8,18,DOGMEAT +0xD5214Aa867DFa6166B0489Da17Ae6012b15Dc670,18,SHON +0xE69dD38823d62b77D2E6f5c73a2D3F21AAd7701B,18,DENI +0x790Ac212a0d205E355dc779E3e979C4C9dE10805,18,MXA +0xDF61175de699b046F7beD166992dd05fa16c96Dd,18,DENI +0x3F458eeAfd1d66C2E305DE31253aec3C8B72105d,18,SKYY +0xAe740D8F907C047b37263A672E7078325a648918,18,BIF +0xDeF7C2e9a4F53Ae0d9F49515E1d93fb370f31DCC,9,TGR +0x99C0C995dBC6C12fE0C194942eEb6c05256FEA21,9,Duke +0xf2E69E2cF5d9Dc1b64bd3FfE8260137f4957d0c4,18,UT +0x618457ac0a73527FdA92e8B46550BA9E9A0305b0,18,$MAL +0x2029A5940AcA9e8B83C603b8c47D182b1BE42dAd,9,PEPE +0x53ABA78e8ad49a0Ba707C192fC328A3E18E4D786,18,BONKjr +0x788D6C9F15336A5AAA250fdF66d09BD00E406c3B,18,UT +0xb5b9ba1092d9146D5a75E7865c1f2A8B0F602DBB,18,$CRAT +0x8557Ed4Ab1B82B229F95e576C6d7654384147975,18,$MAL +0xa81371B56595B944521F7af8168C62D18BB4E3d6,18,vol +0xFc2Ef1FD1B14e1A0d541Ec76786134266e004164,6,MOON +0x1E14dB39A9Ce499480B0eE31d0394Ec41c542596,18,ZABO +0x1824B97330e593871e8a95B56Caa39F90d2DEe10,18,0xETH❖ +0x75a235fcD2510430cAFB09a5458BA5076B4383aD,18,0xBTC❖ +0xA6F53C160E839AF6D24833F48f2703BA5bf89c43,9,SDREAM +0x12E77293B8f2362C8B52517759B6c142C29400fE,18,Husu +0xC6d5F1672ACB88DF3E439A34ffE2AC838EfebBac,18,SAUDI +0x6175c3093FbD6f979299c4714E3715Cb1edB813A,18,LES +0x19c6F0233D757105d1A597fFa26FFC088Bd3950D,18,RTEST5 +0x53b3A3f06cfeba946Ddf558B816BA1E365f2b40E,18,RETAIN +0x9Bac547916B38e8Ab045870a166617b4C7065765,9,HK +0x2bF890fd6D9A05A45Ffcf9520a332bbfF975eD83,18,RETAIN +0xcF90faFD9C0F76221Fe893079696BA01414aD4b8,18,ELLEN +0x893A6c825040eF2C19B758D839805cA4F4310Bd0,9,COBRA +0xE12D9660433b59c4e718b265F259D6FA3B14CE70,18,ELLEN +0x27ad8206931d1C4C8C883ded9Ba15ae4B007721E,9,AMTYST +0xf7E7E35d4863981dfd129BeCFAc9fadb0daC1617,9,FOE +0x9675C1af50b8f7C08C41fde4d64d5311636B879D,18,RETAIN +0xFC633883219988923804047a919f46a93696fE60,18,ELLEN +0xA36bC4Ba77c9d82FEC88179E88406D706C3c6d2F,9,Garn +0x6A2d1493ACd752733B4557C686422dAE426B81dd,18,BOTTLE +0xb8BfB1d1029f612907852C8a81695bcc42161858,18,TEST +0x664a1B9e8D9953D228090C920af4bBD043dFEF00,18,BCRAFT +0x415b9eB67B2158c1573B634cbd93448780Ca4F47,18,PepeQ +0xD379021FBDB1F4016e3A0d356286c1553186ed4e,9,AELITA +0x05a1f50E16D8E6df16a8b09127C7d146a13073Fd,18,BOQ +0x69bF69248369d3EB1F2f6b2619e7ea2e95CF9f50,9,DBABY +0x1531565c5d50FE2Aec8f74cF1cD216495540Bd63,9,DAIMUN +0x80a5f4667f5Eadf070224DFAeB726B4Ac5c5b21D,18,GRIND +0x575Aa097ffD2Cd510A3B7aeD60cEEe345B702128,9,COODOS +0x4f53496eEb4AA6FfACe2A8F80a972C2F5fb7f8F2,18,basedCZ +0x34E828Ff1289b567a95e1e0535E0785b0D6f2D35,8,test +0xcb53672058AB58137A299fd5002B95C210e77e9B,9,TAMPA +0x6358591d865a627E0f180194BE7AC58d28CD00d2,9,BDOG +0xdAe50998AB032b9B822200c9a97bAc6742C8F68B,9,BDOG +0x724EBc3f491F6610ebB75E70c7b1751BCd0E624E,9,BCLUE +0x4cB91E96D180E07D3bd9E358ba5A67649C0D6D95,18,TEST5 +0xDC7D656bAF4BA6F486239C5e7d15Dd58b74344e3,18,GAZO +0x5D3ebAccb0C56Abd784C1c823b8013BC3e6d4547,9,TEST +0x02C52D96579E1b7E010EDc9D566BDb66067f116A,18,BREM +0xfe52C596070A09068009268cE1eCa3b1B8c6E210,9,ZARAJ +0x36920A48B417A7cF81C5d1E81cF82E430f6Ea5D4,8,YEX +0x065A793C36FCcb05D142A7E603af4c2CB7Dc8198,18,OCS +0x89fd904812e089d74dB40Cb61658bfe0812314B2,9,ZEBI +0x7FC0f388345EC0bde2BBf03a29d6080a768f74d0,9,CMC +0xBEE0564410b1220F63f4698bf786f59576793a82,9,TEST +0x60ed790D2D4890E424766A8f8aAc608e0CD2e158,9,ZBV2 +0x0118C06c3f937B663C71E6D2071986a4c662356A,9,INDIA +0xAc2a91d7d40F5Aca66CeEe99b831e5881Ccd9F79,18,USA +0x0D36Ca282F0CE2a966016cAF6304dd2317CF61B5,8,text +0xA435436372293Fb1835eCcd6d515D261317CcAec,18,DGN +0x033D056bCCA5360f9174e3A36fD9C3feF523A2b5,18,GRIBBL +0x35BF2c9D63a431F7EADF33DCc941f77FC9Fec1A0,18,GRIBBL +0x32e75f26e8Fa667488697A6908F3481b5d7bAC70,18,GRIBBL +0x32839b3d4DCB064B5BA8ff83366ED02CAa86e344,9,USA +0xb5012898772a2EBE73eaE3BBdB90376C98418613,18,GRIBBL +0x9243d8C2Af02C3F714eAA2F04C45aC5D162f7eD2,18,based +0x95545E6155e07a9E3C4f452e0C032EB645dcfb64,18,GRIBBL +0x1e7d250B85C0cf9873A2742d32Fd2667Cb65BAfe,18,GRIBBL +0xaC0D07c433d3Cca009ffA62ccDFB9A70551b7859,18,$SD +0x985a22Ac5f328Be12AEC0928F4cd037066D80EDe,18,godzilla +0x3ed208Ee0b54d3C9EF24e47544D957A0D0ad2FAC,18,gojira +0xDc4b46b5D6f3F99dD964b5Df6794c04126Dc1297,9,CATAR +0x81A975f090B6D58b53d8401591Be258b658Ba960,18,MOULAD +0x8B59408c9FcA76890b254b0671cb9DD814C4886B,18,RUSSIA +0xFA0eAA2E0b6E0C5678e69a4d0E2e68093B4527d7,18,AUTISM +0xA6974a17006868caa6C8A56B6eee8CA630Ad0444,9,CATAR +0x16FAA41FE9af4E57eD359DBd30d40367d401e9A5,9,CLIMB +0xb39cd760ca6CEBef5c8DB921dCf727642704cA0F,18,ROCKYCAT +0xe9109e0a2C4b59ACDA6e2e1A40E0814Ff922a24f,18,AUTISM +0x73aD5C044F6F5a242156B3Bb339f57beBcC8e312,18,SHIB +0xedbF01425044b2f649470e760af4E6da6360792a,18,Zombase +0x2ceD72800a97fCCa1d66e68049B9E662309C7dEc,18,FSWG +0x3Ace0f1f16F84875Cecdba1C6a9ff86Fe2eC12a7,18,KIWI +0x7e3a41F9aa73430fD6f6a7a62fC18d24632f0322,9,PIPE +0x4bb664CC1Eb30f2F12AA05952129d457407eA095,18,EVENT +0x3c4F23f82DA277F0C6cc8414505b65f9ABa8F86B,18,BUDY +0x8A0dEE598bA3e90c27e6D5AbFED6Ae2d48580D6B,9,NEON +0x87E669C4f727b59fF730dE9a772D0109330eF1Da,18,PRD +0xbbe45Af264feC09ED477630D96bB37683611F4D3,18,404 +0x2156006a207A793B4069a2B72BE58DC2bD759232,18,COIN +0x702ad32ad22F74d1d17ED2fd67E0690F5979035C,18,HOWIT +0x80b900A27CEd457eD1797B6F36523296C4e625f5,18,ENGDex +0xD4f074455ae0B0bF30B05C42acD105E5d2bEB8ba,18,BEFE +0x8a06Cf177ae2B9c52d68cFCCEFE8DA01ece668a8,18,BONKE +0x0E6a490ad60BB67dB54cc55AB39a642909e41D46,9,boden +0x59DD0Ff34AF1bc043364f7061908279B9fA7e157,18,STEAK +0x98637981fB6170AbB0F1bd998157884EEDCeA523,18,TEST1 +0x176cbB77c52dD5fF1d2d955E36519643f5e19710,18,CHICK +0x94d100aab8e5630bB4D2eE8aCBb09eC49cA07739,18,🐸BROG +0xB9898511Bd2Bad8bfc23Eba641ef97A08f27e730,18,BONKE +0x86e4E87da7ee6d6d561E09f64804a3288F1c27d8,18,D2M +0x58C55e82e52AAa96b092678250ad9F6e769BfC44,9,SAMURAI +0xfaE1e0514084F93974d3F5A6aA5c6734D8A85E04,18,TRUMP +0x858F725c1D3Ee7eFBb7AFcA907c705ef01dd8c99,18,🐻BORG +0x6801397C7b1F133275743Fa2305C2E7D00C0FEf9,18,phine +0xE67dAd6B09E3590c08F11CFeefCE088e3CB3a815,9,TT2 +0x8103F536F7f04837a6626ea2AeD8e5e56274756E,18,Phine +0x291Ef94B5ef8cF6a44A30408EB010b8747d8C7b3,18,CAT +0xB0bdeAD0689839890F6087b90e3f504d321E6887,9,$BOBDEAD +0x1b49D0ad077589c0945B732772ea48904Ec2b142,18,BRIAN +0xd64271E3826165303f90b4a7973569Ca4ec807ed,18,WALT +0xE215E4dDb4B00f680Ea66b48365Bf749C1a3a4F2,18,CZ +0x5A86197081f8aD549D00dc87D1BE556AbE85dcBF,18,TEST +0x49f5669bD3e7AAC3e502Af6Ae02884063b9Eb5e0,18,POPDOG +0x8E90708bfC6eB4FfC5eC17d19f3706fa65F4A6C0,18,PANDY +0x1Af923E99917d38de53D8282D71e6d15fBF0E1Dd,18,WIPH +0xAA5B8E0ECFB4f8e2d7843D580Db0BF02BF25Ee74,18,normom +0x3840F6a5676d8B38a6310492ea5BCF1B495A9Ad3,18,TZPHINE +0x5637368bF042977fEAaDB7A222e439B5a640948e,18,BASEGAME +0xFDC9D00609d5150c988447B7F0389454d49D3706,18,BGUMMY +0xf75A757F9bfe1F92f30a5Dc79DCF6798145e1Fa4,18,REZ +0x7afE48fafe626C9C212671cd6e34d5a1a7CccC84,18,GGG +0x91a96e9649a45aB674B2C336CAA1D7cA3B1d46Da,9,PEPBULL +0x9C5F31FF2Bfa8240bFe8606a880C8F52A20dDb7d,18,REZ +0x8c72e70656d8cfe2a320a5D25cE2358bf962a769,18,ELON +0xE830DE8ec53Ab96De37a665C73fc15395c92B661,18,BASEGAME +0xed3211Ab553852e4660E68B4D51E3B61875FfA2A,18,Summer +0x322E2BB894288F621046B41bacAf2030d4D48f8b,18,RARI +0x1D4F6893CF76f3c79Ad385c96b83afd0fef6d0e6,18,pipi +0x76c7E4dAa3027D1b97aa4148501F0AaAd223f34F,9,SKICAT +0x66c9bDC837346101a41fb7915B48140196Cb7Eb7,18,🐝BEE +0x98BCc780A4bbB599E69C5AA00c7a7Cd23a5f1b6d,18,MTK +0xa91285EE637638A8485c8aDF32c67d1e62819Ca4,9,DERP +0x8269C3A336FD5137c845E15145457947fFF09d79,18,🦈BARK +0xbdB68C97FC37Ab43d61b6Bb5732086145917865b,18,AIALRT +0x32a687C633216638B6D4008b08927838E39ebf78,18,LIMA +0xCEa8a2B7b3C05A44F9eb3aabab6528DD5EB24c67,18,🐷BPIGSY +0xb21500356E42C18e42fC9C9B3d47e7A9394751Be,18,DUCK +0x13e3728606cE3bd35F9A9C424994EECE1a63a9b9,0,GEN +0x7D5Bb368392712b855Db72Ad9966e70A7d1291f1,18,🐸BROG +0x7cF7B2418343CED382F2455225119CdA47242AaB,18,ASABOVESOBELOW +0x57d5a7C97d43521E6dC55BDc7925F3C194BB871A,9,GOAT +0x806Dd9E6b3cf3bbA7d9EC52CAA87be635bA8d5fA,18,🐸BROGY +0x3cf0566656D56481C6189C79fA50D73ceB3e85dc,18,BLAZE +0x6AA2755D4b9216727Bc7CEEb6C58B946d2944622,9,BROCK +0x489763970679EbD87F68f3B1F774981DbD18Fa4b,18,FROG +0xA08981A4DD90eB8bE171643897dc415d231E7Da1,18,BASESCREENER +0x0e671C1769B624E9865090818c606D205C296567,18,RAT +0x5b69Edb2434b47978D608fD1CEa375A9Ed04Aa18,18,TEST +0x9022c88B2E4beb374aF8CfC499A86Eeb497D1096,18,PIG +0x840D4C4d30Af1C8eCf9A88d8f89fc7b9AdcDE0e0,18,EWE +0x7fA7BF4eD36692D473A237681c32fd2E4Ff7c305,9,PORK +0x5633B35e713E10d3b903D6AF2a93af6A1fEfb219,18,SNPE +0xA73225147970e338d27bA3eCc41F4c2f0f770b71,18,FRGKING +0x7EBFA70685ABaf47a17c99c89c1E1bd9F4e6CDB5,18,TRMUZIK +0x515cB82e27FCe24DD433F13399b7BEbB000DB676,18,MEME +0x0740C8F438cEbAd42c9D3E034Fa71A37941B6783,18,SPAG +0xfF5588A472Cb1c61f22f5Fce93F15905e1964ECc,18,HAM +0x35AB8dF362C328784C06eB94003E481087E8B509,18,WOJAK +0xB00b55FA6e8D461fb2a21d67D20Ea9186448DAB5,8,BOOBS +0xD8045A207A735934dE3044dF475ca409Ead87598,18,BAMEME +0x9022604cB923483916c85E94c570D798E7A10A91,18,DAT +0xBB467Ad0201986c5B6Bcce2EcD23502fBA779cdd,18,BRETT +0x1674C0C6626dD52c3daD12E8963AABCD992e2A31,18,SMB +0x4B7Ccc073E896fA99E0945Cf106A7B25b78E8f2A,18,BOMO +0xbB102140Cb7fCED7D572201B32A07333b61d0508,18,TOKEN_SYMBOL2 +0x419112D60Ba269AFD155023bcA602262f58DD0d3,18,CONY +0x8ad4bd06Ec3c744fB7Bb9a4ac3669802E04F20Bc,18,BONE +0x79654DD29aC3e23b409DB9e76D9Aa5F54A4f9CC2,18,PEAKER +0x6D461cE72Aa3Ae04B987A2F0c91004fdaa1e01D4,18,BRIAN +0x21b9D428EB20FA075A29d51813E57BAb85406620,18,SYPHER +0x30F21AC6ca967533Af5985c26E60a2697F031F80,18,THING +0x6cA4054c3389E8990832b40A4f9181Bb29358354,18,LOLAMA +0x4f69a64926315B387293464513755a182318d5E5,9,GRETT +0xBB925676EBc735CB13a789E6Ca3BdBbA897E3b24,9,TT2 +0x197a233BF35391cC0751B60a8C2e5826D3B3aeC8,18,TOKEN_SYMBOL3 +0x980A3662DDbfFA895Af03C54E7B97CB3Bc868ed2,9,ELARA +0x5484cd4aD74b7B1b1fba0277E8227cB0f8581651,9,87 GAME +0xC4B60B342f636B244326545d18DEe198Cca75a52,18,CONSENSYS +0xDFcF1505DCEC4F745191C7b19F9a6a589406B175,9,EGG +0x7D18e63B5c400B52bda32E11b713123dAF977B10,18,SPARK +0xA4089E74354B03B56d75961a816f71432ff596f7,18,KFC +0xD586f2E9d876a970d61DA29c8CbbDaaFDe5FB8eC,18,SWM +0xF502Fd893AC0f416c745633d95A25dC83e16991f,18,FREECZ +0x173fBab48BA6AD560bA4AE0229C2C017c78D3Ca1,18,ELON +0x6087C06bc26D9eaF98519f24d2483904c68Dca8D,9,$NUKA +0x7BA075aF6e1a1990d09B2e90b9c949fD888C2F58,18,TESTBIDLIST +0x66b9851018b1dF5E7485f4A1135458dC5616aD5c,18,ELON +0x0c93C047cd3DAe729c4A40A00f2bb5b2B188e589,18,GHS +0x5e1773eB46E74F3a3511fdfE4ba730B3B50411E5,18,BOCAT +0xC138D50dD6d8d36E3252278e4990fa26c6a24CBC,18,COLA +0xbc2d0c8084704D9A0D1bc0D0FbB0a1927Dd408dB,9,mom +0x863E40e514Ff5819be58272F05E8655042d36dAE,18,DONTBUY +0xb572F78307a3f6126697A48BF4DBF00178cc12A6,18,BONKER +0xe1E88777bA95a9BAa44DC7ce96a33fB4F121833F,18,ELONCAT +0x43A4eC797beB5296f6a227cCaacb6Fb99BC32F99,18,FOMOCAT +0x44f91a50A7E9b6Ca0201007552d648412f595960,18,HELLOWORLDFINALTEST +0x19c978887B2801268a6c2cCdD86c756C196D2390,18,TESTWLV5 +0xbad61b71a654B3852a10b802c8931fe8828B9dC1,18,SHIBLU +0xd184F031C47B2070CDD498E418970DFFd00Fda2a,18,TESTYOULA +0x674ba47a05ef9aa67e5b2CDB75e29BE628c3cc0F,18,HALVINGCAT +0x4D223B5e3AfB70a40f26c38CC195F3fa2b563ea7,18,COOLDOWNTEST +0xe022cc46c89D55e42de76D34E4aeD9a66c950a36,18,MTK +0x19341A429E3E79110DD76add60A6f82B36aACe79,9,$MOAM +0x9516f22E7Ea98565AAFB1Ec129363a70E0ce7d5a,18,ECLIPSECAT +0x8ad5b9007556749DE59E088c88801a3Aaa87134B,18,FARTHER +0x0E36abaEb5D5A508618D1F159aE473F000787940,18,MOONDOG +0x7402DFca11ED44A48De760715b1Bfd78FE1Bd45d,18,CATWOMAN +0xd85EFF20288ca72eA9eEcFFb428F89EE5066CA5C,18,ISK +0x46579dD2c5E5287694Ed13359f7dcFE35ae2AA6D,9,$NAKE +0xb7C25B2E782C674863B702C9c560Fb0ee541e667,8,🐢 Turtle Token +0x1153B424b3F6A51c2571Ea06C5e9F6Bb267299a2,18,UDO +0x07839c30eE77A606551ad098dAbb0B5E86483FbF,18,G5LUFFY +0x87B7F955b8e3eA7F3c2500a9Ee9A8A7Fb24EBa26,18,BROG +0xb7B073Eb630a0aC8B4026DDc6790d5BD4997AC82,1,STTG +0x159060a3AcEE49f2d475f74A3818334e08b7D48c,18,🐵BONKY +0xA9e6F76880F3785FE69c09A646b68FFc88C783d7,18,BORGY +0x462438f6652790Afa014C173c0296e424548b486,18,BASWP +0x7B3B2d0611960e4cf461204Ec2FfFC67288ecf2E,18,ROM +0xe5Eb14b90Ec38E6357842D6537673f911fF19dd0,1,PORK +0x86426809C99AfF05406bCcC30Aafbf727F01F074,18,1 +0xBDc66999D8bFD1820D63A39D14e6afCFB78D2A7c,18,GIBB +0x507556D2E5505d669C95Ec55cecD6911764ebAa1,18,EUROPE +0x8F6A49Dc885F56b3f88FD396eb5cB23DA597EC7e,18,GIBB +0x28e29EC91DB66733A94Ee8e3B86A6199117baF99,18,BASED +0xA3a4273879e954aec3597e15904Eda408E3c4C5c,18,GIBB +0xbf8DA406799E527787CB2C357443933541A1Bd91,9,$MOB +0x733F438cEb5fA7D29D8d479BD3DcDA46E0C355d8,18,LEAP +0x24FF55e016c5257e0E8Bb27A2b082E9b0a607690,18,Oh +0x54Ea88F89f87F47607d5ffc1C7Daf0979BA15877,18,TRUMP +0x223A334BAe731E01Ac039e959DB538Eed7c3e886,18,BRIAN +0xa9cf3826d04E8C1DA0563A7AF24E5D1EBf04a488,18,BAPE +0xdD9992eFFAE4604F1Ed8982c090726Cb40DCc1f8,18,MNT +0x27EA5F0eFEa5f56bEB04FED2334Db9EaD10dE61A,18,BAPE +0x8bd1E2A0DE31D6d6A7FB4d0d50916Fdae3c64626,18,BAPE +0x3De7a5a85c2687c0E21e7b885569Bd0f0366426d,9,percebes +0xBEbe686538Ea5741950bEa2B60aF94b9499d834b,18,BAPE +0x1288b38eFdB52E28B1458766C9851Ec152E51a4C,18,DRM +0x0c007F33668e6eAe79F733E8e8057840E2aaA05a,18,BAPE +0x265A55A2632ee1dc780367F8c004509F3Da9E3a4,18,BAPE +0x2942b36c3e7a40ceBFCb3Cc5eF088E5CDf73ad1D,18,BAPE +0x68c8E21b6e7F136700A68685aE9c99DD3974CBB1,9,TestToken1 +0xCfB4e15c900bF1C8B51f60a3119a1A70C2f19460,18,BAPE +0x6721ef87a19560A4C8f6F39D33C4cfcB8A915046,18,BAPE +0xd43A1148ad5A8d8FFB4Eeab92eA12f381861fA2C,18,DOCU +0x2900bcB023072503bb496A923C86209B66D5d48C,18,BAPE +0x49Dd99A2DE48881944bD1c7718eFb42bd58CC1A9,9,$CASCA +0xEAB5917784285864a8F76FD3228DaA6b9134769c,9,PEDRO +0xAedc69B2e9873DEacB63aB1762D62b8d28AaDa65,18,20 +0x1Dea9962938ed7Df427a2493870F21Ece5C57a9D,18,BAMBI +0x246c2e3E0e5024aeD6192105575EE48c7ec489AE,9,💉 STIMPAK +0x4f030f9952236fb24b46C7c20C92c34A4Dc737d5,18,CZ +0x98B4793f8C7C76D47c0527Cf556b03c9Fe124a8C,18,KMNO +0x1243C5F1D0f64fA291bD5d44d2c7A53488F0375a,18,XEPE +0x4F388a46D83C167744bd6551faD1Cd3185dc876d,18,Bald +0x77cdA7dA3cBDFD41B08e9fE70F371213EfF34670,18,REZ +0x5685De28034D25A60c8a47405E83f4B8a814680F,18,PUTIN +0xf8B7315CcD5fD9c6DBF2e510C4A870013ec82aC7,9,TTTTEEE5 +0xDC4F74f4dE646BC9B19c2465f92f7f6E75Df2b3E,18,🐸BROGY +0x8daD3e3A74BDa3db599579F47057C169ceca5600,18,SOMETHING +0x39A2641250f349a9Bae3655D21Abd98532582FE7,18,ELON PUMP DOGE +0x5711b11EBe6a61d176606F7e7B0792C5c5548b1d,9,BET365 +0xEC3872544559B58ae25Fd5908F4A3F8C01a3147e,18,LORD +0x815066C8A2e9698e72257E61d5Aa477e725CC9E9,18,??? +0x994E7Ec1009636D1ed4632977C9F98E283501708,18,SPPE +0xa042d74EA8B28C8C1BD27f2Fe053ab0428425191,18,FROG +0x49af724c286b70f7EaB43abC57af5c0102f1F89f,18,QUBA +0x498fcC525A983ebb5A8c6061D405611C01305430,18,BONKE +0x4ea43C5aD2a4b1c6bd226eF3ABCA559394663d61,18,BONKE +0xa9791Aee0D9FC36a4d1E9838C6e642042967bF8E,18,BHC +0xD8a861E74Ade43262C2F36c8c97E7D546a99e50E,18,CALI +0x8BFc82f5275B397e35DFeD4DfC776F2e64F59B18,9,WOJAK +0xe54CdAacd9CceDB9643E52B322B465fDccdeb3bc,18,PepeQ +0x395061889b9F14DB3E95F65B06438773e22b441E,18,THICC +0x70bd9B4619B0197648b975b947FA831c4205e023,9,$NUKA +0x6fa0e59aF8146DC67ec70e9cd8E0710EAbBc03b7,18,TRUMP +0xa8Fa69Eb0ac6851365BFE1bba0DF65E724Ee92f3,18,BRAIN +0xB931b8bE093AC0285024EB56Eadc2084367ED1BB,18,MOONDOG +0x05c2931dbd96D9e25Ff5b46ed2349cb73a71f5Eb,18,PRPE +0x22b27243B8c487Af56c14770f2e1B016874051c3,18,TOKEN_SYMBOL4 +0x1c8C3Fe80F1F54aE40565B49c226c2CeEAde9b09,18,SPACE +0x86Dd542C44DbB3A689ff81631FD201C7C99869bc,9,$TIMPACK +0x5a82e4E0219F034E81FdD05c0150EE8861bd4AeB,18,RDY +0x0ca85eBD24a3863A9b57DFa6DFC25aEcA7EAbAD1,18,DA +0x6B6df06D9d4322c7745b590D1D7bEa370134348c,18,POPCAT +0x9e150Eb6063db98B823b5f37710040E6366a3239,18,?! +0x67c71ae37aEeb690ba60e9DB49EBe0a1d06868Fb,18,TOKEN_SYMBOL5 +0x78734a386Bb0313EC59Eedf93D11baAE9d7b5465,9,XCIT +0xe33095626981d6bDB51Aad2f63C647e92Ff06010,18,BaNDY +0xf6D464d9519b3eE9D823ae97613a967a4Df270B4,18,AISMRT +0xD266C63335372E31EFb36159D55b4271AF194526,18,FREECZ +0x3c9F337f0e09176895212FEC54e636Da6542120a,18,PUPPY +0x5E8d6648d4468D84c0A0Ad808F77Dc71Ad160783,18,SDREAM +0xD8B3a7C2829A22E3DC38d6b3D3ce68a4B6E4C1fd,18,4 +0xf7b82126129AB26fDE257658165BE34119201d15,18,GIGGLE +0xa1306c332EDb5CDDA7f996507fB48F2c4126D621,18,SQUID +0x4b369e1a2D16ada09D734b1D8485B9d1C5921Ce6,18,Friend +0x5F65611394ecBBa1A7Bf5906217d79f31BA1902F,18,BUGS +0xABcD7699401926E6d05566Bd38Da95aD4CC49D9e,9,PepeQ +0x0504fB2c71755B57A1CA19118b8cb15E31f06535,18,4 +0x499A12387357e3eC8FAcc011A2AB662e8aBdBd8f,18,STRM +0xd2Ff7d417F8528c62C2dc45804bEa31c77117c9e,18,PEPEG +0x3A5483d7fDcBFA1e1a42d8BBb7b3e2EC58024b55,18,4 +0x7CB900c533bEBB545cE799F1A2d6605A592091Da,18,GIGGLE +0x15De59489de5e7F240D72F787dC4a292b8199339,18,RBF +0xD1A4B3c0264B5ef7c05fBeAEA153e2c616180F1F,18,4 +0x92988d3668d3dF8214249CF6e85c0539B36458ab,18,TESTB +0x9D1fA9Be2212062de90228Dfd2F4273e531658BD,18,TESTAB +0x50047c53A1f233234C41367bc743BC1bca032e94,18,PUPPY +0xAc463174c8109C61117E456e9Db1C344c9A26FF3,18,GRIFT +0x6Aea4753Dd14802Ba4ABE42E9007F66CADfdddE3,18,4 +0x2C63bC20EaDD0898Fb70f40DEBc4d2c8A51F9629,18,CHINA +0x5c3BB62473788fa0E8D64c752F44c58325e56b4C,18,AWK +0xAAca2Ea30e24D8f31Edd70Ca5f7a9Af8e4f258A5,18,🐸BFROGY +0xBC3d0f16Ddbc9595F03cDeCC03149dE96716F18F,18,FJB +0x9AB5e614da0567Ac836C0b1Bc11d2F8352F483d5,18,TIT +0x89CAd03A404366748Eae121f83d4239Bf795Bc0f,18,CZWifJail +0xD6D73A0c1fCd72c181A2f2c0164aF51347273228,9,FROG +0x90Cc282444312842082ccFf272af10D7c8d9e415,18,4 +0xFc8cA9c96d9adbdE34B005BA8fb19394d07593B3,18,BOMEFORK +0x7FE5aeCE12Dc0A65087405c0479D51aEa63f1B4F,18,CATWOMAN +0x9584B3E63895E277AA836031E38914Ecf732c0E3,18,CATWOMAN +0x12Fa26FFe8C24d98fC90b5276cC771482695A665,18,KUKA +0x788F23106223c5233605b1d981FA8938E77D40C0,9,UPROAR +0x6dB60E89bb084C0D53bB3415647800beb7241C27,18,BOMEFORK +0x745127667a36b0600e9FF6d19B9C4523D034F820,18,banana +0x4AA3E2969d402e640912Cd9BDEAc1C363687c8c6,18,13ETH +0x78a6e5A4Ca891728815e8d08466bFF4d92b2d7e9,18,BOS +0x3015b0BE6eEbEC0c628f5Bb9484d66bF9b1c7561,18,4 +0x1D24A76A12f703e444cF755dC8c6999D89cf125A,18,SAIL +0xcC3878530D22ED37c1086b5dd4b9cf461CDF3f3B,9,$NUKA +0x9eEAD3f715e9988f6700cd608689a97d0330a08c,18,FETAAI +0x60D4d25D8b187e6B4c3c1E81C09E8508c2607f40,18,DOGO +0xB2A99576C01A06c193266A4b46a7fD0f9F31b9A6,18,BS +0x066DF6Ae7f762D850932984F0111E2E95d45aE9e,18,FROGI +0xd8A57617e3910ffc08b2A5981BC1904769d499b9,9,TACLOL +0x80Fe9e82A8E81288597E02A054C52109f68724Ed,18,USAvsRU +0x6d803030f4B34b14bBdF07A8Bc62C62A9f35119c,9,FUNGI +0xE70c09c141e59bbD0010767152783B5a1F1efBde,9,FUNGI +0x087d4b348BB1dE3279D077e4ce1bf94c656ed0f8,18,UNICORN +0xa51910cd166722220240D5b856c0cc09568b0D4A,9,FUNGI +0x10Df04EFfC8Eb48E3106Ce3d1062d3115E174f40,9,TACLOL +0xCba2b8E12DdAEF9Dd572a3938c849BcDFE4c4fF6,9,FUNGI +0x5e63AF52db227C38c6424810c282A1e1e7Be9cA7,9,FUNGI +0x257603a3Fb55D293242Efc74bE97ECaA23cCfedA,9,FUNGI +0x6Ff6c03AFB17599E27DB87E85ac476F19FE29a31,9,FUNGI +0x45dd297ad8376f005cFFC6Faeb7395d5396e83f6,18,🦧BAPE +0x4a6d30FeEDB3329F1DF7547274f4a052141dF5fA,9,FUNGI +0xd6aF14b278A168660cFA3F10ac546c029C4AA191,18,CHAD +0x6B046C9Fa06612b6716f13dB7478cD19A191b80b,18,YAP +0x4C74F070229091f3786d24804D6d77224e0Eb478,18,🐸BROGS +0xa720C4669c56E29B1307e8828D1FC6a7ae7E164a,18,AWK +0x41c1156437BB1bcde2381908DF88ebd30e06EB37,18,🐦‍🔥BFI +0x86DA048dd6C688FF4DDf96d3ff930545c7FBA87E,18,🦦BOMER +0xd487a20CF26eb8E9cdc8a7C2430895Ea7EA4C628,18,BASEGAME +0x80821deDE402E4c2C4bDE6Fba556c94AE26B4709,18,🦦BOMER +0x360B98823c6cD060bd7A711f84852524D5f3BBa5,18,BALF +0xA96F21CB9b8Ab62BDD643DE59eecDda048c7E17c,18,🦦BAMER +0xf18B801B616b9C0B81829E7Bb203d8F690B7CCbA,18,Trial2 +0x45AC7Ee3Eecb9FC052CBbE0Dde30D6926EacD637,18,🦧BAMER +0x08FfDbB106FfE4A8744D8561Bf115712AB7cDa5f,18,🐸BROGY +0x25F160C0253a8D36Da37E8d8b973557A242cc988,18,🐸BORG +0x2b2C63efc494beCdd46F2a76865487FCA0B537B2,10,$BABYBRETT +0x0BAA2074FC0351c24B9787FAf54AD720663566dD,18,🗳️BBOX +0xa956efC871027eF364b19884aF6780346Bc68888,18,DS +0x24C58B14e27bD9482903A423144421a019c5ff5D,18,SKIBIDI TOILET +0xEEE388746D1C95388D4DB6135181E9E3c9A984c1,18,🐸BOMER +0xeC489d9986fcD5F4ABc2B81d47ea3F7d8332DE74,18,🐼BONGY +0xe62BF3482AB46Eb44b16d44fbD3F90Bd600fc4a6,8,COFFEE +0x12580484eA3cE40438E6FCD1cA5Cd87a3cf24279,18,🐸BORGY +0x2EE13A1bE52cB8c365bDB29Fc9C4A1fBEA520324,18,🦥BLOTH +0x43D6445340D5a1D9d207300377Af08eBF3Ff87EA,18,♦️BGAMES +0x6ebfE7B0d18C9B64C8735b4bb7C9d03C456622e6,18,WHIRL +0x6668D4A6605a27e5Ee51edA040581155EddC6666,9,WMSTER +0x226fB3663C34cb07bA4269871fED8957C7B3C92E,18,GC +0xAbA67ee06FaDe40762d807DB9104Dff768F701b1,18,🦦BORG +0x99584124d4a94CAb0662739841e12754261856C8,8,COFFEE +0x813637CD66234FF152f6A91572B9d01a320c6332,18,ARTVIBE +0xBdD77a697bf3eeee8B7B17E3cA2294654C61d965,18,CZ prison +0xd0b91Af5f0cf202671a15233AD3EdEcaA578645d,18,TECHTRIBE +0xD3e0750E36738D0b71697E0b220E323A9a78ffFD,18,NATURE +0xd1128abB1de375419cdD709E5CD52F8741C57896,18,🌀BASEG +0xe6FA221bbfFcc717B3A0118cf204F676D3037471,18,$NVDA +0x21578956E85fD3920a43D418A08343695e91054D,18,FUSION +0x77217282E696ecc257a3b9392d317eD51a742B5f,18,CuteCAT +0x06576714914858aF94535E89d465105Ca8ee52ec,18,INTRINZ +0xd77CD13c2a72b20668bED8899321DaF97404fd71,18,4 +0x91Cc30cdc214896aA5846e2DbC2E164E9951e0a6,18,FOODFEST +0xD18879b9c6Ce1C7748700c1828bdD0807d028DB0,18,BlackMamba +0xC89828ab091c3E456363C28c3C1810816F45171F,18,STRAFELLO +0x1A005D28ea42e488Bf0Cf697340Ddb57aa99da16,18,VICTOR +0x304b6bc6951673151D4C008F7a0D93061fa4c470,18,BASINGA +0x32Fd7d5E040ECfED6cFb515E3Be77abDA12468b7,18,MUSICIANS +0xaF3dD0a3EFA93d241E8792830f304140F492499B,18,PALOOZA +0xa3FEd98622e304bd2f9616aDB75Bb018593bc040,18,BaseCZ +0x1B0CEd3847A4d7aD20b62D2888dF79cc02Cb737b,18,CHOWSKI +0x35C89d505D454200Afc626AA5B889821c0a782Fd,9,MOONER +0xDEDe7EaBCB2CcED33176C8A9157079D6F0d9D07c,9,DEDE +0x8AB62Fa73f8af2AE2C9473BfBf9F32A19E79B019,18,HODLV2 +0xda5c5B144340Ce5764Bb27e7E70704cbbbD7dB1a,18,TESTBIDLISTYOLO +0xbD028c5Ae52718f72771B736a051c99E127f700b,9,ELON +0x95FEF47A3b34ebcb59BA29F975C0F6c8A99dc449,18,RFC +0x2Fd4EE867C1A81228a930a688Fb9A543e427c07b,18,test +0x7A31512FB17BE839B24276C211E941932c9D20E1,18,Nippy +0x922bD9FbF286B85f54e17afc84E4974636aB6Ce7,18,Boysclub +0x926b2b9b7CdDEB454e1C97bd1ef0dF492300C0D1,9,SMURFCAT +0xb3b07559257418f8999Adb476d3Ff81a577fFc05,18,SIMP +0x8724AeBBc83787457977494667251485038e6f04,18,IBET +0xBc72c1Ad220315Fa849FF237Cf5DD0ad0Cf75C73,9,cats +0x2266E0b44A93F1930378fead21864d93F923dC75,18,SOMALIO +0x12727921A8C6A22932cf283f3677d9F8AaA6BE58,18,UNIW +0xF3907Bc0FFF5Ff5aCf1E3dD7987005779C7bf57d,18,SARCO +0x1DB95BF1980688f68602b66188d361195758c0FF,18,TEST +0x11385D53d3436FB61a8272fdb8fd15fCb12bEECd,18,PANDA +0x80E3Ee7bAB68fEAea6e01c44df9daa5de53e4818,9,DOGE +0x87841b30Cf177F9EA30f40f6844a962D57f6877E,18,STEALTH +0x5cE4913fc24077B12cb67485f85C7D912B0E27AB,18,3 +0x6e1E2Ac8F128c3A328C7CF88Eb2C5dD9Ef537dCb,18,KTESIS +0x0c7195F92E4C12a8288cfb49786E6a9a1F75C8d3,18,HELLO WORLD +0xD55b95a1B2BdB2496f4E1D41f577F97d036D300F,18,BUTTER +0x99A9cCEeE7A89fB4053c1b4729e66A7d5193AA93,18,BSN +0x8b22DC9BB9077f56aE2Cbe60705a9BEaf838033E,18,FREECZ +0x82649262b8414892b3227E95644D7ACdc7C76655,18,WIPED +0x6C8cf870d993199ceDF0d2da5D0DD3d7BfBb751a,18,HACKER +0xb82cFFFe1d76f1caBcf8A00774c0287d71702fC9,18,wRAWR +0x93587edD0dC6209475d9B5e7d358f7a40676f444,18,SLICE +0x7049F9083c13Fa2478da974b528af3236941A405,18,DEPIN +0x8c9Aa93a32AC5e0bdfCb7DD0B0117F9820E5FfA8,18,MEAT +0x6515Dea761BdF6c520a0DF344AE393F13EfD9DBD,18,PSHR +0x6710f92A8724383f5830b0D71e6911f8099dbC84,9,POPCAT +0xEAC5859De259F57B007FbB9fcC4b0ACEc2AC2195,18,YEHAW +0xa4194f73Ef5A37dFbC65E78082A9cacAd80a162A,18,PSHR +0xD3741ac9B3f280B0819191E4b30be4ECd990771e,8,DOOMER +0x3bBa64ee0b7428816831101801f3F45B8618d47A,18,buno +0xe1EF3F26B67857AEf67350Ed58BE217a6a2EdcA1,18,DOREMI +0x2C87923DDFC87eFc0413253835D35926770A8807,9,DOGER +0xC27Ca05fA66281Cf97EDDAc3fc00e1ECc067F215,18,PILK +0xF3eC3147D4f86cfB7308dE5F34D4CB287A16e7f8,18,FREECZ +0x575c6d7A1Bf7Ad34AF2FF5C29f110b48e13637CC,9,GOAT +0x1ABf86495551d6847d0D623C74C55bF92BABD968,18,PSHR +0x301002424756e62505e527b0B7EFF8bca3447be8,18,zazu +0x98a9F9aC20f72A1ACeCc4856de426AcF11d77170,18,RBF +0x36DD9128D8DfFbb88F2aDC6A61097fae111F1626,18,4 +0x63fa555B66cD867128cFEf7F6080D6e2D397277a,18,SULIX +0xb52fAC2702b68F38c8005D93fBAa54a2225751cC,18,TEST +0xAc7dbd7171BDbf4Fc92403f9eAc9742B1c2E3b60,18,TEST +0x387c9455CD4CACB5a31f4d79F4fcaD605F862C6a,18,lion +0x615a85aE81245a6a6a6155B65377b6c38C6d7c1F,18,TEST +0x20293c212D0305FB0DDF4955aEf69e325177F262,18,bfour +0x29747ff8F6388651ae116B1722cB4546ECF0cFD5,18,FOUR +0xCc82c277F421a52f816388f3346530BE1b3127A2,18,BASED4 +0x51707DC661630F8FD624b985FA6eF4f1d4D919Db,18,UNV +0x279e8562932CE694677C70c06fFD57C6f059ca06,18,CZFOUR +0x74d824994A940cc94651E6eD0Fd3e3A482a043c3,18,BREAD +0xb874a785C59289363876E3C301dA707f2F2Fff33,18,cz4cz +0x08f6b7280e2af851e956a80a52b20DAeE74973CE,18,FWIF +0xACAd1d3107808577022387C07512E7828694B2a2,18,ETHIX +0x053B8e1B9a6d12a4b04F4E00DDFE9C30C871D745,18,AKC +0xdf98ED5eCdCFcDc585C5f83D18f9cf567FdeCB89,18,con +0xb9cb29d82d84D2A5491c5162e57714047DD621E6,9,$NUKA +0x7C875604abBF9E832eE7535C9F05cc0B8EFE792C,9,$DEGO +0x338E69FDE17270B3cD5FA24655371d7F6Ec260b3,18,KISHU +0xd66A0991B63CB0cB9666d10416B1Db2E6B84C1c8,18,JUSTBUYBOZOS +0xb3d244D24E1f65199F04bF8bf7D01396B31ADb68,18,DOGO +0x57bB328A91657c817beD1064b94064f2b25f9D12,18,KISHU +0x4A980CC5b59F69e3498Dc24235CB7126D47ff68a,18,lion +0x7C67ad4a122333C404f9668D3789Aa3166031ab0,18,Exit the matrix +0x5C54C69C7bc62aD730ECa31b377010f7bA241A29,18,MST +0x3FD5EdAbe0F0C1685E0a14ba4f9e36cBfAe85ec8,18,FRIEND +0xA714Ecc367e00302d46b0a44cB2203C52Fef59f5,18,Zoomer +0x91Ba2806A9E5A43e15e7b81025CFfff08209985b,18,MOGU +0x5846c072C18fd5FE784A78224da3085346B8C2C0,18,TINK +0x7C16Aa51d658ad9A623dd066E77905e4179563Cc,18,MTK +0x75d337710cFF769090A371F8b014B9E6cDdda3c4,18,🦥BLOTH +0x53e1252C96B50F4a0B1D24f6C21b784E87b6e083,18,Europe +0x8950b90676F20Ec336626a4Ee61993bdcd3e8985,9,$NUKA +0x73FA0572c7f77B44ee88B78ffcC2ff519d2EC222,18,🐸BROG +0x569e1A337b095B1A6c8F206158072cEDb6325b56,9,MIDI +0x73b255353d4D76F3A3A35e37f49CCBcB90377943,9,FUNGI +0x14C7F3E2Cee45E439108313bA91ADA3b26e4d5D4,18,test1 +0x8fA11EDf65253c15372d7E7EC595D5628E8930eF,18,TINKER +0x694C79DDEa7Fc14d78070D1c2B7d4cdD0863f1dB,18,BAZ +0x8592354Fe71BC73544602227Edf5Bf59A500d9d2,18,$TRUMP +0x263337143b832B1E274F9E047cECc42305A2e8d2,18,Waifu +0x2d448bC9a98d28cB094722c2B8208916A248D5ac,9,MIDI +0x7b4674FEfCd10c9866aD1d8d49f3A6691f6746E3,18,PSHR +0x918BB976fd99F5f8418B859b9bd5aBba266c41BE,8,SLOTH +0x0EbB289148e7B1b492fAf6E30B7817889091eF1F,18,VATICAN +0xf7Cf2DF510bc0EC400232874f2fB4F2cDf9352d6,9,MIDI +0x874D61443Cc13716200Ad7d0c8D1608cAdc87ed6,18,BTT +0xD9acDbb82BB0afb8C0400419cc1D6F9c6d31Bf2a,18,SNSY +0x070899689d2a3158986f32F76dE266B748b29459,18,PARS +0x706b353fad1db63D6160eD415D410d46Dd5De453,18,KingCAT +0xcfe51959f913B08a82EC0D431e9455b5A629bBbF,18,GAY +0xAF14a47e831890d8d85FD6C136987fD940894168,18,SCARCEDOG +0x6e8623C8481395E0b4DA5A7427A1dfb1981Be17F,18,CZ4 +0x347AeDF8750110953b054B1dB63F57694Eb93c09,18,NIGERIA +0x8f2c7104dD7891Bf9B27B73ca7B2796AC4E21750,9,$NUKA +0xB846dc079E2A0eEad8A3173Eeaa0f1607b67E27a,18,OOOooo +0x45d2AB668980266536c58Cfd0513e7e27725235f,18,POO +0x834B55D18ECE23331D978d7Dd64eAA12F26beD03,18,Kimchi +0xC57977faEfBC146234594C8C2AB5b21108ec62d7,18,SYM +0xC9359C9B0D28EE04825C94932AbA31a4ff2124d8,18,RACE +0x24A672bAA45A4246635C3d8ea156913FE1b2b288,18,MT4 +0xF3BE236b50aad54646Ca20f473774420f894c80E,18,🦧BAPE +0x8a4fC47807B49D04E8D931B701Ec42cF5cD37C0A,18,CuteCAT +0x0079bbEBb3b58424B05720c20caC32a4C02A32E2,18,MONKE +0x689b2629B71D367b2Af6F8EACad708e0F48194BC,18,DORY +0xceC293b646520395D5992031EE4f5AB39e5eF6E7,18,ITALIANO +0xc29315c810aE8B0BBe883580859482BF710C628A,18,MOGUS +0x8b099E0FAA984BEdbBf009210680Eec11dacB1F9,18,🦦BOMPE +0x67d73A9bCEC2F681c2B4E298B32c170b0543B9f9,18,hej +0xC3A56536Ca667A1ea6372919A464b0861147490d,18,FER +0xAF5D0F7b4F138fb663E5dfF104370C57511D5207,18,BSB +0x5C53B393E96aa70Ca66D6b7def4C8DaE0AB6ea55,18,DONT +0x5E32D4b6B8E764A4A48f79065757983FB1FC6f3f,18,GER +0xA722ac0A4472A94Ccca11c6C17A0b25bF68640f1,18,VER +0xf1dD1c9148eF2c57f1Bdb7e52Dc4d9592E9C982B,18,NER +0xd7dbe023Df5CC998868Fba987531E6A3b823D047,18,EMOB +0x69C9fd4f0cEaa6002cE3cf0972c56255CA69cb8c,18,BULLRUN +0x2A23444C3Ecb438ADaAFfC4614fFfaE6E99f3F9e,18,GMRX +0x3d238aa2dbca11190d741c0305Cb729f6445aFC5,18,Scat +0x040bC694573014948dc6a8AAC2C85dC5cA09A765,18,MEWPOO +0x12aB5946eC6A53801D932eEFFCC691C98b370587,18,MOONDOG +0x17D8b367B943BC469393eF213f0975216821EfBb,18,FROST +0x50bDA2A16A130a8B71695FE3aE5EbFA0384d71e5,18,??? +0x0FD93ebAA9535Fb79B1c5D5C02Ef012057Ea3822,18,??? +0x2Fe75Dc03dFF95aB713D492b31a2c7971856fEcb,18,BEER +0x62a19897fe3DC18410c6E0917235133453B3025C,18,??? +0xE9F34d7B0634a3d4f968302B8dE8F6D4187c127a,18,BURNBUS +0x7d0bf08e4b666380395738e33B1cE71C6044d8e2,18,CONSENSYS +0x991a6FBB168Ce6D0B9965Add25f9f180743a0c99,18,CONSENSYS +0x0296Ba3eD1ac005698CeE17206b45BEF35B21c21,18,CWH +0x1614A9BD46C1Bd174Ff55620246d12f26Bb88dD0,18,BAK +0xf1181F59C964e421D7778e588d2DD2ee7bFDdE7F,18,CAPYBARA +0x19DB0087f5DaC10d9bA1C3Af0E1D1B13b1998148,18,COFFEE +0xeF7bFe4cBd8F16EEAa464665E8D03f1AEEAE965E,18,KROW +0xd981C33aB52FcB53bfB959EE0Ad1DAf1C381E314,18,PUPS +0xB4eB0a7bA39bAA314131252d9AC66C779a15B899,18,MT4 +0x4989DC71611eB2B55D309ef9a3527CAbd725EbAE,18,$bichi +0x9b012220c0f48C7a4A98B5b4f0BEA9Dd67AbB9f2,18,ILY +0xa1d75013Dbeb1b4b909dF5aF56FeB98413aF55Fc,18,BOYSCF +0x64d761061AFdCa42E8A9412A024116c92D6D0D7E,18,SOON +0x1DEF9D03c13A5B56469a22F5F2CD580E1CA071EE,18,NOPURR +0x96b9CDf0816A2E542A93141e1e5688dF507825f9,18,DONOTBUYTESTLOCKER +0xBeFa356479133201416d011AC89C0285BE24A8fE,18,FRIEND +0xcAFe45b2EE3a4245c16df7156543d196650FDA15,10,MNY +0x3e7A4dBa88FbAa0d978CcBF899089d30C5b1754a,18,RICKY +0xf21832438e3b440F581783FEFF9A851bD1825f2c,18,GOONER +0x6779aB4ca4d1E64Bab06577A5eb6cf736e94Be9d,8,SLAARB +0x884f51973a35b6F129c011c3818D9a20C22d7f9e,18,HARAM +0x9a560d908A51277012FFDa0Ef0122fA4B878C10f,18,BOX +0xa5c5867B40f8eA477D1A114B822b51ddba98a11f,16,HANC +0xf78BAC4532A943C5992f7124f667F96522E33eFf,18,MMT +0xc4B90EAB71DE6e174e49FCc613Fc10D4c782f970,9,KOALA +0xE81936Af3e9EA94BE72baE962FBEFE6946C39de4,18,BBETS +0x434304d95C5c44187a09340caC414B49bC4Be520,18,peped +0x8db905F66f6F52c0f8f11b6D563810471FDB3dc9,18,FRIEND +0x54D36E79c4Fdc9895FB031777Cf4D978a1D18DB7,18,LUNACAT +0x46C6f19D05be7c2D2170B1FF6cdb0e632F1b2B3B,18,BRITT +0xDab24425Be6a9B88620EfBda279ffc15D4CA40e6,18,PUPU +0x18cbFb48C0fdc7989245d63D9F5c4bEaF478B6c9,18,POPO +0x09230699598A04044d8036ef4203e1faaB193419,18,GALAXYDOG +0x8a0718972cB74966c09bA1aDe766b9A6Bf5162d6,18,3 +0xECda5dB30Fe7fDE5b875B0d62103539752d882F9,18,BoB +0x24666dEe6d17EBB0c0af62E144B1b6176F9228F6,18,MATE +0x57e2C965281AcEC4aD075FC446d418Ce6CFD692c,18,PSTL +0x3aa236e543CB9Af6bC56eA365f688317327164Aa,18,testcat +0x844318FE750640C3F7DFF8902720f48D1d1F0535,18,SCAM +0x20B33363e9e58fa1D611e5b48E3dB14aA582201C,9,NEO +0x4dA6759d909D224815cffC84647dAed33c8CC8f4,18,MYLAMBO +0x6CdF4223814dE8018d3ae7ab1631850863CDbAF7,18,WIFWINE +0x0fA43D4Ba5c8321Ff521Ec880B282C81b7F4017e,18,BSBS +0xBC821a77A4f9328c335F13B2CAFa10C4f5756282,18,HELLO +0xA67780dfE86169CE45ad8df3b3D8Eb08AA1900df,18,ROCKY +0x84b859196c608f9CA716f855A9D5D1074d98B3b9,18,PISS +0x60ac9092a6543345FDA439A0C8613b2B09C5326F,18,ROCKY +0x4Ea7Eb10Cf0f79E33AA26431126B8B98d1C05fCe,18,LIVEMOM +0x8Eb48D0C02D061990970b88f327F9636B2C8f2B3,18,Tst +0x1f1740956abc645D2d355570E6424D872B8f289C,18,SIEMA +0xca08107F9Caa0a3b1100Bab1696d069C79BF9f90,18,livemom +0x8b908462272bF8870011ACC71DAB6839316089CC,18,SMOMMEME +0xD43a1CF351D2364772E05116774A3b35dAB861B0,18,RDBLL +0x496d847DDa30Cc561F4F4E01689e3B5229C7e092,18,BABE +0xeCba110DFcCB7Cc82B3edF8ba4AaD93A0b0f108C,18,PEAKER +0xFaC65b9C1354736892893532A68c8a6Df08C7B82,18,BMOM +0xBA3FC5f87692E676489E01ecD5FB5Fc4d3507c1F,18,Ricky +0xB8F7Da22c3A54dFC7CA5da675aCdF7F76BA094cf,18,4 +0xaC704c8e6B6aec869B64fEb4f4eDb4172c74862E,18,elo +0x15a9E5e5D99b4aD7348DA5843DBae97739174f78,18,EUROPE +0xd316C1E70a23B81b413D7D610EFB36F31A51Bd84,18,RICKY +0x79bbb9fe2416CaF66b1ee902c3CF50f0EefF627A,9,PLACE +0x925c83bD25E77229fEb8cC6690Ac191C07F07b20,9,Hype +0x93CD10bBA6Add1A79C3a66A1F03eAD0508496e68,18,kenyca +0xa0741B19F5f56D6f779963481fAdC08bfeAccA3d,18,Ye4Head +0xfdEc795574e60cf09CB20f3AE1100605A9942791,18,DEGENCAT +0x9808500F1F0F89f8baf1d381F6f6F55D270F4a97,18,PARTY +0x327D447370ADB0dAbA10C2d83508eFFA14E59667,18,RACER +0x3b1b755724c2f0a6227e43369fBe7476a6a5526A,9,NEONP +0x8e47cd4DF9B63D6952B7F41F8C2e4FE271AE56C3,18,BRETTY +0x3D172D8a854A73336aC800E30660b7dE14e40512,18,LOLA +0x2701D9920403b50682B7Cf5EFA5927C7AdD52075,8,GOME +0x0bD4887f7D41B35CD75DFF9FfeE2856106f86670,18,FRIEND +0x5d016F7c1a14E46dB391342E9eD418fF18058426,18,DOG2024 +0x1f1Cd15bE4cc3f0A992818D56F678a9320Eee943,18,FRIEND +0xA6Ff79EEFf76B1546E2E984e0c60F12e8D8A98C3,9,$CORNELLA +0x7E3faeeec46a4649b084927E2d465b2a699f6b90,18,ENEMY +0x9d380330d3C70FEdE3145E4AbB8CbF7D78c3bec3,18,CZ +0x7fdAa50d7399ac436943028edA6ed9a1BD89509f,18,WBNB +0xd01DD689229177cf9cF1739827F191642FafF318,18,SEC +0xD3E1d0816B984c1250A8231719969c683f4A7921,18,SEC +0xB555Ee1497C7ed48BedAa9eB0bf230fcb90D5826,18,SQUASH +0x8dA366956b59042D1476d2d398C28cC6c0941053,18,CONK +0x127Cd2fBc764313A7ED425f8cC4149454409a9d6,18,BIDEN +0xb14A3F8287D590B6aD9ABf1CC94f0AA3198fEE4D,18,sec +0x9724FC5741f32B531d21C27991E136b02A0AaF11,18,SATX +0xE3de7eE53B92095D27dca231908FdA5323ae3280,18,BUNGEE +0x158496c7daDF2354930eCC7585d422b3b3D249EB,18,10000GROK +0xEFe06922615B7414E8083931247b2B075b08D4c6,18,JRWA +0x422ad533B2Ca7f37f73c10bE88B1Dfae99ACB39E,18,FRIEND +0xe99d036f5763289405C9783c4Cbd41B284e107F6,18,FORK +0x8C0535C94915768914DEA00718d4BA266DBB5ba9,18,TEST +0xbEe68B06455b8B9A3639BE74a0Ac5A5aA81500BB,18,FRENS +0xfdfe9A14438B9B6D6E631aBC7B8A9404ed22f5c8,18,WENRUG +0x9Ce79cde794798B1b840c0E346db57ea68004535,18,PIP +0x6A49715A447867e1E7C4D05b8c1ccaEC043BB37B,18,🌀Bgames +0xC1540F05387421bF5a46ff31b1c2010CCC112683,18,TEST1 +0x1900762434eD240309e47bfa6a085272e45e175A,18,🐻‍❄️BAI +0x7511FD9c2dA45562ee813809e0a88818895233b5,18,TEST2 +0x65823733544A2eF382A3Fd6cEF45A62CcFE87908,18,COKE +0xd65f96126be7F96670488CD312d578E036e113a7,18,OSCAR +0xc1c19f70D5330F2d3CE0ac31432345F39421f7E6,18,🦁Borki +0x973517eBb67A865f67a63a56508BB851042d5bb3,18,HYPE +0x6c52f8a233FBE6bd7ee52b76FC7a525E321974f2,18,RUGPULL +0x85FEE89A35696deb5585CdF14eCf24c9d8DB63b7,18,Bow +0x53F50bf4fbF3dB069a359Aa588DA435932830e48,18,Bonkkiller +0x0832D31884B6DAab4CFde1cFdA27D37a00b13048,9,PLAY +0xc8E958AA78209eb6fE79C21315D1B7B403242bDD,18,CUM +0xa65afCB9eADd3cB61941C24665b6aA36f1E79B24,9,ACAT +0x1B2163BC8a31508aA2f49d6dA3fbae0C96A95860,18,PNZ +0x35ECFc92FC79e5B6bE1A3b540729F17eB1076939,18,SERBIA +0xBdb9e2cBc63594c89Cd88592CCB4bD529c585190,9,BRRR +0xd345d407327C60636Cbd0Bd8B356284F2C89d21a,18,FRIEND +0x40d2C1F94AaC9EbfaeDb2F1d19D457d23816491d,9,$NUKA +0x4c357D6fA5ebb9d75E1a0F73D6b0D38f09d1b1dE,18,LEO +0xBE0b3d2e6a0413fD9C28D70988A5eCCD2DAA1a63,9,BOBA +0x7474a34aEBDfc9643139387EF10ECfe8B8F7f690,18,BUDY +0x0cfDCc958A5310ba550C9CE2557b9a9C22EEdF55,9,SQUID +0x311eC870e3d7172896CA9f18145bAfc8902c9F3B,18,BTBS +0x1234d66B6FBb900296AE2F57740b800fd8960927,18,DPAD +0x0180D2732191eCf900971F5aDFD480200162d092,18,BMC +0x8AE47D774A0209a38a037D8E3584c871e2EBDBF8,18,PNZ +0x38cA8bFbe642A39dF755940b5675B653e7641d61,18,QBERT +0xE879Af4e71A2Ecc5f06994e34AeB60332D0860Ec,18,Kerm +0xa5067786fAB666e260BAB70ab6e1AF950f14bDAd,18,WIN93 +0x1a7FD5Daec2Db98bF101B7b49AbB0553c88E4341,0,ACDC +0x146061Dfc2548db81A8bfAA09F2eAeC39C4f3B95,18,WEED +0x9AF641d5A25128C38a76a0f2F77f730438ce208A,18,OSH +0x74272DD7dE59bA804Eca30323CBE09b48edb128e,18,pipi +0x08141979F435b3bD2E1259E01f16f290f7550476,9,MATT +0x6891a4d1a3a6dbA2295A3c30937b87105EfCEB3b,18,LUNACAT +0x00772E28Dd03b350515E31cB27aa218C0CD3e1e1,18,POO +0x7025876e6a2a6E00A6fA88A3b96A9Af5d2CD960d,18,BF +0xdF2880a12CaAeF3e1014241Ae05c4E85DB08aBe5,18,Ttt +0x46b3ED3baf51aFCc67c0eB4A6a8c81f9d0888930,18,_____TST +0xddA73b4DFfA1aC3a687903B68900f80122b8f7e3,18,BLOOM +0xb610Dd0EC593d25E8245515B6B3432bEb6e09e6A,18,🐸BORGY +0x433E16C18e528dc4D3bB1080DfE043c7cEE1c289,18,PEDRO +0x346367d685AC3e55597A3292AEd495afE2520D3A,18,BINU +0x070878D3f70D8092067264Ab3F93b313c2FA8dbe,18,ESMX +0x4F1F2db498437141a97f79eeD3cbCdE64F55b65D,18,🦦Bany +0xC068d30229c097d6bA0Fc0fcA835876d1E59C4B0,18,HACK +0x8eC82EFDf428f8e9F39c990B52FDA651A1c40E68,18,BaseGame +0x4d58608EFf50b691A3B76189aF2a7A123dF1e9ba,9,BOYS +0x810837E4C6c4744ba66ca672ea9462dD7c190752,18,FAT +0x2d96dffd266910e11D1bEE9A95EB6845cb9C0D35,9,CONC +0x9C4d3fE67295e960DBdDB7BBdddC3221aD1CAd7E,18,wasabi +0xDc054430ec51C9bFCb1E20e3417f3c59e5111371,18,PerpAI +0xcEa5Fea9B8e212AE9C96D7e1f6131BDa912F95b7,18,🐸Brog +0x9fA26d90D5853052CE561974B5a7F3cb25646993,18,BBOX +0x492C5803Fe1F498874afDEC18BC30fb19296400E,18,BPD +0x372A087CC2aA0Fe60f16dc3C49d0524D40E9B268,18,BLOOM +0xAfB5d4d474693e68Df500c9c682E6A2841f9661A,18,BLOOM +0x99e3f16d251e1f3Bb4fBFf924549556B0f0E34F5,18,BasGAMES +0xd2dE9b74958c91cd569733ED84c9515A62745082,18,LUCY +0xfE52E6fa32D12Ff248454161Aa8449Bd1eC01d90,18,BasGames +0xa1135E6e1096bBF1588E343eD76d4965b2672C5f,18,RHUB-TEST +0x9eae210b84311D47431c67E99915c8436A9C6fE6,18,🐸Brogy +0x606B2Db8Bf642677Fe12E8F067bF55145A350cb5,9,ShibDoge +0x3c8665472ec5aF30981B06B4E0143663EBeDcc1E,6,WARP +0x7080EBFBCb1cb148E3a9b31FF3351b0b3C71f83f,18,RHUB-TEST +0x89A9C4317BAfae9c4726A8862dB1E23B07664F79,9,BSWR +0x1A2D18D0546611fc381977B37F2c324C6973c396,18,STARFISH +0x36b7544cEf40EE4fAc542Caa77Fa137e32319463,18,FEDDY +0x054f6C0E7525eEfFee9a61dB6533564191CE6351,9,BSHIB +0xa3cA89087685011d6407D420273e2Abe875fD7eE,18,BBC +0x84020258640DD2244B0ae9D83338bf2FC5F9a944,18,RHUB-TEST +0xDdF32652fD8E3e88bD6042db9F18a193CBC57955,18,MEGUS +0x6e773d10f7919eDBB598FEF0E640e24E46E44FE5,9,$Cool +0x2E4753ec87C4992892dAd8Dfed02f215A62002C5,18,wow +0xdfc10ebD9E556901ee5972f3f9ebd8e8490F4cBE,18,BBB +0x6D47F47EeB36B500ABA73810124997b4514cbBc7,0,GANG +0xf1B5B5F32A684d9d1ca60C92945Ad16dC19131cA,18,DONOTBUYTEST +0x1f1D0374C4EF4e70f8ef14Af33D41BF2f9828F09,18,FLZ +0x2CB819A4382020941d5f0FD6CBB5e315A8b95c7A,18,PPX +0x1c0de5aBcc615b41Db3eD89a1F87bd7a6aff8179,18,CAMP +0x9DE091397aA1313E472073BE2bDD5476f9E1F33C,18,TESTWITHCONTRACTVERI +0xBE3B49F2c4Ba5637B04ADe3210Fb9EF031CA1E69,9,Shep +0x6f7e468E01A4253955844c9BCA769f0A5881fC8A,18,TRP2024 +0x3fF6C60A582643c2294D6A309d84d2a6cAd16c67,18,ENEMY +0xB958800Eb41436D30ea111d525B317Ad25C0DC94,18,LIVEMOMBASE +0x2bda937cEf2FBe976b62eB2B2C2f1e6f7DBfFb8a,18,wFRIEND +0xce69102Baf5A531319a3e77E71af32777ceF18fC,18,ROKM +0x035f87869c982e6C892ea8789AA8718456844F99,18,Neochibi +0x26BE2aaaeB921a269e315A72355f5DBB2d6F74e0,18,camp +0x3bf6d8b4001277163FD81E938e4BC7457526F5B9,18,BLAME +0x21bC0Da0a27405Daeb7574D4cC5584d9aCE1f73d,18,WIF +0x04f0576F776F844DF961Bf1a45A0481c6e7a5580,18,BBB +0x92fb1b7D9730B2f1BD4E2e91368C1eb6FDD2a009,9,JOGECO +0x3C4aF6C4E863A55B32c726F6D46159A8fCDF3f16,18,SHCMP +0x2330D9024F2c9233e84a2ba56d98fAc13218D399,18,ecats +0x27c2B825d836Cf002303F4bd728657129Fe60C2F,18,BRETT +0x22498145121e83a4F9D825828E9b45eDE4B0b783,18,UP +0x1995fc0291A61A69643a1EC9B04FD307B28395D3,18,BASEtt +0x2840210B8f222008Dd9daFD0B22c4762CD9218a8,18,.COM +0x1672968cCde9938D5bA0e488EFcB2d731189458e,18,PONZI +0x04498128cAAEA895ccaa95d4E443f155803C2123,18,FORCE +0x3C382e4BF4FAF903783048827281a23F45613291,18,mountain +0x05F537C3860D18e244285F839aAD6fAeA0bb42E5,18,YMM +0x0B7B67e24c896d57a89f495d0ce844D06fd12733,18,500 +0x25a80489B54bA4c91d8422e4547eE66691bDc4a6,18,BASEic +0x0eBB825d64B91B88b618D66897bAC440F3D1e1Ba,18,WestHam +0xca0afE2C7A44984e48630E5b79BB33890cA8E6F3,18,PPTROLL +0x1A65cB85e482303911e8942dB79F6E3ae8D01Aa6,18,BLUEEYES +0x9E92FFbC06dE07855F2286dc958dACdC843d1235,18,ARMYOWL +0x0e062F28b15f0fBAEfe47F9a609e972aC459077d,18,TGNR +0x46c5e5b4065DCC64260E53ab6F13459a7971BcC7,18,Sheps +0x064Ab2399d499161eE7F0fEDE38B65dd27dba0f8,18,SSSI +0x1178FF084407357bAeC33d8F211b33795DeCeF98,18,Bichi +0xe6bC2CD535622d6535B17e3807C0e6adb51c0223,18,PILK +0xe929c18dfFDdD79489AE37F4B39456C3a341e40d,18,RHUB +0x13CB3E956be8915e41a5A88a7eC6918dc5a54c9E,18,YODA +0x1826A8dfCa5cc0B3F2b750ab58f365Dc6E5099C8,18,NGU +0x964Bfd9a6BFe54c6AE977B1627752067fb09A1A2,18,AIPILOT +0x3Fd976CA058E78E8c921208C6aeD6ccACfAf0384,18,777 +0x210F4117B1790647d5543E4157B568F7FA486E0b,18,GLORP +0x1148E628aaC1025B8ceedaFd092f912696Cee3d0,18,BOEING +0x0297Fc50A98f70d681a38e5F2A267e21bc787d9A,18,RHUB +0x26D3ec3353f0a064E3394676E7F5530B082d1a93,18,GOLD +0x22c20824E037C6B043eA0356dC7A059A0957e257,18,100x +0x12a18C14245ea3D6F0B6D4cE399b82929bA7B16F,18,CUSTOM +0xFCAf32a08e889d8466FD1D7A14Ef64C2340ec492,18,RHUB +0x22eFb160C8e98DeE3BfF37DE537368C228f1Ec41,18,it +0x28bA6B4A583c4C963f320C8Eaf28Ccb957CdC089,18,COOM +0x161F331e43ABe778e82d7D3fFFE7524092249c0a,18,WOMP +0x358415D39ff442964D4930456eDc288f2b62d9Cc,18,UTC +0x0455adE982dF9c457792F27685462f5A85E0C458,18,Wobby +0x109cd63CeDdFf34c02284268f195943d6035dfd2,18,t +0x27516FE354492DF0DeC8b672B0e805A85F99644E,18,erggreer +0x329fC6738E247859dDd05164A75AB77Bd05f7bA3,18,NAT +0x3A6BB4971F9edf05BD15327EF7eBB25192E95017,18,WIGGER +0x292Be9c3EfFB1EE8Bf64CE874592194A7B7D77dE,18,BT +0x2371834Ac742E3F7BFc25049c043966d5dCE9D78,18,JEW +0xbecc9a93D8Fe302A9A9866BAAaB4901866B2c500,18,BASEADO +0x0D3F79Eec6BA8e873761aEb2AAd42140767866ec,18,IM +0x3cEA7EEec0e3bce9D0f9435523eEb0A618B23844,18,GLORP +0x2Da35Df5b84DE26fE22B4d34A97087c0495Ddb8f,18,GM +0x2e81A2851BCFd2ed263E6d60eCa7D5e09b943ac4,18,e +0x3531787A61Df373124DB6e7201F7d8eFefb65dF6,18,molly +0x3Bc7407172C3491EE63c5F6F390EB7E8D69A0de0,18,BEET +0x0C04DDb0599bbd18E1B90135ccd8F301d0ffb5F1,18,TESSSSST +0xA8ead8a9B2a0EE9717650ba3D2E13a89Dc615f6E,18,RHUB +0x736ab92B701C5509568d59B81B7d7567763aE6A1,18,PORNHUB +0x14631e7a6B353cE20b0d2b06f1193C96a8bA8116,18,FAAAAG +0x337f1d4711CE3a82dADd710ad856FBD572272EFB,18,W +0xD0751d184bA6142D98b6AF1D3D36F829f1C420Bb,18,RHUB +0x7Dcb4ca7D6C563B875A554b62D412Db941130B86,18,RHUB +0x280C74aa58B563723FeB69499bAd6160D099E2bB,18,LONG +0x9616527739be06EdbDcF9b262b2157237d38aEC2,18,RHUB +0x8c0A999c772DD3204f1053433740bC11F68F0D22,18,FRGPEPE +0x3bbA3D4A5A59875eDBa9D01829015C8b40e389a9,18,Grass +0x25Cd2c29572FA2569D3E46ae2af994074AcC565E,18,NWO +0x7E729161F53bc82E5f25AeaBe6aaCe28Fb8CB35e,18,RHUB +0x7543944DC68c057B37bFaacD31C8B157Da2E5F14,18,RHUB +0x34cb9cCE3ab2DDCf80b4f6e07258678655f522B0,18,Joever +0x399Df6856dE36E546D49D847e6c169F341e04c60,18,a +0x34A8E3C8767c71eff9AC70750b653bF76d40499C,18,RHUB +0x2fF9be3Ada6D91c70fA8E4aBB42b3a21F3C80773,18,BASED +0x3F1c50145BD0b7a3A5BddD16BA01324E1240E736,18,MEOW +0x134AF523b4a0fd3fE07d6c76d46E261b3d7Dba2D,18,wwww +0x2295d437B76DCe84f92fD84B201dC1090E5CB9aB,18,Ovouwu +0x25eD31f13134879236B381eF36F4c5CC3cFA93bd,18,test123 +0x136F49094504c07C892A3F39A94f6caf0B5f4500,18,WOOF +0x1D87642e59Eb6992Ef6E8F4C29a3B710E1ef0CbB,18,Rayfu +0x7Ed580d9983E9D82754d4a9D3610be38BA3A56a3,18,RHUB +0x179F3aBdAcf76Fc91cf72B40d95e254994228A30,18,WOWTESTER +0x02549849C371a109aB112286F27d5D7fF6899235,18,TICKER +0x27EE04900844F17b2A872Fe320b1B6Fd37949AAC,18,MAFIA +0x398e1170dc02E094deeFE25b7e039E92D3109EC9,18,AAAA +0x2F367a7FC1695eb5CFc8364f3Eea658f2Da0425C,18,aef +0x3A41Ef116c5545729D38E47D10afd98BAA06Ab61,18,FAKE +0x122D1125CeD703413De7CFE2a2a54016453F1026,18,hehe :3 +0x19A1C79Ad6fa89560aaaeAb66551fd3d3DCE540C,18,WTH +0x065c83D57bD70F7E59A0aeD9dE5342971e1c3Fb4,18,Pepe +0x03A5AEdf9a60933511c608029E8dC32eeC11f402,18,GLARP +0x1dbd4E32CB7133fd85Aa6cbD4aDD3b3381552f96,18,CSW +0x3AefAC19DD153C0D92c29662EB882918814Dc075,18,FT +0x040bFD332f2dfAeE800b93b1B7E2477e732Db3a7,18,ALW +0x3016B1C6c2e0c8194D3A5b41b4eE8D7fE1Ecb0FB,18,. +0x2d0ABCbB874Bc3ba9ad9117e8a9eD94236b3D539,18,GLORPMACHINE +0x15e4Ad09340A00FfAE1F0780543b6b31285717C0,18,Grass +0x39D728a9114aB26BFd13740412c0F5d856bA6775,18,TICK +0x2a10ab6F0741da177B58371d889356f6d25CAea5,18,camp +0x0a338996f6Fd6D2FCF9eDBE73a2F902cEC4B10E0,18,re +0xcdF4Ed1221C330dA8555b3237b05dEB569B820BC,18,RHUB +0x404bb5991Ef024B689738BAC8eaFA7a7C5cdB2B1,18,AWWWA +0x3a0262a656A440CEB2cbf65Bc83D936b53a15150,18,BASED +0x9d72A983d27cF186A608eeD2d14Bee22b2dC6527,18,RHUB +0x129346bFE9c2A42C834cd9B7588bD4d864640a9C,18,Glorp +0xc4AB16FA4F521E3dDD59504E128217A4030f1241,18,RHUB +0x00881016B7324678F4012FbCA0C0267b69ebD10E,18,RHUB +0x2eBE818fF2371b166130255678924686153A9cb0,18,WWWWW +0x2283Fb10e8a6e3D02A111971d121915071Ab9AD9,18,777 +0x41b50C9A3fAe9ab1e34BdB43d477CA7fe98D62e2,18,SUPERMONKEY +0x0F5F9494D70b3376bf19b220A49B985e1AA92Ac5,18,MC +0x22ed1824a677fb3FA5b57583Eea9C6CDf8eFc8df,18,FrogIsMad +0x31874686ef66432e65B3D18A503DdA0938dC6b35,18,TICKER +0x075660e267228f7ea4f2E5395A41650D41Bba97c,18,Sage +0x214422Cfc0f0f745656b74Ac2054357E14faa668,18,...... +0x37017403ab739292420d0d1fA3976150B3872B32,18,WORD +0x091Fd7911ACA851729CeF1596F45d52a7f7e7DCd,18,BOWBOW +0xE557Bf10bc4d50220ac1bB77565120d0F85d72f7,18,TESTDONTBUY +0x25E427897C12314CDE527719CEdb5D4A8760870c,18,FUCKNIGGAS +0x4dd44BE06c9508FC706f4cb52cc1c32cBba80049,18,TRMPLFT +0x86252Db4CeED302cf5De0a3A372A8bf0d5420a06,18,BGMY +0x189a0B8a077F2E2aFa1574b947fA670E6Bb58f5d,18,WWW +0x005A2c675EaDbd6df191d650716116Bcc004F742,18,GAMER +0x314cC17A9d883e954E62ebA46Ff9C23Fa49e81A1,18,TOKYO +0x28383521a8C19e3d000cc7146e494A2d67CE00d9,18,SHORT +0x011FF1387A96eCF8F5fFf073915CaB4613Da9684,18,69 +0x250066b83B8F3A3E6774526198Fce54B121D30DD,18,GEILVALLAH +0x2b167173027B3C4C17A4187AC1774bFA1206FC1e,18,DONT APE +0x1ef9236885f4734151ee7cF2b8B4eb2a9b89e7fb,18,KING +0x043641023Aa278E7c3b85803d5c1ac7c33500C37,18,H2O +0x126c050DFf973528755e414D1CF1770632EeFfd6,18,working +0x9Ddc6033a681C265C8719fBdF84384FEFF172A21,18,AICLVR +0x0793B46523842c30FE7123Ef2A2e3090952A85f7,18,wen +0x3dACB2666c431e693AC88163506Df4247EeA615E,18,egirl +0xC66aD799283957F3371cD33f3EBa04124b0CF6B6,18,SKEET +0x10EEB045C0C18bB14aecdBc9E4f10480A2f58d0E,18,69 +0x012da0D3F4c12aA940A006FB8276B186f77d3055,18,NIGGER +0xe917Ec526Ea9983340935a8a2508cfAd2D2f150f,18,symb +0x1Cc7becb731bf7F469C39deb1051D28f009884d3,18,MM +0x0a11ABc7F03D58b25c64A1320F677256d0e97807,18,Z +0x12e5e8A871bB6F716DcfFc93C7f204A779dd6e29,18,PPECOOL +0x4D853a56863fFA1f18c3ED693066A45e3Bf6374e,18,RHUB +0x0221C1F1A1b15ce714E5c3Cb9eE4a1eF6c28aC5B,18,999 +0x339Eeb24F690555434218413C7DA7D1568a0D612,18,DEAD +0xAdee044c9d9fab7E4d09d260B384cd38054DF1eB,18,RHUB +0x263890081F520E5e661563900a960B29566eDff6,18,ABC +0x5aa5DEe30bc6D7EE891eE70DA0A1907604A09EeC,18,RHUB +0xf6Db985F919311FaC0c2A7229Cb342E5F9aF8ff9,18,RHUB +0x5Ca1E7dcf12071b74D668b5D90975ACD8324439A,18,RHUB +0xe9dd6112EaD0A43b85154EdCCd389b2E22a416D7,18,RHUB +0xfC5cCdD1C2dB01915E588d912a902D782a9Ae39d,18,RHUB +0xB2b2C1a976d789DBe19Db999454797Eb08788Ab5,18,RHUB +0x18aDeBd9FDb4E5C25de09b2712059D0fb42Ff35e,18,GM +0x4748A0c40E1E3475eFC15feaDEE4051E3cc47fbe,18,KENDRICK +0x7aaabb95405ce273e047bC624329f521A4A010DF,18,TRMPFUN +0x6FF923E04728aa2C1C392518c4c9d27Bed4d66B5,18,symb +0x41BF9e0DED1389f4d0dF64936044a104d9A54eA0,18,RHUB +0x3e05A37cF59e519BDe2ecfA3C90eFF4dFE77584A,18,symb +0x71f7DcD69ce6bDF528aF2c5DF97d87974EE97e52,18,MEGA +0xC30678f2C7CE828149CB47b9765870e715172cf8,18,TPT +0x555B7Bc0Ac4329DD129907873fEe42030125fE66,18,bbb +0x0140886d1d874de45CEDAa2bC5720EDbB6B6A061,18,hhh +0x3EaC1DA87Dcf35f3418D85560Ef30c5531ae2Ad2,18,AIROCK +0xBE8DfC6661fAfAA4445Eb952586c0D347EaCF048,18,MONK +0x15d95e35A66044460E8a149F55cd195910Dfaa2D,18,RHUB +0x9896D8487Ff9D2626B9dF7f5AEb5Fa9CD7237e96,9,LUCKY +0xfe189Ba4AEf478cD9082ed7DddEBE08424DE5741,18,SQD +0x2660Fd7dd86cEBCACB455206f597762454456103,18,RHUB +0x5E48CB3b29b5F1351e73d030f47BB1dc01386e7B,18,RHUB +0xF368E21cd5D9be93bAB9D7B1Ef55C3d0FaF6AaF6,18,🐸BROG +0x3E88DFF80B3Df413802d9ad8F7924aA028A6C483,18,RHUB +0x892f888eC879100d1addF9AaDd98090EB6cA1E5d,18,RHUB +0x3e524Af52a19Dcbeadc88978f0acd203002223Ab,18,0.000000000001 +0x1442d4bdd038DE86A5680C57654212a63bD69627,18,NIGGA +0x078f4F9c419D486AB9B756b121Ec4E347b8612B2,18,FROGLOL +0x74c985a020ADD6110B867E622f421C3519EE690d,18,RHUB +0x750F4853C8C3a5007F9B25c48A689681916048dE,18,🐻‍❄️Bai +0x1D43bB87F639411DE4CC0241bA428A11d07f6D43,18,BasGames +0xA342bC8cFE573dD16593EFD630A1358CDF07F6Cb,18,🦥BLOT +0xbeD2a3CC2c8786D3ee6562924eCa24Ff9fAF5d3F,18,TEST2 +0xa4ecD597adE3c688E66d4478140c0db4669d85E9,18,TRMPGME +0x7ff87F937be5d463508B75654c67ec59Bc06182e,18,HITOMI +0x22422D8cd1b0854BC14ba5E897e005C84e67dF9d,18,ATDX +0x9d762f0E7e51C3086A415d1d5453B701951DA54F,18,🌀Bgames +0x78A7bD982Cd0bCD8b26788f6b5362083b3BcB467,18,TRUMP +0x11f6b2F04c7003d9858f2dD2610F04a72658f862,18,RETARD +0x5a21FeffD6Fa5Bd9DAEd020b5433006cF6ffeAAd,18,MARLO +0xE298D5b5dE077b57392ead70Ec739985C8322e5c,18,🦧BOMPE +0x2386F744a577949b1e4ed4DD469474f123189b68,18,SDOGE +0x27e162E408D27C94EE1E204ea44A0c69Fe183444,18,💠SUPER +0x2f141f2E7C34170404660A936f198064b42aa560,18,TBAR +0xF8B6D1Ae46C98a08944e24BCBEf9d31939ea5c93,18,LANEKI +0x255db4e94685C1eAdC20a6F1DA3D46522f39f698,18,BULLDOG +0xc9A8FDB365b98b2e545794081fF443b2a821961B,18,FRENS +0x65d4d4a9EB3a3Df2cDb60c310dc85DD0f100cdbd,18,MNDN +0x7C32BD65e302862568EEe5FdCbb19D3136814AB7,18,$BAXTER +0x086CfE4fa4B1Cb3078Aa5f9951348BBe19aa61Ae,18,FREECZ +0x241EF1dd5A5C81Cb3c8d364e66B8cD1cfCdF5F5a,18,Nearium +0xe116A9f5b19c59FA8dBFe852dbFF7C0CFaEe2E6D,18,BENDES +0x255E35ae06623Ffc123e30bFdD48B1B48bC40977,18,BLUR +0x488fda0e0D0efE5932b59f9D4B3008Ed26E41763,18,🐸BROGY +0x3cF5bD8f75A109B9D740f8153883FAEda96F5D51,0,GANG +0x0Baa013dd0C0E9fE67afb4f5C183Ce29AE3cCaa5,18,wocat +0x68328CBcC8E0338C74e8ea49E3A0012AD5E70e3a,18,🦥BORG +0x6521E1c40b3116c2b481F53d85F7002BAB334540,18,BARLOS +0xC7a871501c2335ED5E10827567d2E9167Aab3383,18,SCN +0xd266c0aBAFa52CFc0b7884ad7c5BfE9422B91A75,18,Catnip +0x8D0F6CEa9eEdc429A23a9cb565C4EC3713FcDe54,18,mom +0xf8b8d852952C4A6dFC8D78dABFc13AB3b085b41B,18,CGANG +0x2B52759ee477D2b27A69c409f59CF5EAb7AdA224,18,king +0x047491DB6704b7da74C64fe7662D6d7BA6acB3D1,18,🌀Bas +0x329f65a15221a061d9FE0FdfEd173205ba7763F8,18,MILADY +0x8A31667b167598Aa56584261ab28056F24968395,18,PUPU +0x7eb622bfF15481e4c0fa0e76545fC34a0BFa1371,18,RHUB +0x80d7Da11AEBc62dF6027F5d9A7448628749AC5B3,18,RHUB +0x3cF6389dB6025A1F8b6f699c8613AFcFFc68Ca55,18,REMILIO +0x1e1dd2dEDE79c1eC56043e36A0529CbD7121e6E2,18,WWWWWWW +0xCaa6D4049E667ffd88457A1733d255eed02996Bb,18,CHINA +0xC8EC1ecd840a5f669A1322859704d972E8c14E85,18,RHUB +0x4423949DA207a8F808ADEAeC0aE702180a5f280D,18,🦦BEME +0x236Ee01BcbE95d847a286d2A52d1389bc444814b,18,CZ +0x4eaa20AfB2c4fF0Ca4662EBA797DC60980C1dFa1,18,FRIEND +0xb3DEBDD8042148547BF68245170e710C10A81Eac,18,RHUB +0x1fB181c5a263Fd5d6Ec3c0EB2Af1Cb29b0E7d7EC,18,🗳️BBOX +0x2c728135dbAf5fd672deD97960C94C771E606761,18,❇️STAR +0x04216901e84E2141534c51574311BAa75B3C43F4,18,NFT +0xD5457DC852Bf0A1A3FD1fFfe9232D843B48FeEcc,18,HALFIN +0x33b9e28064Be9a5780e315342efB98B9b5FfC132,18,GIGA +0x3E919a5e3eF66C672aA74Adc7FF8B79Ea451C61e,18,NIBBLER +0x1BE22C2eC9e6c95aebFc889e06Bf668eC17e8FcA,18,TRUMP +0x0AF14293BD00634b3E4B789bADb5928477B1d402,18,L +0x2af48e0FAc54A9B32317E51b2b5982fb5411268f,18,WARHELMET +0x677f60F6c336812D5C07B130deAfDB79859bFD6c,18,BONKE +0x317f76A7bF01DB9f3B9986ED62419528432bAD97,18,GLORPSON +0x377dA60C8826Cd83C1D6F14d9729F06AD1Ec6587,18,Glorpy +0x98Fa1079a0F095C360d11f2AD472C25FFB2a9aCE,18,RHUB-TEST +0x779f1e780584F2eD6edD2350e3A35e4Efb129c68,18,FORCE +0x0422D5563603469E4Ed9e2bdF23f211c7CBe7149,18,🐷Bpigy +0x75A25e8eaDCe9b909447eB9Dbaa689a1FC47AbEF,18,YOSHI +0xAF95455D656C744d16359CbdA063A6271B28aC51,18,RHUB-TEST +0x48AA9F48B8e6654fE0e7060407a7a301D7d222D0,18,RHUB-TEST +0x03cbd34e2bb70a22AdBC8c3499d4d92c29E9b7DC,18,TRUMP +0x246F2dAF1cfb1Fe238A56804b9B1b6742824bA2D,18,CZ +0xc278028FEf81da39301f831baF29545210805A03,18,KEN +0x8CEa287eE70F9ddd72c2B76dbaeD91f1b12c498b,18,RHUB-TEST +0xD96C53D194cAE179dE22fbc56EEFbc4299cdd68B,18,RHUB-TEST +0x7BB31B05A57E4Aee89114aa1d485e2f6A920Da70,18,SKIPUP +0xFd82C0a98fA39733c4D3dd82478583eD3153999A,18,INU +0x29690fCC43b394F266B271152bEC93971D58DD27,18,WADER +0xE9A08c02588198E425fe5aA42433A35d011a14ef,18,USA +0x500eD50C2557863A2fC2c53e0e994647cd2AdA02,18,ADENA +0x7Aa0507Bd164378632d2FB80daCCa474047AD1b7,9,$DOG +0x1c7F193700dcC91Bbe9719B64e9346846DDB6388,18,Heeehee +0xEf4BB156016991BCacaBB3d99B91a053E18F77c5,9,$PEDRO +0x1dBB6f6E788b0a91A0baeE4FEb36D21CF6F0620f,18,Balls +0xd7c361bD5188E126FA2961492F543d0DFa69a437,18,DDD +0x19540E8d05111C3DE18CCDe7fFbc3d8dB78d00F6,18,GROOMER +0x5023404e67Eb84B87bf21dE91A58c494454A219e,18,CHINA +0xF034db41E50A6aE555bB117a915d2b9C2F3477Ad,18,HBIB +0x2d4862E912ba7ba226106fd09419379Aaf25Ac86,10,KOKO +0x5fe3d79A091dE0083213Ad0efDAD66E6d9fF9a98,4,FEDUP +0x9c3eAE590107BE796874B973980041889C1BCf47,18,STARWARS +0x3ADb41AB16779f19d4702f8d9725505884e09fdF,18,HOMA +0x0871D86fCbDe7f5c89274b1017Ad43d5B8A31340,18,🦧Bape +0x15dd13Cd0bC4879ed9332cb04480fCceEfD1ee8C,18,RHUB-TEST +0x0c16c615b0F73fec423b927a2EdD964E4690eC27,18,MOCHI +0x05719DA2515ECd7d57fa21D511CB8925141BA95d,18,RHUB-TEST +0x0E803bFf72531baC6D0D50fb1f11E0a46Ed1FDF3,18,EUROS +0x9cCdD6284d1da924BC01fd52b37C42a6C9a9feF2,18,RHUB-TEST +0xe0E2e4A31D5Cb0555AC2E07d36aB23e954F83A5F,18,0xChris-TEST +0xDFE30Ad244C9E9417205dD26996bC0a9a17aa87D,18,TEAMU +0x5b55F72e10C9978f10B3cDE46F77A6e44c4B6fbE,18,kitty +0x30c38CD596DAe4C02EB415FD0313baEb953F4A1f,18,aaaaaaaaaaaaaaaa +0x870660a87E2e4E5aB22b80aB4842B907b76907C5,9,BASUS +0xd123Cf34c635784d5a152033962023b1dD09a251,18,V-TEST +0x7cb76629590C32f35e0CD2d2E84B3f0405123e68,18,CIA +0x151378F647A88444547f45e1C2ec7C5dadE655bF,18,BASECAMP +0x5099e1aeD326efb6651b49C78FF309632e294fDd,18,noodle +0xb56d0839998Fd79EFCD15c27cF966250AA58D6D3,18,USA +0x3F282b91149C0e43549aea06233DF1CC8a788D3f,18,Ⓜ️BMeta +0x04Ed0E9e194262c7DF1528AF9a8474F5A1F6adDc,18,LIVE ON TWITCH +0xeC1184513a0Bcfb96144F00fe9368C5B6e33727E,18,🦧BAPE +0x8d2f83bc6E24EcFe0bE436E11B5d65B0F0CaB045,18,🐸BROGY +0xecBC993C4B29EB5A192712D689B63A8a665a8f78,18,BaKiK +0x61ef59e690040E6b7a1693C97383D74570a1C9aa,18,OPLEB +0x374FA21fFe10779a10a05dCEdBc04e69FB97E571,18,$SKEL +0xcEb4d6D473D6DC0C478d59037a97c45EA1E0e804,18,XXX +0x93AA36C6d465961B575BbFB8AC1377A0bd8875c5,18,CAT INTO CAT +0xE280341441bD68E9c1B1CCfede618f0f863CEAc4,18,🦦BOMPE +0x868BAA9320D79e9aFfb695858725F6FB7BC7ed07,18,drunk +0x24fCA802DadE850a7c4c8d29A921EDd603F746CE,9,OLLIE +0x3Dc93222d44aA015dFd30026429cF3c27eE5f13f,18,PEDO +0xF81C42EC85E228A86dc9cED746DA02E09CDa3F43,18,JERB +0xa915ac5572913c06A79451FFe3947016991E140B,18,V-TEST +0xa06df66ca12c1873D6E5885B0B7d3EFC4c7D9429,18,bubu +0xaa1AC4B59e960B734Ccc14a4Bce4BE715350C1cf,18,TEXAS +0x3d3864765AbbE273f814a0B99273e1cF8d1Fe073,18,BOC +0x3b79E7d118119bc91120C120b3793dbe540FE246,18,Cock +0x93b97d09765C7B481dC88Da81dEAda890f4Dd3a7,18,JP +0x5596cA167AD817cc5230C341C27D21993dCfcee2,18,A +0xc402F9126D414b86829e2822A731C084Ecd5e5b6,18,PEPS +0x98CC8C426Aac7C23Dd21adDC5082D75847522079,18,KOKO +0x24E1e00b4Cd06B7f19c56c0a881d2E9666A2788e,18,SPIN +0x34ea98cAcB437B432f75B21eBc0d772c8C598d3a,18,KOKO +0x9202f3c6eD0Be424A72E49F25FAeB032A267D604,18,MOB +0xaFd1dC9Eb8C9e47951102cEF56e4101C0e91c08A,18,KOKO +0x3cB31A121222e8189fB1be94EdD1d6051B98fbE9,18,DOLA +0x893165F145118f92b058c230A91E6Ff2a095f800,18,PUMP +0x35a6105778a3C7CAdE4C1fDebCe6FB9c6Bfbb883,18,UHHHHH +0x756bDf59eAEd73266323B786BdEfC9c832dc5695,18,KOKO +0x059B501330929a3c71B37909B65D4F8cB98562c7,18,MEME +0xc2D8D26e11d11a40bB2dF3Bdb6809ad3288F33C4,18,BEN-TEST +0xeC6F07e5E55D3f06796c220074179b3eb7DFee80,18,KOKO +0x4280415fe4dd3dBA5681d054048A589F2DE2427f,18,KOKO +0xc0c349B410817a3d3ED5ad9DD4d316dCbb98CC71,18,KOKO +0xD4EB36A4D99B7894AF57bed726F2163ea16B0352,18,V-TEST +0x3301940016faa3259045a59c16A70843285d3a26,18,KOKO2 +0x09cf80BDd19786120d2A21674926B47fB36fB513,18,Tom +0x5763147BDFb07c6FDb3fa036B7398c451771d678,18,V-TEST +0xE782eA8207c9c6421097f4D764f1bb4Ed3b5A1C9,18,V-TEST +0x6a0FF940A16032aA1436D871739F02107eb73E41,18,KOKO +0xD7B8c237759bb87E90d3Ba24723A728D2729Ca4C,18,LORB +0xcaa260463604F3479318b9B967668c9Af074a8Cc,18,CAT +0x107b24C41090eE88BbDa17e3FADe660C85cA2a1D,18,PUMP +0x538A89fD6382807681B47990fc8d9fD608Ef919e,18,Arek-TEST +0xa458052DFE661fef3595849cB299F9366519D710,18,MFOX-TEST +0x419fceb6B64c2cBdf55402ae50E736869FEEdc7A,18,KOKO3 +0xcA155e3c0B495858edfbAfC1c97805103bDccaa8,18,KOKO3 +0xC2D9F0B0c5a96B03285Df1A8B54A47d8E67d0EDE,18,AREK-TEST +0x25d87D381DA259aF3cEEbAD2441E2a69AACAbD2f,18,SAMU-TEST +0xaC8bC3379213dA50303BED08EAa389024fD34De9,18,SAMU-TEST +0x4dBC2bd8F0D6a90d230d053182eF3fe626F5f4D7,18,Iri +0x6b831665B348E4B89f87b560500Ea273FAc38253,18,SAMU-TEST +0x24634d4e5eC5002a9CAA977f4649D57D3AF59714,18,PUMPFUN +0x15a09258425931ca702676ecBD6a2dEca96910Fe,18,CT +0xfA569151EeF90d812E63aABED3fFF26DbE7C4164,18,KOREA +0x67Cbd63f123E885a28CEc85e1E3ebB91fDc9c71F,18,KOKO3 +0x5E9b243593380d1937e1935B27b96afEcFe914A9,18,KOKO3 +0x4E568c2B8b1E251f8Fe9FFAe3FcD5fF646EA7a17,18,MAY4 +0x16EBBd3e4A7183DB652E5699b404a6dFf1b82339,18,KOKO4 +0x19BCEA5886D8835c85fF72d0669e42f0794cebE2,18,SAMU-TEST +0x3028514B393fe8B7C991dafb983af0ADa942F6c5,18,KOKO4 +0x1B262fFc4EA59c9c8fC0c36FEc2aE8f92c6B9336,18,V-TEST +0x626F6c2Be9ebb0650228830883A905B14e7FD5D7,18,LEMER-TEST +0x90DE2a8Db8fCB32E030BEFb9358d7bF0B1826e07,18,DAT +0x5E642Dee9A9f40dDE5188873f824bdD6b278C80D,18,V-TEST +0x193e4F53714C15db72512355eDf52BD05F8CfC21,18,KOKO4 +0xFFb13c46e2D4462C9784f5123d165938131FDF50,18,sperm +0xC58A6776911b18d92fEa58533b617b830eE8ec7B,18,KOKO6 +0x1F4DB73D9f46962105Cc2d0FF9cb71cdfd2C4646,18,POG +0x4a721d9EfFe8c4DD5Cf3324df44D2F9256EEDE3d,18,KOKO6 +0x42161bDbc6e63B48F3633Da5B46191edFA819997,18,LEMER-TEST +0xc5f7128E0F03a1bc9507f80289420f6d73744B05,18,KOKO6 +0x7c6c74C9E5Fa8237aA512DaAa43deb2c1159Cc3d,18,NEMO +0x06864e0Ace23EeB2ef12020063551d4C73fAA2Bf,18,HPO +0xFE63278cE5FF4F3eaED8139d896A982Dc41C5a3C,18,pon +0x6B72EBCe45716e5736dC6790d2b5F7C0023CE1FF,18,Mario +0x1Ff66B66C789c4A47b32f4BC5806aF8E58Acdcc1,18,X +0x1A036309C6767B16393740215CD62F6280A40584,18,OXB-TEST +0x9dE2e1016A191Bb2eC20c3C7abE38f9637eF9fA4,18,KOKO6 +0xcDfbD1a86A0CA7dE364f0909F140Cf7436876Dd7,18,V-TEST +0x63fCD40cc5d10Baf05Bf66F1F6A1480dd047BC4A,18,V-TEST +0x7FcCA7f39e856D488B3E47853B7E6CAe47EcB89D,18,rETH +0x451019D3a720B60254a851272D450f94F06a73cf,18,V-TEST +0x182A2e820D11173425cba9e939598FDbe1B91B94,18,OXB-TEST +0x4AEF983f5F87CEd93AA8Bb9E9E3c40120Fe4E874,18,TRUMP +0xac2f7110fC7d0df9f685955622013086dC9eAA63,18,V-TEST +0xCEf432F90ec2523F157901a6B88439286D38c7A6,18,V-TEST +0x92eBD8465557C54E7829a41176E7c5095678F50A,18,JAPAN +0x83c239528Aa860Ee209a3B9CA6172D6D3c511E26,18,SKYY +0xbc092Fa27EEd4f4e39f28c429C7E0d8f45280Df5,18,NIKO-TEST +0x19eFADeE263233C1569841c3e514Ba5C418B8F1D,18,$BANFT +0x0Be8631276723fBfc230690D495271a293C9f950,18,OLLIE +0xb7d5130550fCF27D04543A6243999F3aab7ab56C,18,DNFX🦊 +0xAaC03a0Bfa67aA7ca88c41822b81541268BFa8F8,18,BRIAN +0x3918307b28d0F25ae8a64455Fe33a592B503899b,18,Bchung +0x2a673c22b6e8AD076823505f33632f48dB553B26,18,$USA +0x03168D9917e875325f765c5dfA0212d3aE9613f8,18,PANGCAT +0x3359B390a9DD1DD861d818B5Bf14c4119F10c8e1,8,BOMER +0xF2ca48c59da97e434cf83f4150C7806310f4DB9C,18,REDO +0xeeC9D0E7FDCd6a959479Cd8A5A075EaF48af1e09,18,BRCH +0x4e94825106761494676c4D5b981FeC28537443dD,18,V-TEST +0x091c2724d175073Ae48938fC5589583b34A6816B,18,BUFFETT +0x647B378b11A523470b49dc88C4AaD3A83446354A,18,KIKI +0xCab52a5D771bC0e71D11f80825e14947bA1AB35A,18,TOTHEMUNRKT +0xe951F19CaF0e998658078d47c35f8621F47cf576,18,KIKI +0x51F4F2BC1da5e227Ce76c86FeA7b306BC0F8d58E,18,KIKI +0x7BeCa4fE2cE311C7771003A45674c7becE42aC67,18,RNDR +0x598de5C830753C91DC09bE4749734328af51cED9,18,FUN +0x0320BF9908a63C5763F7e1d766fc8d0899cFAEdB,18,KIKI +0xB09aB8052d4136b8A99C97c984A8A3e9ABFe003f,18,V-TEST +0x7EaA0F40eB0d9aA331B9b12bd2b3d9b0B6355d6f,18,KIKI +0xf473340761473f67059e77928287bb53B906774A,18,KIKI +0xC0B414553DaDd5f12Bd7F2709DA311ef8B874224,18,KIKI +0xB50F0C30a6D8bBE9A6BEa08707942D5E73d00088,18,B2B +0xe5a24a9992dA0243ddc079Cf057C357Ce0BaaA94,18,B2B +0xDb71C6279f9D7F02b571fB5bcd2C605aC39eA249,18,KOKO +0xD12a09B50e30d13E94BCFC3c7E83029C582eB5d6,9,PEPPA COIN +0xc9CA6A4dF5EadA2210213E5F1dE4A46899481665,9,LIGMA +0xd60d956466058dD8EaA01d33bD2935fa78Fe7962,9,LACOSTE +0xCf35D84FA1eB06B07F55Ad408e3f0af907cDB6e6,9,$NUKA +0x833C67b621a2DD5Fe7394857cE623eC69Cf34c59,9,$NUKA +0xE173Db464B4AA97881071B1B65654271584FA6b0,18,TED-TEST +0xC6a7aC2FD5f45B49C478fD452A954B40D8F4DD6c,18,TED-TEST +0xC0459640762861A3059A47033cc8Bd3807CE6538,9,$BEAR +0xF42364c0fa7AB04c93B19f02CbA5410cEEC00C13,9,$WIF +0x1FA694C442c1DFf4Ac2E7546b206C07A92115C9D,18,BRAIN +0x01D05B2C9c3c17DdF6A8B0b09e00453161afE82b,18,V-TEST +0x24216fe58558A318C6477c23cFafb1F8Fdc4A929,18, Jesse +0x4a0E172a72E245C28B66B9fD65dF5a41b1003dcB,18,0xChris +0xA8b443e8F5f6B93189838cB99379f815A27C6323,18,CHINA +0x15917354c3257f7948A5705986AE0238FD1996B0,18,0xChris +0xA6f73159E906b33D1c9667D35a7Ee26Ec49E00e4,9,$DOLPHIN +0xFC504b699534e4eD71FbC31aD16655EAA95734d3,9,RCK +0x2d3f52C8632A7BD1752f96D858f365B7E3Db81A3,18,CuteCAT +0x405e4e821d33121943bc8Cb0bbC033e4A1d16AC6,9,ADN +0x678379123D18Fc81097C1f0d059EeD23F23fa240,9,FW +0xf66Fd37E92cDfc59559EcF228FC5b79685e0cF8c,18,KOKO6 +0xB03af6C94970927200F6d74aBC84EdF62b40637B,18,BRIAN +0x23146569e778AD9368cB31F7D5a41DeA565669e2,18,CR7 +0x96419929d7949D6A801A6909c145C8EEf6A40431,18,SPEC +0xCFC9e6d6f9E2fDa19a1513Ec91D0c50B17B1f5F9,6,GEM +0xc7Ad0e0A9473f2ACdbaa3B251306DBf8E4A64203,18,BURN +0x4cBe45e1bB8Df0b89Bce7e61c0380bF3cbd23fED,18,$GNUS +0x328e914aE361d479FeBb9B1a112A0A27F1F463e0,18,BRIAN +0xE07a954E36A859e19011C901DFbEA17426710c21,18,$BGOD +0x97442F474F6D8b3fEA11a3E6418E1c6323E9F088,18,$ELON +0xB577675DAc53CB38afE98c501AF92447945Eb6a4,18,ROOCKY +0x77f3A9dEBB8F3981e71ef6b4c0f6a0F14085F4e2,18,TESTTOKEN +0xCc62Be843b453B92B57563cF97e898F4cc6dECdF,18,HALO +0x2eBF3c90130b2082ce5A86f42Bbf59331F3d3015,18,symbol +0x0de68Df7E57bC9C564b7F8e7E5bEABa3a46c8051,18,symbol +0xb0bD00524936bd856dacd8da92ce0f1414A91911,10,VBCat +0xE43772F201c222f7305636E660F93cd281aaa248,18,symbol +0x96ec6b8936850B4b7e36d2f5279A7e9449790f34,18,symbol +0xB61a21E35E35FE6C2Ecbd0e689F52d834F4bF60c,18,symbol +0x5FaCa79Dd5eEd857f246F071Ba1C0190bc3aE24D,18,GNUS +0x1e6a39c68814b6fd83C5005030AAF325c1a34E0a,18,symbol +0x02A8b8a3a12D695a07be03953406Ee52f10d6eF2,18,WOOFEL +0x8567387F9d605873E84ea6F889A20cB07F4aD65b,18,symbol +0xd852248063b7fCa5D94e21e4c642C5646E486E2F,8,BIDEN +0x0D8b003fFA5F22D6f595dd3B4369F8d76C40C979,18,WAGTAL +0x1E83F5a5e530D0A531D88dde01e203d820461015,18,HENTAI +0xD20Af41dA5aF716d5161195d2de7E2fA04233a2C,18,BEPE +0x60497D4db295087a1b3EEBd26f142e46cE5E97Bb,18,SHEB +0x8F486Fa59C1136B63f5Cb8beee67c9AeB9d95177,18,VBT +0x1E60b4B4e89F40Ce6F93c8cD5f028a6007E776E7,18,AA +0xF45395Ba46e7F2a366E688E1edfb2Db6E5295603,18,BetaG +0x8e18fe2E6c2c00c0a01a5ecefF8874df24B2FfA1,18,ALBART +0x4E4f62B57b7Ec78a4CC0c37FB0B61a4510BE4a7d,18,V-TEST +0xD699A8b1FC1F01f515A0F9972087Ae37c25AC782,9,VOOXAI +0xC01e800851aEE88Bc8adf8Ba9D49fDE97428D9Be,8,ADO +0xA800dC8215aC8c31e3CFb7DD11d0A128BbFc232a,18,PUPMUS +0x245Eb25865cdC78197490FbB24B0D77E315d0167,18,cc +0x017F6923c928871B1ce6865467EC4AD4D280fE6c,9,BOSE +0xbbA50D32bf4E59311F39274974580Da874b87D30,18,BDUBAI +0x1a7927968C6e5513aD83D82ABf352cB378c18BaA,18,MIMICAT +0xCA63F4f6641eFB5baBD9EFE7956810C54F4b3730,18,Piesel +0x0979499779B31BFfA62884ca702e34eb10B66327,18,symbol +0xcABddda5f2D003555830B91A9F81b76FA943c9BC,18,🦑SQUID +0xC4b1f3f557cEc68F2249639f64cd3737F394e5cb,18,symbol +0xdEcD9c6e9245eBAa105f4971EfA5362f451bbb27,18,BULLRUN +0x913Aa323127A2E1E5604bD84D3f3d8B929215f52,18,COOL3 +0x2439F6366710DAFCd563E3348948dfdd641957ce,18,horse-TEST +0x2DD88Db80c9ee6EC1fE337EE3317Dd5D0c562F40,18,KOKO +0x4e020614AC6130c0bF71BdCD8aeF7F5E2Cca3eE2,18,bibi +0x70a04085816A689aBe937ed6eB16dA5c4337494B,18,PEDRO +0x74244415C811bCAF0aBE6740585AFE52FE635914,18,BULLRUN +0x51BBa29e3B0d90357b2a2dD75F56c38e43DC8588,18,Ju +0x9965967A90d726b5a139da85Ba51D408F55B31D3,18,SIMPSON +0x51c612BF22FB3e338899Ba5187c05410997EAc9a,18,HARRYPOTTER +0x7c3707548C78fa5f4bAF07bb5A85AFCD3Ed40170,18,JASON-TEST +0x150819FCCE6A7D6Cf105aD22142E09f5Df86e208,18,JASON-TEST +0x32C3F10bf4Ff79AcccDEB0CdAaBf92e471a8C486,18,JASON-TEST +0x034b345BD7E7991316a9E110E33A2aeda698A63c,18,66 +0x0aeeBa75378811Fa76590F432BCDEe3e2C426e73,18,pepet +0x4710F26fcbc455aaDf2a40734963B9EffEB7A9d8,18,MUSKYR +0x15cFEb9FdCCE1f49AeABD2BC1D9179006B3ce191,18,symbol +0x5DB4222C8e773094D7dFE2fAfC1a7b0193A30cf2,18,Tgr +0xeC27B029997E5901CEfcA5bc61B0EC7986E7174C,18,PEPEART +0xAd93be442507b73577aefAc892201cAa389bAde8,18,BREDD +0x66b5867bc6c6a0589E2C468F506F3CB6C74Ec8E8,18,AIJET +0xb377A59F291278eDC1fab028d33777DC019989B1,9,FDD +0x3F8E58Ff07C083788b8a242Fe6321BB1c872a029,18,BOYSCLUB +0x88BB03C0F82cd6aFAAbA978f5fCA9326E191C105,9,LUFFY COIN +0x5a5454016272A353c735085a9dE9f4b364E108D7,18,MYSDOG +0xf1188d8F68ECA4d6697901Bb78e72C3fa9Fe21Ce,18,TRMPTV +0x1E6169465955475Cce994b7A223EFbEe3BEC9154,18,FT +0xba3546f8db138F62338DfD666942EDC766df1316,18,pixel +0x10a9f33ce94420FC459c8b11641B69f8480f1534,9,ELONPEPE +0xDb5EDc73f6dA9e4F6a6d7C3Df44540431Fe9b8a7,18,BULLRUN +0xE7f32BaeDdeaDd98A2aEF83c1479E0Ac3F759B7c,18,CHIPS +0x40c0F14645F8d9bBf5D3867386CD0d97Fe169a8E,18,PELON +0xfCeB868925AB259C2345A50Fa5e3809a000fe69a,18,Olumpc +0x70ba2ede8b46d3b3b8840906a34705696F884771,18,toto +0x070667CF6B5C8C21AEC9324d8d9F47F4343c509B,18,$BAPEP +0x1F3cC713655ac4461e87259a3f0Ee736d480E86c,18,spepe +0x2b9b44aa68562daFfE88453dD86d8efa300cF4D4,18,BHED +0x398913fD83ece3467fdB6e7bFcA9Cd6569830AfB,18,CTB +0xa030a03E97C576a5A44B54D387127fFE020dB37f,18,TTTT +0xc1ee9011d81AA8132700F6afdB94CaA13E7992F9,18,CCC +0xF4320ff855888ac0Bacc087EF7EA83244eFCcecF,18,TN1000X +0x283405FE1B0415208515Af2E4a02620Fbf88eaFe,18,MIUMIU +0x3aE675993E76fFfDb2491EE8b0D4e81Fe19d5dcE,18,DIAMOND +0x440031ff0A62A339c213fc187916AD82433a8df3,7,BOOM +0x3c87A416F2906e4e282A52f8D4660eb1BAEC7eFc,18,test +0xAC043E77D1f144AC6a00Dce55770A1921193df0c,18,TESTFAIRLAUNCH +0x8Dece6A225516176f7854524f35B16177fc2D83b,18,bam +0x8C699B47F535584919e52D9C1099573811239A07,18,Skyy +0xD0E64768acd71D651E90ecb24D5D6B2a6b47Dc05,18,JESUS +0x1E79dbafe8d3D27B5E5EB02EDd86fD98F63eD12A,18,V-TEST +0xDD0932796e59C728E633Bd42587F91BD4cdc224f,18,PECHEE +0xBB0354468268405316892364eAB7aA159DD98E21,18,V-TEST +0xC51f1Eb75f26E95356457eef6B1c36c097D1d62D,18,test +0x32A6a178403B468811958953119fd9039604e7dc,18,LEMU +0xC26f3b65C925C534eA5A1FF6faFc7f264A1A9C4A,18,LEMU +0x25D8774728D03a240EA953613Ca7e1b3F61Df19A,18,EPIC +0x0Ac22860BB8E2F09E0cac6397D34b261158d7D82,18,COCAINE +0x135C7Ec51963b4b85B0fa5D3b0928f7D2B4D666E,18,TROJAN +0x92FbFD80098B9B85ae6DA619B331A4d6b4140F85,18,Skyyla +0x0084c4B91f198308eFfe3F30bDe7845eDbb0Efa8,18,LOST +0x75678318258d3C574FbEd236f5EC61ec5b8591C9,18,KENDRK +0x2aAd962605a55973C9fc2c9b75DaEb56C39F2e69,18,BULLRUN +0x9260409d4719c235C7c199106219f9616D66bde0,18,ArabWif +0x7AfD0a9F6d22AB0533B673d9A8267B482d941f24,18,LEMU +0x2d3279c6Ec4ca3826070fdF3A7b648D64716C6E4,18,V-TEST +0xC8F67Ec8Ca5Ed7a3B4546c87e7Bd953F308873C8,18,V-TEST +0x980Dac846238BbAEb2F2EA864d7d5fa3E9662F0d,18,HALFIN diff --git a/fastlane_bot/data/blockchain_data/coinbase_base/uniswap_v2_event_mappings.csv b/fastlane_bot/data/blockchain_data/coinbase_base/uniswap_v2_event_mappings.csv index ef8e33e28..77245409e 100644 --- a/fastlane_bot/data/blockchain_data/coinbase_base/uniswap_v2_event_mappings.csv +++ b/fastlane_bot/data/blockchain_data/coinbase_base/uniswap_v2_event_mappings.csv @@ -8882,3 +8882,174 @@ uniswap_v2,0xedC28cB85b748e532c9e249f0Ae3C5C90213b7a9 uniswap_v2,0x8552252f400132788D2c642E8328FcEb681dE5D7 uniswap_v2,0x74A9dD976723e7ce9023AeDDc51215308bE35382 uniswap_v2,0xFa867D15268503ad71e3cda97Eb6266c7f366Ab9 +alienbase_v2,0x0480Beff117Ba325B6322d85C12761fe615eF169 +alienbase_v2,0xe4327BFA7350E800F5C1C1b96fBbc974a2FF67f4 +alienbase_v2,0xFC98434213a3d736cb588355F30f1A1C01bA03B4 +alienbase_v2,0x07502B19cb5b10357BCdF630b30E41F232F0eF4b +alienbase_v2,0xE9eBB4056be45d758F612dAfE6c6cbB98c904476 +alienbase_v2,0xd3f93DBE6149454eA3D2426a151881E9B8448f2f +alienbase_v2,0x141e9882b7B102632EA104ceA866D087B4225bc8 +alienbase_v2,0x5FE1f9CbaebCFCC0Cba33db4642FB89CfFc11748 +alienbase_v2,0x65bEB0C98cc89Fa1Be971755B16309243EF3399f +alienbase_v2,0x8DE31b86A8848334693E43198B23d73260c55E01 +baseswap_v2,0xc032A4d54E5c89Df879578240D5332a1f585D17B +baseswap_v2,0xC32E88A041F644019c0C3Ee4ab5835e3d38E7bB4 +baseswap_v2,0xF2AaD3c9FD2C68DCbc0B6ac5C19341274f33f12b +baseswap_v2,0x6c7662D0236ce35918C736742418bc5dF796bA97 +baseswap_v2,0x569d81C17b5B4Ac08929Dc1769b8E39668D3aE29 +baseswap_v2,0x236d12142098Fa83693B7B5f11451dF81604F236 +baseswap_v2,0x4dd246E9f6c935fbba0633962808a8157855799f +baseswap_v2,0xB35a5027995E89b4412C38Ae45827C045d4FEf03 +baseswap_v2,0xe3e5E0BFac7Ff37393D525f838691b0b8dEA8BfB +baseswap_v2,0xF397081C22C35ad718684e6f2DD2ACb414F2dCb8 +baseswap_v2,0xE26158d053391125FF61a0933FC64df1F2605f3e +baseswap_v2,0x66b33e8624Ae38E43F1Fe930F7a6BE75FE86B118 +baseswap_v2,0x28E7B2526397549CD06584555806b1b9AFA54a11 +baseswap_v2,0xcdDf5c31dB6E179e344a552c65B65E503173E35A +baseswap_v2,0x7Ffb6222cec40710A78a9AA3279A00974c0429C6 +baseswap_v2,0x28D27263Dd485e2772F2233c80Cb6e3c3725858D +baseswap_v2,0x598A9F9a96c0836b73F08aE66219f2452195B74B +baseswap_v2,0xC43BEFDFC9B7212f4A096cC784c87A5Cd9ADD209 +baseswap_v2,0xa8697fBc69C787794793A39C04eCD677630B0ce4 +baseswap_v2,0x5B66410D450b218273a4342ea78b9F54b0Bd18d5 +baseswap_v2,0x85946478C49E2942C5ACf9923A405536853DCe37 +baseswap_v2,0xF3c85f90d4173320d369140A3a78e581E91010eA +baseswap_v2,0x78080242bcB9Db98F6E4563Cf56b57a614F517c0 +pancakeswap_v2,0x6CA40356e682a91D249AF252010561BbA18bF6D2 +pancakeswap_v2,0x0E10cEb1D295Df779bFa711fF0B2557Eb54C9837 +pancakeswap_v2,0x3f5D949D44373C44DB366e2A2e7864EC4Da5c134 +pancakeswap_v2,0xB4dB1f77D1dFAFC30890f75572b7b6215b9939D4 +pancakeswap_v2,0xE7e2e77420ec5DBB5F0513Ea404Eca2B24CEBB00 +pancakeswap_v2,0x4fC009a842Aa978Af2ED0D750A75b5aAF5c35F23 +pancakeswap_v2,0xdb9E3674Fc4f0B1E43974B3b27869F91FcA83383 +pancakeswap_v2,0x22160d23E448eAA9BEf7952b8a467D3920f41E64 +pancakeswap_v2,0x7DcF57e1C1E4dCA99A1BEE106664C30e4C1cEbf4 +pancakeswap_v2,0xA4B557be8835428bd12610141C7C27AdACAd3500 +pancakeswap_v2,0x94A48DBC0E3A7b0a92b6cF9bd6Bf97d72984F171 +pancakeswap_v2,0x9c55aDf6C4DBb25cDEd488cb6260Db64c9d7E6A4 +pancakeswap_v2,0x045B40B49F94401FAcE4FC991e27C16Be4b144f9 +pancakeswap_v2,0xe281D7d1EaA54410CEC3B8613a3E7175404AC263 +pancakeswap_v2,0x6E6DcD2fb6a586D90baE2C6DF6A203428cd1C7B3 +pancakeswap_v2,0xf9BCE7De4BeB10938D6EAF6E5D6D27e221468461 +pancakeswap_v2,0xD08CD223ec7E529F2931c40f1CC2D34a6A8DA6Bf +pancakeswap_v2,0xEa51982e8efE3Ff26ba5bBc317EFA1C44ffB73da +pancakeswap_v2,0x6e38C1DEE19245EC49e7B1F37e3CfFa8Be2ad189 +pancakeswap_v2,0xba7E30045151A506599fECAEfB023A236aCe0E45 +pancakeswap_v2,0x8B21Ca1a986DC2cE5E7D349580f000CBe5115cf7 +pancakeswap_v2,0xA6ddB465563c166b1495De5e8443DDD23FAbf33e +pancakeswap_v2,0x8BD9F77b20129c1C92f690b80De0Dee57876F680 +pancakeswap_v2,0x9a4D671dd3B549D746C9F389251Ca9304502A31D +pancakeswap_v2,0x39E7B235028fCaD17f0540060034A9de9A61551d +pancakeswap_v2,0xB712EDa9F444082f01A11e6f09254580Aca14ff2 +pancakeswap_v2,0xE4d0ba74bdaf0e6CEE8cc0Cd16FC6b01B35c8E64 +pancakeswap_v2,0xE8E39FB73F17B84B3D9fCBB0e00cD33742D578b3 +pancakeswap_v2,0xa61a76984b48462fB58E680b50478665E7d1D65f +pancakeswap_v2,0xA54677aFb5606239E49138304eA20f8a57A1ca79 +pancakeswap_v2,0x722106aa28bCB539B75e64becA9950505a9ba8F5 +pancakeswap_v2,0x83fBF80d594ddE56B6E8bb863ff0b493Dca85bA5 +pancakeswap_v2,0x9f4400eF226bEdae515114edA9C0DbaC48B738B6 +pancakeswap_v2,0xa825E2Ed5696f8B07E7871cB7A160eCaad353E8d +pancakeswap_v2,0x02F3BEc6c25B69641cca3685Ee7bDd56b03f39d3 +pancakeswap_v2,0xAf99Ed946686C55E830b98CC4DB6d4F39da310c7 +pancakeswap_v2,0xF28876B4870e3Cd9A0ADdA498bb50341d1475555 +pancakeswap_v2,0xBA6DF5F505BCa0f3Ad4e8345D9AECcbeec8C62fe +pancakeswap_v2,0x2bfAf877Aa340713878E3D343f1Df64e8010B7a8 +pancakeswap_v2,0x4A74335E41319ADACd21f2ECF370BFCBB90b4022 +pancakeswap_v2,0x464746DCaC79D4353c29942E18A5653fF4b87F55 +pancakeswap_v2,0x0D3241fc7c7b1457c562Fa05CaC0CC6BA66FD520 +pancakeswap_v2,0x2be7Fc6E641B6f7776eA115ee4fe0c18Fa7164A4 +pancakeswap_v2,0xEE8cB4049d72316281331fb73B1107046B5c784D +pancakeswap_v2,0xdCDE0fDD52c995Cdc4D55Ba8F6628685357DCF59 +pancakeswap_v2,0xFda7b2cD273C904372FbA83DC2192595A177ED3e +pancakeswap_v2,0x16Fb173607330061B8A3c755854258AED584900a +pancakeswap_v2,0x199F12Ce842c48283A19203AcC48D8196e1AB334 +pancakeswap_v2,0x862d424cA9E46792ed74E340a188Ff4ED1A471F7 +sushiswap_v2,0x925c2E236E451522F2e47DB568Aa1Ea976E066D4 +sushiswap_v2,0xCF0BFDc3859f84210333BCa032205f9c5d389633 +sushiswap_v2,0xD1ae7Df8438B3Ebb94862a1573F1F289F38df9F2 +sushiswap_v2,0xd923ed8A7e64B83021dd5999338ee444afE03475 +sushiswap_v2,0x5B086441FEA4Cf7eb605eD8E4cd326fBf6FA6a53 +sushiswap_v2,0x70d09044699B20938eD398D6bC94503A226d58Fa +sushiswap_v2,0x04be274F170c7E7c8c7Da4eC8db5935fB5c0C75b +sushiswap_v2,0x87fdA2aa1D8AC5eb3E5E67fdaF168Edc63b70EB5 +sushiswap_v2,0x42740c0e47F8B721a191b754f1f51cBB06afA9a0 +sushiswap_v2,0x4a279aD132181b0820D0c76e1bE545F114d65B12 +sushiswap_v2,0x6cf1b4F524D72c787C0E389bd53876dCd233F923 +sushiswap_v2,0x56E839B6a517bFbB67949F81F268C9e1be202565 +sushiswap_v2,0x5b36b542b3921c0c3922b655a74a3f2e72291f20 +sushiswap_v2,0xdE75CddE1766AA8438F83d0aEb171b1Ae22D1985 +sushiswap_v2,0xe10933A9d0d0d5Db8446c5b9E3b29FADb6f615DF +sushiswap_v2,0xB524206c2d083b35e15fC7006B9817B571d313b7 +sushiswap_v2,0x529Dcd8500F73723e45A10Ad3fdFD4bEb8a38552 +sushiswap_v2,0x862C04c627c4DCe115471D22Eb755fBf3357F4E2 +sushiswap_v2,0x565452C3d2aECe3F05eDC226B48e0FB8cb12CA52 +sushiswap_v2,0xDc1a8733DF948F60068bFA8B7a299fda460cbEB3 +sushiswap_v2,0xb33e70d829573C6BfAFEC2A484060372d2B56908 +sushiswap_v2,0x08A75d77d91c86446a8bD6936aF7e3321e69E5cc +sushiswap_v2,0x062aDF0216d7391dCf012855689D47D50d0e650e +sushiswap_v2,0xA1ad5dbb22a079d6B73F775ed4b83Cb5a2052ae8 +sushiswap_v2,0x38106c0468ad32D9E221A0C2C80092D77380d3C1 +sushiswap_v2,0x1FC5368e833A131624f314829B6745448DDa22E4 +sushiswap_v2,0xaE24A794dEF2F41C8541E4E0C40C620C44198307 +sushiswap_v2,0xD51CfB11E5656cB517Cb9dDdA9d872C7Fa310928 +sushiswap_v2,0xf3F4f11374faf5F648371281440a675a3959D757 +sushiswap_v2,0xeC1c0BA6943e6180f7f294ed4004c11BACb7B663 +sushiswap_v2,0xCE481c80BB44cdD51b655BC23CF06d8d2A3d3b6e +sushiswap_v2,0x9694F93C4e8774B7ae6E91F53b5Be74655A3fD2C +sushiswap_v2,0x40F89F8Bc616e656f3799a503191124096025A4f +sushiswap_v2,0x987664943E6e4509087DEA575b4d2bDa7aC7E00a +sushiswap_v2,0xbAC92F3c576EEb135b88457Fb68497c7e831fC08 +sushiswap_v2,0x20115fEB7De11660CbF9215663E060B093238a22 +sushiswap_v2,0xfEE6E412705277D6C56Ee4Fb858773dA2Df07aa6 +sushiswap_v2,0x0175FdD99f2F7E64C4e3E6EA5b9eF31A7F267AFe +sushiswap_v2,0x455073A3491A9CE0e4fc298dEfaF3a87a3Ce4a96 +sushiswap_v2,0x644d902Aa36E5e5bD0a3Cc01A1cdbF57736fC9bb +sushiswap_v2,0x647c342a0ed53c2a4950864B5B282552EAA519bD +sushiswap_v2,0x81F52cDAd52D6F9a8Ef439c1ec57D274aaB3B62e +sushiswap_v2,0x7caE4C12AC99B18F9F2AaB9F9d74931EB9868556 +sushiswap_v2,0x52Fe5103662A3585577D58Eafe81024913624cB6 +sushiswap_v2,0x13BbFb7e5e23b6c066f5a1CD3334C6C91e576a9F +sushiswap_v2,0x713d01Dc99Fb1B5cac8829FE11805492B656fcFe +sushiswap_v2,0x2D518f37461D4D1289bC7cd4fBcc7134Cf635927 +sushiswap_v2,0x4AA5B8057FB058B086512Fc3B275168a1c32A5b9 +sushiswap_v2,0xb8825f24CbA7640eEC739572c2bD789ccdd32859 +sushiswap_v2,0xebEC7d98a547647F4E3535409FAcB10c47459B59 +sushiswap_v2,0xDf495a2E05ba3423D516880D23849A0bBF896f43 +sushiswap_v2,0x543d5A177Ff075178ee0798b8960fa6Ce5a0fa90 +sushiswap_v2,0x95191A71FE3Ee72D8ec7B878a877523F9DE3073F +sushiswap_v2,0x2De1d86148B48cDBe86CBC85Be2E000Ed295572D +sushiswap_v2,0x15d5DFFF9C362f112bA96cB8000c20228Fb0aaa8 +sushiswap_v2,0x0F040E23653134569c798bFFb16887D8e1548d91 +sushiswap_v2,0x38CC2323cEf0364Dbd070c853e6AFfF0D9A774a7 +sushiswap_v2,0xEB42f563011C4410122B74165FaFaaC1E08a6176 +sushiswap_v2,0x7D8A038eC388Ce42A0C8369E9C8b9F34c6CF4449 +sushiswap_v2,0xa7347a593E84003a7B00A512c313eAA61c0b74bD +sushiswap_v2,0xDd5B25812768E84dDC756E73503B9F016025bd49 +sushiswap_v2,0x6795054Fc8699d04aDA529Cd4B8C26CEEFAb76fD +sushiswap_v2,0xf6E5E7E3325F5bd177b84Feb0d82719d26d4D794 +sushiswap_v2,0x4e5432Af805Bf3184043aA393aE101c49E67559E +sushiswap_v2,0x253B356899022514A712C0dcBCa38c2767A5BA7C +sushiswap_v2,0x53Ce13c19c2DDB41B2483ff5EA8845e8df4746aE +sushiswap_v2,0xe6afC26A854D008382DBB51888c929d12AF487Db +sushiswap_v2,0xB7bD1680940c312148AD03C5F4922c1fC505A84a +sushiswap_v2,0x9855d99d38E8E10212A2762F18B37F3b00c24cE8 +sushiswap_v2,0xfA6EDeb1fE62c1670edDd276f9b0Edb763fb79d4 +sushiswap_v2,0xe0F0a29b865F1c8E5ee849a02f6D647D9027685e +sushiswap_v2,0xAA6a6634e7674DFa7598eAc087cFBEFa8bCbFDee +sushiswap_v2,0x96015B167cab82658422f1573BF4158a11B7b36E +sushiswap_v2,0xc32F74CC1374dEF673FF2baF1404528179235635 +sushiswap_v2,0x64147907b2AD544008F2484f1DbaFfa3F655B3b5 +sushiswap_v2,0xC281BEEb7D543daA3ed6024B2c6512E5526fCbb9 +sushiswap_v2,0xEFE2C5CC2Bf1f734b0b79b3C17584dff3454BaD4 +sushiswap_v2,0x0300af30f95af0E83acD903fDb3DF6ab5c3abf57 +sushiswap_v2,0x1c5A5a93a9dCa4B786c7b0f2D205bd27Faa77ce3 +sushiswap_v2,0x216E583e24eFeB3ac106E7691eE8cA5a2B74aBF6 +swapbased_v2,0xdE8E4897368f273A43E79887437039Fbd740854F +swapbased_v2,0x8a4B358D1f603d1b807D0a19F626Be4eB3a93041 +swapbased_v2,0x58740d7F68994F203EA2313953FD5c6fA76B3757 +swapbased_v2,0x5aE84DDF1a70cFAEB84384CDE6DCc01BF6F64FA4 +swapbased_v2,0xe85d5A74756cAcB4B2E066Abca8971136C10b9db +swapbased_v2,0x4f77edE2920B2b3C91A8f958a1faBC783860cacF +swapbased_v2,0xFED40880CFc8b8e3888963305c2edB552aD4B433 +swapbased_v2,0x6151C96283485602e10709265a12Bb171382381c +swapbased_v2,0x0dbE022a1d3216809bD0e22245A5b371C0C73F4D diff --git a/fastlane_bot/data/blockchain_data/coinbase_base/uniswap_v3_event_mappings.csv b/fastlane_bot/data/blockchain_data/coinbase_base/uniswap_v3_event_mappings.csv index d3aaab95a..1dad7b857 100644 --- a/fastlane_bot/data/blockchain_data/coinbase_base/uniswap_v3_event_mappings.csv +++ b/fastlane_bot/data/blockchain_data/coinbase_base/uniswap_v3_event_mappings.csv @@ -26125,3 +26125,1341 @@ uniswap_v3,0x1C201401d00EA91D1CC2C5705522Af28aB01E393 uniswap_v3,0x6751A76875E4C0028b8a9d496400CA625E860EE2 uniswap_v3,0x7b4012De7ea515f42F69df5114e767dABE7B8C96 uniswap_v3,0x6B7FC62f81ffF9D13402C32C7a3A1E56992b38E2 +baseswap_v3,0x1F9e844eC387943F262d8FCc1503EcF71c77C6CD +baseswap_v3,0xe73bfA46cBb78920657Fc1806147622892fb3622 +baseswap_v3,0xdc1f1BFc36a2EE07041e01d7E38cbDcA3985fE9C +baseswap_v3,0xD70ed7f34174c70fce41790Ed55C0D19dBD60103 +pancakeswap_v3,0xF44FBe634C11008D6e8420055524280C4C9dEb57 +pancakeswap_v3,0x1C4785EBfF4c5aBb1cc89B57F33FF33385f61C1D +pancakeswap_v3,0x3c65C4dd602A8876B1110920d778E8A91355Cc7b +pancakeswap_v3,0x01654e0c490dE9D61436656D125cEB2229277b7a +pancakeswap_v3,0xBe3F091AB33689b689071c6Ca9aAA519c7bfAEC2 +pancakeswap_v3,0x85841184a2f9d75EBee49cb1419180A3761761bE +pancakeswap_v3,0xfe7337D99910440E075099B9108B1159ae59936d +pancakeswap_v3,0x05d03b47a01653352b1b986e3D33419927915DeB +pancakeswap_v3,0x54A6ada1FD8022529ed73A36191A3c8A6fE4c2E9 +pancakeswap_v3,0xcDCFC3398a82552B97A8056f5843df0Bd42bB386 +pancakeswap_v3,0xA6940BF7cD7FA14404AAe97ee7F6cdcD131A160c +pancakeswap_v3,0x98911784e16A16D02E7f6A8aDF40CE4E857f6C76 +pancakeswap_v3,0xA5E67906fF0Cc32ab79659941df8124d988FB86B +sushiswap_v3,0x10182408Aa4bE8Bd7B79902CF5D31709928CEF0e +sushiswap_v3,0x701ffF7a5A5074bA8F0b721b67b8C15495cC75Fa +sushiswap_v3,0x31F1899143C8d4e84dF9465C6058d720A6C96A99 +sushiswap_v3,0x853b9a08f70d7558600778584D45632AC9DAe9c9 +sushiswap_v3,0xD54C1B5d1248D4E15F9f229DA0d04901a48C36b6 +sushiswap_v3,0x1a10B5DaDad2197d67A641110D28C86CE62bbE51 +sushiswap_v3,0xD2d5f1482491F7Ebd35dcfec3cEa9d2091019E2c +sushiswap_v3,0x1d9ff97295AabfCF0A83D66aE5ffFF9E992002DA +sushiswap_v3,0x9D0576d5348c4a41903174806B4b7a8C6A5d212c +sushiswap_v3,0x28aAAfeB16A2515450ab5e7433ec3Fb2A76c9DfB +sushiswap_v3,0x333E2A6DB1d855fE949288a6CF4Beb689d21eBdF +sushiswap_v3,0x7db739c955a63cAF9F0370B268348aa76E274Da0 +sushiswap_v3,0xb223ad8E7613e1b0cf6795AAB86bd83Ba45CADa3 +sushiswap_v3,0x65a333EebCFfD2C50B4E4e0f0847C8aD0d5a5b5A +sushiswap_v3,0xbF4212086A25F498c9263092Be63856400869BCC +sushiswap_v3,0x62F719b547fEc43E99f91203d5dEDa3C0D8E77be +sushiswap_v3,0x49cC8c9E167fCBCA57f43ABD24fda47107f7230A +sushiswap_v3,0xAa98B808cfbB35EED0a254C8c96A138D5f1e0403 +sushiswap_v3,0x8C6dB511654853B02378Ba14e4321B649682A6B1 +sushiswap_v3,0x26bf1AA2Ca5F948E46b68E576C58eF19e192FD17 +sushiswap_v3,0x547120AB66De1FCC71De25AA1c040c9B9944B1C7 +sushiswap_v3,0x2f7B2409FD8Ac5ab01242FADC273F3e747200ed0 +sushiswap_v3,0x0CBDDad882cC64ee32C1b0AeC13990a599735e70 +sushiswap_v3,0xd71a622aC6Afd83FF4f8Aa5dA22AD4B7f17078eB +uniswap_v3,0xffbED1eB83caC2Cd0aF35257646be5d935093668 +uniswap_v3,0x16e5F8Ea91440D9f99baB738C2470869F357a04b +uniswap_v3,0x1694296282c2634eed3822F76c5E9505fD602bA1 +uniswap_v3,0xaf1349264Be9daFfE76D66781e8f36de9e6Cb0bb +uniswap_v3,0x6F01c4A589e659A9b52Ae29e0d40D65C85eDf8A4 +uniswap_v3,0xfaD3cb6362F9d1703Ba5A54e465324b892609382 +uniswap_v3,0x5DE0929a0A5Cdc2A3791255CeEF3F74d8701E722 +uniswap_v3,0x6aCb9723c5f2D3a2B210609959F8B7c2675B86CC +uniswap_v3,0x29355AB16b00bd0eB587A01B210A2471ADafd353 +uniswap_v3,0xED0ae16861478CC7049F116E7E7a922fDC5C1144 +uniswap_v3,0x660f837E65aA0A52B302E958699203cD03fC4c32 +uniswap_v3,0xC3b54fD01FC7911fdA40D8d85b16BAa276F4d0fC +uniswap_v3,0x9Ee5F5E030C395FC8dB4C8a576ab4aE536E830F6 +uniswap_v3,0x49418DbD8FC7d7d2642031FC72DFd7E4162F8eeb +uniswap_v3,0x248F1844775242DD09ad6b54209533152FF5BB1B +uniswap_v3,0x45804ce884D6B5f3b4673B295c3EF84bE956774F +uniswap_v3,0xF63fAcD7d73aE114b2Aa3b803939C210672F429F +uniswap_v3,0x7bde5f73d71bD33ebF080182d35398fF0e8063C3 +uniswap_v3,0x793e0c0EbE2856dcEb82eE90fc9E45bD003617Eb +uniswap_v3,0xf1FF40E71E8eAA1599e3729D696f236E77116CC1 +uniswap_v3,0x16096d565cD3c9Fd4f115A57992EC473Dba6B2db +uniswap_v3,0x63927c8c41fA1068555b3c872fd5a38B754d8B0e +uniswap_v3,0xD4eD33674F5dd4Cb46FaF8d03ebb15cfa416e4a2 +uniswap_v3,0xaeDb4ec388082305f34dC4fFD87d857ABC30140f +uniswap_v3,0x3a49a39bf6DF45004D23a948273BaA146Ce98464 +uniswap_v3,0xFE341F852a829E57bA1BaFe4757Fea6b9aFf24B4 +uniswap_v3,0xA2944E3535231426E36B5014A12Cc2F0ecaC86a8 +uniswap_v3,0xd8D3Ca0e0c5BDdfE1439d3B87bcEeCF2aF48c981 +uniswap_v3,0xc580540b12004d4D987B4b54e1C1e684321eB9b5 +uniswap_v3,0x99d32Eb9277Cd32a7f959D633b9BcF0A76a2605c +uniswap_v3,0x9BFA705c5FAEBCBCb4B845B4A8c4009d53fd2130 +uniswap_v3,0x148E3aE3057B993e7285782E2d3e785503a9874F +uniswap_v3,0xA3070a96e276071D316eb4B50552E8FBE3969e6F +uniswap_v3,0x6A69c4737F533099E251e9c2D73e9F86dF36FD33 +uniswap_v3,0x194356F218577F6FB7186D85D4E22A9999758493 +uniswap_v3,0x4a93032dA1cEA33E7b31311a7f5580918Ffbf644 +uniswap_v3,0xbc5C4dDEa0Ffa1c85cc97c2428FbDE94AD09FDf1 +uniswap_v3,0x40a1f3BCD4E112Baa9a3F76BeFd336a45bD0A3A6 +uniswap_v3,0x51069Ff6039Db97965D54638283C6db98b2bdfA3 +uniswap_v3,0x822B01Eec0B0fd94B6Db4e8495A707636ABBE594 +uniswap_v3,0xaAAb6dBc0C5FE04D4a617861c25b15717aeaC2e9 +uniswap_v3,0x763163Dd010E7fe63c835b2D830bbb9A4cd9d41E +uniswap_v3,0x819Cd5a0A02de51609E7466303f3fBB205BBf71B +uniswap_v3,0x429002a59b8399A1c59e1A38d215C2d7536ea959 +uniswap_v3,0x18a406b64f2F8240C3AD8c4e23D42E284eF35511 +uniswap_v3,0xb08ABA450E61b96Dc38CD9A9229c27B96aD851D8 +uniswap_v3,0x53BA16BE0983bfF8F44ceBF17359161aa140B7D8 +uniswap_v3,0x3f4C6c6673345E62c79784D042253206B7fa85a1 +uniswap_v3,0xAF8e928F7fd438CEA6F4829c1554a2439f311aCC +uniswap_v3,0x6E9BD50AE4Ced7e62e1f45c08e37EbB8F5aEc0Fb +uniswap_v3,0x5aC3d8EA4D045Be6baAbF144b1137bC775B673F6 +uniswap_v3,0xA6A7CcE47dcadA6a3377Dd71F913f652FC86e58b +uniswap_v3,0x55Ded14E81367b46375bB4576e58C6dE91fD31EC +uniswap_v3,0xDED8827E3598F1344D5267C073eD2eCcfA99F4aB +uniswap_v3,0x4CAFABD9222D42Eb1DD0E9af7bFEDD58aEB1fb52 +uniswap_v3,0x6672484fB5A9b686fd6fB223b5a2B986a12E28f5 +uniswap_v3,0xe6Eb66caFB64555247C91CA13232c0F5efA0d7d0 +uniswap_v3,0x6Da1453eb4B6dD99B23beD48A58e80Eae6535C62 +uniswap_v3,0x2D8E2f323bbe6dB86c9eE32505Bde652dca7122D +uniswap_v3,0xe0bFFf35B46572D153c68C29ee7d08E9D4dfe286 +uniswap_v3,0x848FE1d84049Abd4AFDd9587eA2E5f79d1Edcc51 +uniswap_v3,0xC17Ff8380c09685B2A671E8076c98E5F2eC56832 +uniswap_v3,0x9A0c2DF1188CBCa9a19ae8f39e00Af0d31A326a1 +uniswap_v3,0xFF1771991D40EFe5bc0e4D13F289B020a8e77Cd5 +uniswap_v3,0x09DeA5B751a7f9597816cB52F07b3E4E08F0A8C8 +uniswap_v3,0xdf9C1e52229C22a85291759173A746e489913F3A +uniswap_v3,0xd24Af8C5750DDFFB5166d1c3Ee15e2E20A3e47fe +uniswap_v3,0xc2eEa1590CC558e3BCbf4d0752A1892bE8329F52 +uniswap_v3,0x124AdDf329EF469Ecdc24F76E74835070E8e4F8D +uniswap_v3,0x3C1904E72De9bd58345646A0DF8a7b3Cbe620419 +uniswap_v3,0x9E0734e21e245c70f759beDFF28Df0c78740312f +uniswap_v3,0x242754a052dD1aB53eE4Bfbe97a0C8092b97118c +uniswap_v3,0x28D6561b1c2337a28D26E11f4B79A280706052BD +uniswap_v3,0x1112a4837Ca4f730EFeC0F32b2277f61F6Fcf138 +uniswap_v3,0xA4e64b605714721Be050E4Dce84B1cd5Ff4D5cF9 +uniswap_v3,0xCf432647F9438510c0574052168845E7f139180A +uniswap_v3,0xd2B148ec40c966935EAE5ae5D1dD7c0346d60678 +uniswap_v3,0x830115860EceF0dE5745B29D441722384Be076D0 +uniswap_v3,0xa48507715d7d720CCEe32b3c64BECCCCEcdC1692 +uniswap_v3,0x41427e5a25c7303E2C85611773f1CB20A94360cA +uniswap_v3,0x0FF765541b6549BC704BB51Fb3720deabcA0D81E +uniswap_v3,0x51DBdb031b6cA927e6E5C87C001110a8E543E658 +uniswap_v3,0x439b5BA612eAc8b7426B74f6730d7e523F8264e7 +uniswap_v3,0x2b1Ecef2E2B3c6d002639a470916bF1d2B698c50 +uniswap_v3,0x9c056626Cac41b5F2643c316c376F9Ee1Ca06b14 +uniswap_v3,0xEF9F8d73305cf2d579f8Aec864089644537CcB9B +uniswap_v3,0xd65D0A292479150acF2a7F265a32Ef1BDC89910F +uniswap_v3,0xF1Dc48Be2E2097EF6c49Cc4500c684115DD47d25 +uniswap_v3,0xB0B8082ceDe5aF681657dFf537180786CBC7a7E1 +uniswap_v3,0x1deBE54DAf727DE6b771Ce53B8E4c9E5792fCe99 +uniswap_v3,0xA31C4Cd181880c4808A2d06a2e48F73eFA85cCf7 +uniswap_v3,0xFB4942A1dc6d36f6EC0bAd9f7c313D6982457321 +uniswap_v3,0xcA351C891bCf425b92ace8B23b812BeA89Bd889a +uniswap_v3,0xf3624c4eC7Ec4b68fec33787f983c31fC7eF630b +uniswap_v3,0xC987c309639c1161d256FB853A156b835A6560f1 +uniswap_v3,0x0BCC4440ac3d73b75E8ce4Cc0dfd80C80A793c34 +uniswap_v3,0x19c3aBAd3b624Bbb57f6A2e3dAFddFf784117F53 +uniswap_v3,0xEA14A25c2D5F84bf830396fC4f1636d786d8212d +uniswap_v3,0x59eE1b254fed3BB2F127898B6026C1d4Fd97C1c8 +uniswap_v3,0x5ae30F8f8E6EDb62Ae2f4Cd06d99f54746E764FB +uniswap_v3,0xB97Dc68B986860807C6c8ceCBECEE3F5D05Bfb94 +uniswap_v3,0x054bab8FBea52Ce9921391dB4964f2703635CcE3 +uniswap_v3,0x3C2cCe85b57a5650cB314e2ec2ec74022cD58A77 +uniswap_v3,0x492F0E2B1BAC7A0f2064283bcAe581ED1120Ce2e +uniswap_v3,0x674e2bd05400250f95C6D70a0B7ea50680A25EB8 +uniswap_v3,0x5dA5De57F6666Fc6bf67069749919b3D25b78362 +uniswap_v3,0x32bbFaa054b6d8DC4B586Cb0f43927c6553aD545 +uniswap_v3,0x873e3C30A2C17665A3cd969b95c1A6D67E7868D9 +uniswap_v3,0xEd188867dE47e3fdEF1bca4C169952D1095F386b +uniswap_v3,0x3245EE3647E156901734eB03Ec5F6B7971Fc2E6b +uniswap_v3,0x1553cb65B1c1bd25093fe33e80AEDe294eF16CE0 +uniswap_v3,0xD8684a076452b527516eeecB29181da332A5B871 +uniswap_v3,0x5ACE5D7D3d9a1Ba068dEf3f11bA7188d4F8485b2 +uniswap_v3,0x18f4888ca98fb9F29D3f0A1481020abB919995A5 +uniswap_v3,0xb2718fAbF4cCe907EdE9B77823764FCFa8bdCB80 +uniswap_v3,0x5CE0CddA13b5680ceD76D875E4C5e279Cb48243c +uniswap_v3,0x96814DFF280A2CE4aDF62AB7aE15cdFF16818fb9 +uniswap_v3,0x2f0D1938cC263Da07B9a851aC47aF9dC845116A2 +uniswap_v3,0x0912B8d7d23050773e8afbE0e8C564A9F095777a +uniswap_v3,0x53E8A72C01daCfb6bA06A3c78764cD1Bf5E5939F +uniswap_v3,0x47c8E047a5CB204080BFc16bFDb2B6D58d53768E +uniswap_v3,0x7E9800297F389d0a93a0F3caE12C69672a431c60 +uniswap_v3,0x9d6B7470306121392F1Eaf91dFF9deFB15D589F4 +uniswap_v3,0x3E67Cc55D0FA52cAf8dAc548e460287D6A71cAd5 +uniswap_v3,0xF235Cc829E5e49450c5A5E819c13a540D1743713 +uniswap_v3,0x3a4a95F4F5E8CE1e2c24717a5B579c586193173f +uniswap_v3,0x6704F48fca12d8fE1EF8511a7d5d751B4cA9308B +uniswap_v3,0xF9e857f8Dcc6230fB61d020D6a17abbf3f58F808 +uniswap_v3,0x07283C9bdB76fFc56C5ef31725E2D619df977bc9 +uniswap_v3,0xde6eF606552EE43403297D18Ba5682F5cF317F1b +uniswap_v3,0xE7a0A4CebCbd453aE07A7723178475FcFAa43894 +uniswap_v3,0x306e600e33A9c86B91EeA5A14c8C73F8de62AC84 +uniswap_v3,0xC8262E09aE4A4Da3E3b61899Aadea5d6A4De1C0F +uniswap_v3,0xB2964709082830f48DCf98F161b8F5BEFE1419b3 +uniswap_v3,0xdcE6D3e28F8E19B7cCE1102336ea2E417D2e9195 +uniswap_v3,0x1364F9B5b35402D4Ad91F84dD24eFe98B5E4Ef10 +uniswap_v3,0xE64d22CF141AcF3724222456bd2e25A416b1c2FA +uniswap_v3,0xcA11e1E048ecc90A502B489c37f4ad7718c8B2a7 +uniswap_v3,0x9989B2E84149568fbda2F84450ef3fC427F51986 +uniswap_v3,0x71C4F2B444460fD070af3D0E3F5C74794EE29Bc7 +uniswap_v3,0x2BE85D06FCb32E08C4c2D3D3b1e15978Ad10a02D +uniswap_v3,0x250CE7133fadA6601674B2bC61bB39a6897F46BA +uniswap_v3,0x2a5f51b6d89B468C76938b85C5B654c9cd2810C0 +uniswap_v3,0xce5F90543319A7BDaAd7d2CA7669a86e355bD4ef +uniswap_v3,0xdAe51c3c20F85cEBbfb1762fF2F5A3B4FF1577fA +uniswap_v3,0x167E2c3E3CEBE99D3759eE7EF5374d8D0BeAd17b +uniswap_v3,0xCfb4735c33399B584ae3c2a6f02e4495D072878B +uniswap_v3,0xF8aa1Db87D84118B0b461e2135190ac27fC1859d +uniswap_v3,0x8De7A2dF0D3AD9dA6cF4C0Ab438f39498983B585 +uniswap_v3,0xfB52f3DCc560fDe4E8C925643cB50B0e50f63008 +uniswap_v3,0xDCF02aB5CCACC1e6EfD8eDA95C026eDb1B1824e9 +uniswap_v3,0x20820B027b6F5912AEA0B7Ee6BF940b3D1fDb5fB +uniswap_v3,0x5899A78a923eD4130d7cE4377514c8226741503f +uniswap_v3,0x55cfb5Fc5175Fe9476d95dCDaCeedDF77Ab49323 +uniswap_v3,0xde294b4659C0143E0A4732BE939620273D625540 +uniswap_v3,0xD586dEb2d4101897f044187c258035b55677856a +uniswap_v3,0x76fBD9Fe99C302188c18A9f69005d21CAA3a98f3 +uniswap_v3,0x06D406AC8a9d987A078Af7573F00B1D79C00fca3 +uniswap_v3,0x306BF5bEb24Ca5E714D8b8AE2e6Ef6CF5E3213Db +uniswap_v3,0xEFA6d525a026c63a101Ec5026904E16D05B45aB9 +uniswap_v3,0x63efb043D724c9ADF2FEAeBC3996F51A63D7F44C +uniswap_v3,0x45b32142268e93A3960EaD948A7dA2037A0eB5e9 +uniswap_v3,0xF6205F8A4D8ae1A4F1B06BA94da2E6C41048a24f +uniswap_v3,0x07a8cb149c3DE72060A74cbA0f94E9D6099e5816 +uniswap_v3,0x4d9ab70c1297adc010dd1b3297e7a34047B952E9 +uniswap_v3,0x87E43b6077D95fbFc4E078EB7474Aab7Aa1a0aa0 +uniswap_v3,0x4833D618E5382358e685055e2755D9419b1138F4 +uniswap_v3,0x1c4bab1F6F5584d7d4Dfc6fC91c31d01f0E90dD4 +uniswap_v3,0x4CB6B44a484bbCEB3717A283FDF9035B9721d2e4 +uniswap_v3,0x443359F4d14E530dA0DFb58Dcfb94F6Cc5ee860D +uniswap_v3,0x86279c78b20Ea9d60bE074073755835671Dc9A3A +uniswap_v3,0x8ec50f133cd304C39217F775054dd0f9740bF35c +uniswap_v3,0x07D15440268B240210CA9742E5ccD781371Da619 +uniswap_v3,0x8f74E7A96c2f808517032D6492d43153B156300b +uniswap_v3,0xea45fC1A8F8Bd6c7aafF7d3Bd61c05C318fB1060 +uniswap_v3,0xe5478b24A15c0AD14679342d421519978DEf3687 +uniswap_v3,0x9D75D9B19e7A858DDD777D1e0539584fc1b2ad88 +uniswap_v3,0x74a278035b2C89c66BA41209a1AC69181e9569cf +uniswap_v3,0xc00330d4B33Ad0F59CaC293Fc561411437Eab1a1 +uniswap_v3,0x943f1c91b9def2a389685C4eD52bF245A3c07Bf4 +uniswap_v3,0x89407D870318d11256f743E258Bd2d360eFd289E +uniswap_v3,0x24FDC3d393623eFe8dEA92C191cAFB8a7b15819B +uniswap_v3,0x548B6922F40bD0d75e5C93B37b4e48100bFF6355 +uniswap_v3,0xC1aeD10c3AAfcb09e5cF60c125Cb63e587F97788 +uniswap_v3,0x332A3343370F51EbBcaF9A14Be4513A5A512c2fB +uniswap_v3,0x3D8bAb1418d9588f9DaD55eEB5Cbe76dA02533F7 +uniswap_v3,0x2B6Ea0e6A027f260201EcDAA06d6EAb6608a0039 +uniswap_v3,0xaBCBAe18E0d8DAb704B323E7388cC9F5d4E325Ef +uniswap_v3,0xbD803Ba75D3ff784B6acA8C24360F4336147E372 +uniswap_v3,0x13FecA769C4d264C188880896f07933d7157847a +uniswap_v3,0x6dcD1a4A786cf1370B51D5dA7D04054fe852ae78 +uniswap_v3,0xEe2D7b9F3F78cc02F65C23CD597F5cBB2bAE3d2C +uniswap_v3,0x4D06DFD0888feF76498b395f79E766a23c6dcE47 +uniswap_v3,0xe8Fe41e14933644E0C8FFa05Df285Ce7a6929cD9 +uniswap_v3,0xA20b8DE9A08c107488D19cc48BdAeA48602e76D4 +uniswap_v3,0x5Aa65DB9B374E1994c7B559749e78A41D9a8ce9a +uniswap_v3,0xB578EcB9819751DC83A5a83Ded72397925eF8cf7 +uniswap_v3,0xABFB3FDeeC099eAbF46a5D6369EA41033a6948d1 +uniswap_v3,0xAfC3B0a0670380be1a19D39B7CB40eADd63422ee +uniswap_v3,0x7ef7f515EAE00cc4fe814eF8667f92C923a96ED9 +uniswap_v3,0xB432540909ABd3D9175BA75c4Cdd5D013B43b1e0 +uniswap_v3,0x699De67E45eF711c571f10BF674769BAc3647f94 +uniswap_v3,0x9087E3Fdc93782fC21Fc7B6E1c9F18bb6469460E +uniswap_v3,0x51d9A6f8022452bd56850F6E70E957DddE4E5677 +uniswap_v3,0x43DeC70ca029e159da315C3A893198bFD44Cc71A +uniswap_v3,0xfcDD9801adaaF4116ea070891b1A47039e60ed3D +uniswap_v3,0xBf05446d5C285B340122327537C500967aB628a2 +uniswap_v3,0x2C8265695a97908987De6dFF051c789cBE157AB9 +uniswap_v3,0x254b0687257Eb2f31a31c48C5377CE40aF833910 +uniswap_v3,0xcd0fBc9B628431a4f8aDE0D7D3AfFf82Ac99877A +uniswap_v3,0xD4Ed80b2105B3fb9E09312D19d17cadEF1D4C08E +uniswap_v3,0x2B21ED281dd9Ff8CB376A946D8526f906176b9b3 +uniswap_v3,0x9D3a72AE5D51A5BF06D3127663BeD5BC2c8fa6Ee +uniswap_v3,0xc6fE8f4BFBB69A9C6934C79dEbfa8E9696832ff2 +uniswap_v3,0x01856c7F8ef4f17E84371359b2d85daC321A9aDD +uniswap_v3,0x1aF74978BaA31d6896CF9321bfa2940D84e0F614 +uniswap_v3,0xb7b235A3de152393622a438ce70b772514D2EEb5 +uniswap_v3,0xE2a5145e56D64B267da3BdB4BF6daBC39687e1bE +uniswap_v3,0x2e7889e5a510425dda34B5D527934952C0f57e5b +uniswap_v3,0xbC22FFd36DC1286278287bC4073271389923a87e +uniswap_v3,0xB0CAF40c6D8155aacafE5b0a46FCa153bE1761DF +uniswap_v3,0xCAB54c25B737194A42d733c4C78ea2FAA7C356Cc +uniswap_v3,0x848609210d65cfdcaF450f2f65ee6411dbE172B4 +uniswap_v3,0x9C36E4eFdB1239652B23F8ECB53f0b0335a5Fb69 +uniswap_v3,0xbFEf5bB6E46cA995fD0C77ee60E68a27FFBC587E +uniswap_v3,0x825a750c973bEC0843a63e950fe2A632731FdF45 +uniswap_v3,0x5fa36079A205136e1022Cdb706bcce8cb0ceE5C0 +uniswap_v3,0x7c0336C47B5C8F6cADF519E2049F39C9a1b41BEF +uniswap_v3,0x72DC14c6048c3C35dC4610DEED47880e464b0304 +uniswap_v3,0xEeBF77d720a4971E2f5a1658195FB1F619cDc6e8 +uniswap_v3,0x4efDb13693aA9dc98eB4043A302c752af0BefF3D +uniswap_v3,0xDFdD21003E6a6708Ae40A5ae065fbDA6271b6EE4 +uniswap_v3,0x5B98a625E8c178d8A100DFE2F905F39cb4343F35 +uniswap_v3,0xEf057617e6B08b585f91b97c20010572D3bEF898 +uniswap_v3,0x797a28ABA77Cab5E1e8117D34D8300D8EC76C51A +uniswap_v3,0x83a1A95eC4010ed9841e12bad77bB258c700Abaf +uniswap_v3,0x358Fdd2EcE9d5269056177F0fA1B1f79E0036044 +uniswap_v3,0x3215A229311D654eB31772Fd3cEA7D78da731CA3 +uniswap_v3,0x9C63D621F26777570410E130f9a7F7E609F93dFa +uniswap_v3,0x33C4baE3899e26B445CD6D95376494c86A93dB1C +uniswap_v3,0xFfDc5DdA56FFCbE6D3cD22018A19880d87DA8078 +uniswap_v3,0x4b41E9bC81a33A2B8F4Db48665Ff05c13c53eC66 +uniswap_v3,0x3dDF15B168c6D72F8F6cB63baE83313E3dCd5459 +uniswap_v3,0x05f6C348e293CE068B5f7682cb01dc28524Bf6a0 +uniswap_v3,0xf653865af76f3377FF5277C2ec4E81152bFda1d1 +uniswap_v3,0xE31719e329080985a93648436E7B4D3D50180e7D +uniswap_v3,0xE28617a46558E38F1Ef118cCB71D2763001683eC +uniswap_v3,0x1a1E8D52B0B51FE415218e74fAd60d10d48C2388 +uniswap_v3,0x83f8D1A2CC4E329a7c8Ed4C28fC74f4c5b6Ca45c +uniswap_v3,0xe9C5f3331Bb7de5cc527bba97B87Ab7D224d6637 +uniswap_v3,0x4683B3c254B397d97d24Ff86b349c83aBa8aA250 +uniswap_v3,0x1F24D4Fccc6C53B5b2162C475856E1a64AB17b4a +uniswap_v3,0xA091E2DCe6659F9Aa88E2cA73265a8DF160Acf33 +uniswap_v3,0x9fAF2069DEBB9513C815BB0264bE462C756d8c7d +uniswap_v3,0x4AF5A3ADb853290Bc9f909138FBf1a3C3fEB0868 +uniswap_v3,0x9B8d1D25Cc9aC5aA1BCbDBB1212cdE3446b8A63c +uniswap_v3,0xcfd3fD29eF1abf63e2863418Ee60Eaa563C509c8 +uniswap_v3,0x8ddAA74CDb4B70343B13299131eba31c665dff73 +uniswap_v3,0xF18700199235D05f849ccFDbc8f3acf9AddB93e3 +uniswap_v3,0xc2bd5534cEd2a29f24bC68010fa0716676E270b3 +uniswap_v3,0xDcaE5d7462d3dF3f301ACfaf52f6Bf4d94bFF322 +uniswap_v3,0x9A1cdA3Fa15323f22884Ce4a3058d20b016B747d +uniswap_v3,0x217861a86007234Ce0E71e17F804F23AB1F27178 +uniswap_v3,0xE61e660f035E1d7fd972c3BfF4f62fcCa1FF4F78 +uniswap_v3,0xDb164E978DC9F6f57CD1B3B144aA17a15bF5cDCe +uniswap_v3,0xb541bd4184B469D9B299ecE7792fEB36D0773851 +uniswap_v3,0xF6f27C5dAD30c21E5c2A2Fa000367411CF924Eda +uniswap_v3,0x096C6c392eDc94EDc4EE9b124829f136Ea7E8969 +uniswap_v3,0x85957d5De2C64C28f61943dCB4f8FaD368378703 +uniswap_v3,0xfDEFce10a7b51b68d78d645956Ec84CeF30829C6 +uniswap_v3,0x43210151d3A36F8e787068C72F1f0002AF5f252D +uniswap_v3,0xcA8fbcf6dC9247e4A088987eb330A4D621Af1F0d +uniswap_v3,0x4E2f1Ad6D24314341BE4ABcdACe4Ab0a9D8459C3 +uniswap_v3,0x1C8A2d2B010710445C767D6807CEe2Eb70B0dfE3 +uniswap_v3,0xEb49bfcE903cFae69fE67Ad434853b6Af170B7d4 +uniswap_v3,0xA635509Fd1fEc9143b62b2DA86Ca76f47B68e203 +uniswap_v3,0x70c8d6b7f65020921c770824CB99B3d5A3D936cc +uniswap_v3,0xa8fc2aD8699251dE25F356f5F58513580b09690E +uniswap_v3,0x33B6D3A3e4550319cA2f8E4082B70592530f6659 +uniswap_v3,0x4bcD348323cf169d33a9b5D3f96f9219cac901a0 +uniswap_v3,0x396657Ad8473652D4FFbdDF25DF80C1369695391 +uniswap_v3,0x0187C85D2b896b12f30f0B0470477658168d2162 +uniswap_v3,0x501B61233cFC5062734a1cA0c0AAdE77C308C2ea +uniswap_v3,0x85C1beBFFA2b6b2ccDd45be8c8cac3bdD6449122 +uniswap_v3,0x6A8b747018069e4f843112175822B770b4316784 +uniswap_v3,0x1Fd6B741d82C1bAbE6Fa78a07189Fe83F84cba9e +uniswap_v3,0x9CD9012204dD12ACC228A7E8e4093E148845669B +uniswap_v3,0x624248854defDd5340F8fF424Ca6FAeb914641e9 +uniswap_v3,0x90029Cd75D3252c7df892De61F32F9141036FDe3 +uniswap_v3,0x7e71043c835A9C1f0bDA5075347a6e3Fbb3657C5 +uniswap_v3,0x91A3D52b4a679d566C883E3866aF8617d97e2964 +uniswap_v3,0x5f95870D9a64589E8fE02E2C413CACb74d72d3df +uniswap_v3,0xF7D302EC3A173C7cb84FD14B54F4DCa2D4105560 +uniswap_v3,0xB1876AA65fBB26C01b96652539d21D0C61bDeeED +uniswap_v3,0x9a8178F5f064F7E659F86A779Ef0B500D351299D +uniswap_v3,0x9B7250EFd7bB9D83Cf7642AcdD6032Bd1893c9AD +uniswap_v3,0xc063baeA527BdBd077b0852fe6F271205e33C345 +uniswap_v3,0x7AF77fAbDcdA8455C1A519F4a41ba81C000e788e +uniswap_v3,0x865c10098417cf4397B715A65e9BDA638fFB76bb +uniswap_v3,0x8598a6320Ad9F1d18fCC4514773FDE8BCC10CD7f +uniswap_v3,0xE900D67f03BdFFD83E332d1034aC7224b5588a62 +uniswap_v3,0x9C892E0972046Be8eF907A007F355308FBcadaCb +uniswap_v3,0x619a54C37eb03367d665D34798E6A1007405bB68 +uniswap_v3,0x08e0E8f400B0F6BAF2AeCec9233Ee4BDBea3626C +uniswap_v3,0x6554a9E558f977fED1A2b714E8Eb7E97399cbd9A +uniswap_v3,0x4B1acBCC19BE8D950654c72A57D2c0F065Fe7c7B +uniswap_v3,0xAcD1C4eFe9cB52e65D0a92E5D9B45baf8Dc66B90 +uniswap_v3,0xC09Fb9feA177d88D8d3038Cb8C051480ecf33104 +uniswap_v3,0x052dB74B375F0956039946178C1021dc16b176d9 +uniswap_v3,0xEcad5281418b09Cca90757011D1A405dc34Eccc7 +uniswap_v3,0xF979054066EB1d6D613Bbb51Bf132a9cA473b652 +uniswap_v3,0x1E3Ae9A71a49F3b23eaDf90576b71493b48ECE82 +uniswap_v3,0x92a54A6Ba7a43e292E01b0515706CF0770C8CC11 +uniswap_v3,0xd86c77629C520d0fE621F20687E2c1878e0Ad071 +uniswap_v3,0xCC4bd51ff2Fd5aC7ADB1828bB4920Ff3DB1361f4 +uniswap_v3,0xEbC31c53eF72d163540Ac6a7e0B534961B97362e +uniswap_v3,0x2746db3fAd26DCd2721966Cb4603Aa75fF06d63a +uniswap_v3,0x5e4f27d20Db4f21429EDBa05f8C69E7003CBC5ee +uniswap_v3,0xD4762f19b329fC6BB1903D7A276b851E0b9743dB +uniswap_v3,0x9D7A1aC33e2A6F71712Dc62F11466a6B74f5C318 +uniswap_v3,0x623e43AD2DBe7B25B4630Eadb97254dae8747203 +uniswap_v3,0xAC87e969caCfd524E6eBC1b1F149fB8e2E0629d5 +uniswap_v3,0x0C6B2874657D32aa7D10DeB82cA495b626b632bb +uniswap_v3,0x76e1d01660328522027d640A146e71736617d633 +uniswap_v3,0x08a0a30bA2F2D0fe4FaBAB5A9B10566066771150 +uniswap_v3,0x1ce7478886CdF3655A5294a6a5a8927e2D1C46f4 +uniswap_v3,0x641d2bDd73cB2b5080dC2dB486c6D5cFB442340B +uniswap_v3,0x7C255C91bea9e75cf3328De7cc96d57B606F6ad6 +uniswap_v3,0x145a758Edc0d80A21E715285544f219d6760B2B5 +uniswap_v3,0x2a232B684dF03e8396f059fe3571D06cF3a73A41 +uniswap_v3,0xe25583Df29a40FF647cE1006Fe8f10ff9c6412eE +uniswap_v3,0x38AC51bc5237809b7883D6279B46424f0e9e5B54 +uniswap_v3,0x1726B0A74EBCc5f877af8e9151f662f7Aaab9C5a +uniswap_v3,0xc1583d6C9738b4d6B913755682a571746929fffB +uniswap_v3,0xbB0c0969891AB614649b7BabB82c8C793d761051 +uniswap_v3,0x674c3B1de47896a4468B2f9953849A2F8b3E05eE +uniswap_v3,0x298Fc66cF884a6114A8c023b2D6352b6fA55E50F +uniswap_v3,0x2E50502527a26dB2ea16E19CB2901140196DF1D6 +uniswap_v3,0x80fF523A33Be165Ef62d68b5a6911fE359699e59 +uniswap_v3,0x21EaAa412ccb9967FC9376A3FaB07e92Ce586640 +uniswap_v3,0xE131A69cF5FD74b83a595882A27933DCAAe9e6C8 +uniswap_v3,0x236149D4a269D75EEB9ccaA978b4D76714f79A8E +uniswap_v3,0x63cf7F592258a6a2184e364Eea7F621Df0E23509 +uniswap_v3,0x951a4B1429930fa8EA2B19b53028E24Eed420B8b +uniswap_v3,0x33212BC0d7c26869688Ac11d6Da78a451CcEe946 +uniswap_v3,0x6797ce53396bc2aFC0692d5c597218Dc5711C779 +uniswap_v3,0xBE579dbF8cFcfa8D2716bC679263CD0122daD840 +uniswap_v3,0xf60dea2cAb9feD06854218B16A7cDEDF003d541e +uniswap_v3,0x27c3FF7D90F7de72EC8549b3CD3F2187b56eba99 +uniswap_v3,0x6F86C37B5B73CD07D9f12c11b2568d37f25dF267 +uniswap_v3,0x8b7Ed0596C9c52e319fB13b2d3EB584131b3D39e +uniswap_v3,0x37B31EA693D1fC2137537D751514b01212433aD0 +uniswap_v3,0x1E4E6F6cF232BE9FA04ECC5018e939a628fD44FF +uniswap_v3,0x4828c2f71E5eE7965b9c5F7559A9D1901E7c1906 +uniswap_v3,0x0Ee2207e4E2B5F144Af755a33De9aC0329b532B0 +uniswap_v3,0x17c60Fa3fbb8DE05576cd92fDf74CF9e901eB4c7 +uniswap_v3,0x0D8f715fa533CE43f7f079e7fF62B7a5E744477E +uniswap_v3,0x3059b10F71ffeE8109Ff51D689EF9981F0248Ad1 +uniswap_v3,0xc58f038DacA4Fa9d4b5D2Aa9BAE5A5a24Ef4F771 +uniswap_v3,0x2462D4F8395171724ef56C96209924426F1ED813 +uniswap_v3,0x7d0ADa78873AA2Cb5Ac8B090cc6d7fCF9063A013 +uniswap_v3,0xb7dB50Be25d2bA2b359d687Bb12c11c71aBbe1B7 +uniswap_v3,0xaD2eAe38A513bBcFcd69CB34fd668563040497C9 +uniswap_v3,0x19E0C3d0092a60f0893D7F744F30Bd3Ccc40fb9c +uniswap_v3,0xf219f36D109f3Fbb40fE35390642b01C2bC8e398 +uniswap_v3,0x31Ff71b12c0C3753eCeE420e760Aa6e9c48d7EF1 +uniswap_v3,0x196581AbbC7141E9f7B2f1e1952d7ff41EA147F3 +uniswap_v3,0x66b935d92193cc786Aad7A23AebB0d60A08A9A3f +uniswap_v3,0x2B5C8450c702090cFB2CDeaa9aDa753f6a0Dfb62 +uniswap_v3,0x7232F4600379180d1D3b142172104c93Ca2e8E50 +uniswap_v3,0x092110b0b07bD8fcC9Cb33bF73A06930C0f91ac3 +uniswap_v3,0x1783ec23132Fa8DDb84b5Cf9cCc83BAFbc959690 +uniswap_v3,0xA071bEC46d800e774CC7a4A605cA25d7286601A0 +uniswap_v3,0x70bBB951DAf1C185c77216E2F2dC0d57Ea731567 +uniswap_v3,0xDf42d1354884358820064c3f6f3C37E20F6Fe1C4 +uniswap_v3,0x5038F9029eeaD091930D0eB759AEc864B4327cE0 +uniswap_v3,0x6971C303D468a89015D3aa5F7Cc20a75FE8E720E +uniswap_v3,0xbB608cf63ef7C8298dC88c28316d0B555CA8f61c +uniswap_v3,0x79661B68134491E675AB2A877A79f7B0D3c947DC +uniswap_v3,0x6b340a9F1c1aAd19895b91633aA2Ba3132eFd6E2 +uniswap_v3,0x8C9385ed733492d237908976b3b7de3038382c6E +uniswap_v3,0x6860A8951F8D1Ec505867088504ad1854E27ecA5 +uniswap_v3,0x5ec4D97B19de1ad28d5A5A2427C939D05A4B6e62 +uniswap_v3,0xb1EEe8ecB00f1c90c035e328C562F00A2e264175 +uniswap_v3,0x783d8704f28547b983f60F14Ab1510348D449fA0 +uniswap_v3,0xCD08E6DA36106051Ae32fd46Df7DF90659892122 +uniswap_v3,0x36f0CF505D73Be012C52a6D12197B73b653e8F1A +uniswap_v3,0x334D480F4399905C9F8170015Fbac284dCc17DC0 +uniswap_v3,0x99368F029A2F4621892eB4DfB14CB74B419467a3 +uniswap_v3,0xcB2602F349DABb341b05f0937cE73Ead57D94D91 +uniswap_v3,0x798AB49BcE97984a218Ca7De4B544B0bcd9261a6 +uniswap_v3,0x7Fc02200bb1442E591102743A504954021674262 +uniswap_v3,0x75f0E08597Ff64D571ccCbFa5aA55c4123bed570 +uniswap_v3,0xECf80b20c265A7e61b4DA7b0cE329C738f28c460 +uniswap_v3,0x4cc7f3c621bE55efc5C4629B7930664402643b3A +uniswap_v3,0xe0f56212F0EB39cAC537d4D4BA6aBF04f07DbC20 +uniswap_v3,0xD8d03E9E8082A5e0FcD70153d4384ea8a4f054eB +uniswap_v3,0x946CB8F8df43C48fff62B244f15148f34051Bf15 +uniswap_v3,0xB0fbaa5c7D28B33Ac18D9861D4909396c1B8029b +uniswap_v3,0xC684927860B00A768c14a0bf9F27b91Be1A9995E +uniswap_v3,0xcAB007c2534C751a9E92b4872C3E44354f167995 +uniswap_v3,0x183EDC80669137aA13d1f952402E36FFF66B464c +uniswap_v3,0x8387dBf39D06D5fF45b7fdF7f67146e9B7eAC25f +uniswap_v3,0x01306B8C65211321cc11699a5dffaf37DAc400e7 +uniswap_v3,0x2FbF37838E82fEc5fb3EF1d18439B770a27e3d50 +uniswap_v3,0xeB00349d28B2B3F7fc7d0182d1433fe5B4cB3425 +uniswap_v3,0x9dd7c4542e3562A52De5D7277febed6e20EaAdF4 +uniswap_v3,0xafC766DDE072c4D66DE1b7a0baD11255ebA97764 +uniswap_v3,0x56fAb3401f466117c709dcBAc722ee4f20971b2E +uniswap_v3,0x70b46dD48d261e6b5FaCF461c0dee107b76FBCC7 +uniswap_v3,0x27D0b1d11c7f8f42b90a0bAf9615f8Ad61d8902e +uniswap_v3,0xf310dbC5E850A82c7223D0575bC1732484091f92 +uniswap_v3,0x186Da94dbF1a4e217fb6f4946f8520f4f76050aA +uniswap_v3,0x2847924CC24FF51eEcE8A3D5c465b04803119016 +uniswap_v3,0x91c4dd0fB177A806Cf44eea78f05B2954c794D67 +uniswap_v3,0x016813dB2f1ce21C82c9D81688c5a146F6CC5381 +uniswap_v3,0x8559caf74DF6782ee3A3Facff3edb211DC7f8cc0 +uniswap_v3,0xaA1dCd58C6A886DFfD9C5DC6209eb8B24203c96D +uniswap_v3,0x07452AEb136deFa0319C62A3b25874F6d3178405 +uniswap_v3,0xcB9E3410924B9AcAcF09f0cD03235E0e5c8487C7 +uniswap_v3,0x7d58e8E9F1Ae17F9bE8c0F6fB9153d961eae859b +uniswap_v3,0xe4a432D8394060a9217155483B693aC1Cc6719C5 +uniswap_v3,0x7D8dac0834634107D391aB856623C3D2baD0760d +uniswap_v3,0x9a1E75e07752d03c550Ad3994F21Aa717A0cDc05 +uniswap_v3,0xE65E5Ae2BB0638EB882Ae38a2de1CB52399AaC45 +uniswap_v3,0xBdF182833ec03fEE3CB154bD7CaD6232Cc5fD651 +uniswap_v3,0x4Ec3Cb622b5c94184bc6bFf7914c555b5d74Cd43 +uniswap_v3,0x22fAfFA325707F7479F3A243e04e89Bf74734602 +uniswap_v3,0xF462BaF7306Ce420aa226eCd4c01C7f65eaFF7B8 +uniswap_v3,0xd41E87B2547D008DeFB0F2e07444d7941495104e +uniswap_v3,0xDe020187a1ab4A8c5F5f6B46A9C96d6c431c5076 +uniswap_v3,0xd41661846cD223ae043A1DF96F733031380B1113 +uniswap_v3,0x561B9A7C2E3655785bE91813560e0D39D68Bb0b6 +uniswap_v3,0x8432879904D45b1005B81d731AC32d280918Ec4B +uniswap_v3,0xE180e86fEdE43587743cc719875CD5e8b513a68b +uniswap_v3,0x6d45AB568cFCa75Aec6AB852B94EdD8015aF6Edc +uniswap_v3,0xB99C2C5AC1DD111278eA299Ee32Db61b496f70c7 +uniswap_v3,0x7e19682F8aAa60e8DB2Dd86B7042A682595BDCf4 +uniswap_v3,0xb2a8BeB6943F0b1fEC290d698912A212faD47DAF +uniswap_v3,0x4A6c553FF637626487BD5141D461cFCA6EaF06A2 +uniswap_v3,0x788D55ef7a6aA6f233D36BF8Bc9B51b8c6703255 +uniswap_v3,0xAE7aB7Be9c062633cd451681D4E2AFe064159a3e +uniswap_v3,0x7c65C994cd687CFD3e793623D9eD50E4E245CAbe +uniswap_v3,0xF74510D79C9b4e0EaC8Af07F2932064569683f7D +uniswap_v3,0x9CD06c0559b31188e247De6748dA61e9fEE06f88 +uniswap_v3,0x9Ae695Cb31C1b977422E05e54289899dF6177f5A +uniswap_v3,0x5aEdD07043bc9438BB1acba8F8B1Fa1F3AF7f971 +uniswap_v3,0x5325Dd7313eb32866bBdFA6EaA4312Fb89bbD8a1 +uniswap_v3,0x4A69A382CFeaCA49A10A673348c882dECc5222f5 +uniswap_v3,0x87118ec4efcf9b8202f8Be2C2bAE87b80920Fe68 +uniswap_v3,0x68c9325cC268dF8b9ED4A06429587f28471b5f84 +uniswap_v3,0x762171711f7D46EAd062853707f76FEE990881aF +uniswap_v3,0xdab2E5852daa87335D3BE842B458a6CEd7aB05B9 +uniswap_v3,0xA4404597Ef47BC5A10daeAcE9f170E20E1AA6bdC +uniswap_v3,0x39A79450f2cB3Da2375A8219493518e3059ffd10 +uniswap_v3,0x9F050D4224e03512810D31e5933E51A6E9bd93eC +uniswap_v3,0x56b8e21f0a8d76FD27732B56Ce90E73325eCf616 +uniswap_v3,0x573A55Ce1917E6c2ac44603a00f51c37dFD3Bb67 +uniswap_v3,0x23fab109AC229c0F227538dEb6dfA8375DD5ab58 +uniswap_v3,0x351C264A62D8d78Ca5e9C8a3e01985FcF3B63F3D +uniswap_v3,0xc630f5404043eAC4A8486C05C95326795Ef22202 +uniswap_v3,0x3c8961Cb820E48E96167cc4bd7687f1f47429843 +uniswap_v3,0x6889d1b2752bD875ad0bbDB94ed20eEEb371F51F +uniswap_v3,0xcf97aB0039A5C6137BA8f11ecF93737e919316eB +uniswap_v3,0x3069c25831C9309078971F2E1C310AcfdD0514c0 +uniswap_v3,0x4157fCBB2cF75cDf3f16A0e27728bcC0BE36c149 +uniswap_v3,0x317c459145Ebe1dB0005F1a2120256976020ef8E +uniswap_v3,0x5c891e543149F9473ea988D9ACf825D51b0Cfd4F +uniswap_v3,0xA678FE5D31708477c591db4e36D93FeeAbA89E1F +uniswap_v3,0xBE4152553240f5188ED115c6b8Bd667e8ce6a711 +uniswap_v3,0x7f24ee6e97b2AA837B3d50a5ba7Dc33c01FEa503 +uniswap_v3,0xe16e7a724250AD35BA2de4E599A8b618ECB5d6d7 +uniswap_v3,0x7477831319edE3293d10e68941dB767e33f83956 +uniswap_v3,0x4183fe8CBe172103396EE42b2694AdD372829CF9 +uniswap_v3,0x56593C03Bd79eCD0C7EAD9Ae1Af83568b5D77737 +uniswap_v3,0x5A5047b0dd72d5f3f2CE17D5ef57175330DdbD02 +uniswap_v3,0x0Df78f014Fa0daf2abb70bC720DF74b0aaaB02e9 +uniswap_v3,0xD34F72525fA5A75D9A376337E398624EBc8D847F +uniswap_v3,0x9FDD313D483F43ac68343bc9c49961fC48921AbB +uniswap_v3,0x70403FdD361F4F193AAc04313e185D2d1298b2AA +uniswap_v3,0x676172C834FA24FA85902F5a8BB3F5d162A59A84 +uniswap_v3,0x3f79e85B2fD7dd17a05727B4390E946a9D9a27d8 +uniswap_v3,0x3a41711844F4722658f1F8A000BA920e3988a0a1 +uniswap_v3,0x1cCB66fED28398281FE3f0e7c6808E031C3e63B1 +uniswap_v3,0x48a3f42Ea484443715E77149102c09C891c6c908 +uniswap_v3,0x49fA99e6E328C82B1f01099dBfBFA874A3adA640 +uniswap_v3,0x72135E2Fa5485deC33F9a55114939CD3400f39B6 +uniswap_v3,0x38F1A0f930B037AaCA703784f560B2a7bD0fbC21 +uniswap_v3,0x2aE3e113009E336F0244050dB24fb977202Aa023 +uniswap_v3,0xAb6BE376326F9F480996874A78B8cCb338bA348F +uniswap_v3,0x12EE86243DeA68883677bdF0e2DA568ab04d1637 +uniswap_v3,0xdC52f90310F560611bE0baaB85Ff304654F7c781 +uniswap_v3,0x1b1c7872c1C251771eC3eE53573d232344c8557b +uniswap_v3,0xd12B1Fac04C6E732F88615d2C957b2D02C5aB794 +uniswap_v3,0x8bA061bBEbef104C8b9A6b58761Ea58ff1ACF339 +uniswap_v3,0x0F102F876D8f4Fd59173CE27E21a1C259d0DAc26 +uniswap_v3,0xb7AcE6D17Ed156A4d2859F8F26b1C7D3d32888a6 +uniswap_v3,0xb120389b9593B766399A36989Cfa763A9D8f5452 +uniswap_v3,0x50A0d9fc516E4559E54B9A9d005de935DB6136cF +uniswap_v3,0x576D8dAa66A078c37A5b43355e10721970D9fA23 +uniswap_v3,0x3cC174DAC8549Ccc83C2c1f9b1CaD1b11211Ad5A +uniswap_v3,0x98992CbA85cD8739A7B6Cc69F31C21f84DA8CF93 +uniswap_v3,0x922C29868cD16fE1Df9ddc7Ca082559B71A158A2 +uniswap_v3,0xDE76BE20a17fe64faE659968210BDD3FCA086388 +uniswap_v3,0x9B8b7823F20E1e59e9618e2f1655803391C9f50C +uniswap_v3,0xFB0F8D41eD35C2664988475D60F6A089ff48c7F9 +uniswap_v3,0x615906ecF8352dF45139350CD2d3c9226D5aA6F2 +uniswap_v3,0x2CA5F6548C5baf7A8Db6a177567D606f6e01C530 +uniswap_v3,0xB50C2EaDc69B6924656D3bc05F60c8E8C9C3134A +uniswap_v3,0x13EC7A95fcbfac9E4a91d05F08E2cB2cE72f7ae1 +uniswap_v3,0x062418971f187cEFb4D0fC35543cAF0C09126C80 +uniswap_v3,0xc322E28DCFB832cFB495a2E973BD5f1E3Dbf0086 +uniswap_v3,0x976Dab857f2631aa092C43BE62385352D1e38121 +uniswap_v3,0x117Ed33349DA03686EAcdEE6Aad788a143E8c63c +uniswap_v3,0x5F005D1b2fd42FaC7Da9325f0dCD934b526C1fDa +uniswap_v3,0x637841E8d9232bd5A50f956F38B0f76394975229 +uniswap_v3,0x52967A86b7258cC52ff9E953266Cf735FA1E3df3 +uniswap_v3,0x44bD3A38cA44CeA669295c0fA98F56F0B42653d6 +uniswap_v3,0x090f3fD9110621df127c3F9bE5c6f58C02F2d5eb +uniswap_v3,0x1FE67796A2728018D0DfB64Cf89006cF9661019f +uniswap_v3,0x4F83A621a1BD19D7D13c0Dab560b3B408CB3c795 +uniswap_v3,0xB1FC8523A1E8396617a91Bf7e53B4ccEf366d637 +uniswap_v3,0xf0440A9493e3e69d36Dd772Ae273ee5aD5401E75 +uniswap_v3,0x490E01458BDdD1D6cF0BE869290Fb0E239E8bE9B +uniswap_v3,0x9B572dB8EFD5BE8Cd33C439a78D1BE6067bD053C +uniswap_v3,0xe15d177E27E2332173e3f05f3f5990cb9c880C05 +uniswap_v3,0xD99fe071b1F4f14d6c6c3b251B287A494A2Ec078 +uniswap_v3,0xec40da63B0A6407DD76AA10B8Bbd9462EEa6f224 +uniswap_v3,0x909e5D5b57e6FA8704D9A8D1195E1B8B706d66fc +uniswap_v3,0x6D34165d5Bfe8542E9530a536AC009Bb0115472c +uniswap_v3,0xF841D90166aad4319562bA106ff52Dd9E28C5239 +uniswap_v3,0x96f029C5c0254D7Ae093bA2FF02AcD260b83bFdC +uniswap_v3,0x09e53Ee6fe564F897D01CE7Ada2a9Bc830E33d39 +uniswap_v3,0x1332e8888C65706409D745A199A5cEB561d42C48 +uniswap_v3,0x5A8436D53dc1DDfA01c6F283D1d7FEFf0B19BaB6 +uniswap_v3,0x907e92450236639a6C5eD6D0caBe8EA54e619558 +uniswap_v3,0x23ab20Eb19cC25DB7B4c91190829C7628C0CAa48 +uniswap_v3,0x95facA00Db92AA6371933ef7E5e78ca21d453b7d +uniswap_v3,0x0aD4Fa97e0b1853Af5538a3E34687B9373B17645 +uniswap_v3,0x199a0032d624227b41a4265bE1Bcb8Be9A9bdbe3 +uniswap_v3,0x92F31AF3A6583bc1Eb9692585b3b285A15321832 +uniswap_v3,0x88617634339877faf179CdED1dA4ae6f904BFcF0 +uniswap_v3,0x3Dfe2478b17E5BB24A0022Dfe21DC9D1aF628428 +uniswap_v3,0xcd777577dbbf9f75142bb01d148FCA70efDeC960 +uniswap_v3,0x9c15F38CFBCb611FC8B3B3159D7993b16A69cFAC +uniswap_v3,0x3137F00399cB5c6C0e9c5d8C421FBdd88FfC6a7b +uniswap_v3,0x5B4d41AFE843Dcb567921A16e9c450F35837AAdB +uniswap_v3,0x6f4386817330C8E8748076cB730Cdd70A883AE22 +uniswap_v3,0x2D4ccaEA9D2Acac07cC4BCf42DE2ce3F143a9dCD +uniswap_v3,0x06AfF972D476BA6cD89e3De6eBd2c3F17d66aF9D +uniswap_v3,0x2E9fbC7b26397d2B7F8ce8034cfCD8264d197a98 +uniswap_v3,0xc96b2408AB0Ad2F04fb3a6A2B9de0B841b127698 +uniswap_v3,0xDcEBfb446a3c53aFDd6503FE65e350d94E9c06a6 +uniswap_v3,0xC8D7Bb02D3b1399fc557f73B91338674adA4a86a +uniswap_v3,0x7947D22776b70e356A33E03d90a402185AC97d60 +uniswap_v3,0x8CE8Bc67914679eDA3C282577a5083B299955B57 +uniswap_v3,0x7cD1B229a8183Ca8F0a2A1B50eDeC62f4a5aA289 +uniswap_v3,0x0B23118d768512249F5f213B03d17a8e14222f5E +uniswap_v3,0xA74c5535bE37e589E2BDef88A04423Dd12E13e5C +uniswap_v3,0x6A223512B807C53FB350dD4C091CD3fc1E12d9a2 +uniswap_v3,0x308189a54a3A62D15f87538cdbE6010Cf3dd47fA +uniswap_v3,0xDb450c004A72aA664E6fb0eC39dce3De074C4dC3 +uniswap_v3,0x083547F2d2A742089e97EC06C1E04F30c64E583c +uniswap_v3,0x003024DB4f5Ea13E366B1D63167975ceb7064940 +uniswap_v3,0x788F4E4319c540ed91e467CAD0B744Ad10e76373 +uniswap_v3,0x7FAa1464C6C3ca4D88d3b0eeC98A979d55C48116 +uniswap_v3,0x6e4E79cA5a22463A17006D4a09eD44B99c67A187 +uniswap_v3,0xE10E60c484B0caE7a65173a7955aEd9689404Ab5 +uniswap_v3,0xF01bBCE14522337533AE6E60eCE16f3325a5b48B +uniswap_v3,0xaCE41ED6a6E0FD6553f0e39A28a072BD31DCDadD +uniswap_v3,0x80af82aA13FD65548bb17Ca31aa3deCB6673192E +uniswap_v3,0xbD1a51924cF5CA66B43073eef1F9bCfd37D4fB07 +uniswap_v3,0xc506e9909ceF62a0cE27937925054DdcC23c1721 +uniswap_v3,0x99f51b76C96C0e6026c83975336035Ddd72E9b9c +uniswap_v3,0xe21d11dcBE27DC9a173A0c0cbbacc7DF87486Bc6 +uniswap_v3,0xbb501D57599f4E85749a45Bc91912Ab633B4264B +uniswap_v3,0x16fE9896DfAebC4a023e1e935a9350125beb3C39 +uniswap_v3,0x41e95aE41221a184F208B7714dDD68D954bB81F1 +uniswap_v3,0x6128480b44Fa5DBD57B8030A70Cbd4cA7aC3Db07 +uniswap_v3,0xC82cCc34585653698639001B41bA66aE050FF9C4 +uniswap_v3,0x6C93d2444cb12d7d9fA5E41d68Fe46962aeEc283 +uniswap_v3,0x8D4ba99f2990e1777b9b6d6aE5daBdf0F6Bd27ED +uniswap_v3,0x94A0f0cbe537D395DdfE4a578375a21aadd485d6 +uniswap_v3,0x38ae18CB099E65738ff69e71aFbF287ffAdA08dF +uniswap_v3,0x1dc8CED0734bFC8ccf02587dD8B02153456B0cb3 +uniswap_v3,0xC48de26894a7847b11732c757aBAD132F0Fc6dFB +uniswap_v3,0x8169E93E4044288607525466CBDEdAe8558A75D9 +uniswap_v3,0x62026826d6657EDF219274EA00Ef06D2a8cED742 +uniswap_v3,0xd430a57586bfbA94c0BF1652E194835110e07009 +uniswap_v3,0xbD91D73a0BD66A7b2C54855c4572A35283dFC136 +uniswap_v3,0xACb987687Cb8835F5Ff8370E579a4F6212B9C488 +uniswap_v3,0x1909110D81FD152EB66567F8Dfb36A65b3200A00 +uniswap_v3,0xEd3Fc0DbeA844Fe74F41Fa69C761EefcedFb22bF +uniswap_v3,0x86fcA9D8a25C146E76ab16FAA372a492fb0660C0 +uniswap_v3,0x88B7bea3a56e9bEf8128fE2eD8cA7011a7eBd096 +uniswap_v3,0xCF90e337317c3064E40B633a50Ba48A4258e8715 +uniswap_v3,0x93a50e149ba4fe3A7B87fD60DE9580590cFd6b0A +uniswap_v3,0x69D60c6ae6EB0C6c21C4eb969Db000B26fA56E7d +uniswap_v3,0x2C14e5eC3Ea61e8559a768b8182FC3341Dca6E7a +uniswap_v3,0x60Ca07ae70C5403220B4b6bf0ff6b0EFbCC72D6f +uniswap_v3,0xC66a2a50EF5fE1dE06C90C972ace7eB297dD803B +uniswap_v3,0xc708Bf52dB296B04526BD92600EC0F14d4Af4230 +uniswap_v3,0x14Ac7a30d2A6018fc0CD73DdCEAc841F33762230 +uniswap_v3,0x041eD2a5C4aF75D4354ce46B8eC311A460322e0c +uniswap_v3,0x321A4A71F136227E4c0653f9AD563f9a613121B9 +uniswap_v3,0x387C18a9Fa517Ab13F4D78238a208C4f2E100F1c +uniswap_v3,0xf44Fc9d08db8D7Cf2771E056edbB8126e8a3bD72 +uniswap_v3,0x30d61Bb28A6789f9f49D8c7fB198D63B6aba4B61 +uniswap_v3,0x3c2928ba8b162552468e5f6c439e25ee7cfA6C06 +uniswap_v3,0xCe628976857852F30DcbA3dDEaeab6BE18561565 +uniswap_v3,0x1F7ffBFA892F2c731E9314326c00Af57fb1200C0 +uniswap_v3,0xDaA5EB5Fb16fA80D2D7bd87DB81983567faDea51 +uniswap_v3,0x739281980089A10Ea7144AF73d18C921DA47D718 +uniswap_v3,0xd7FA6CD8268Ff80DcFe1762500BAbB0471be71DF +uniswap_v3,0x183D2Ff1838Ce96Dad13CeBD2E592E63eA424940 +uniswap_v3,0xB6320BCA2191915b76A3Aa8F6DbBee160Fc4A031 +uniswap_v3,0xC57C46b99da7Ad3e14a65479cc3D6Fb5245bBCc9 +uniswap_v3,0x856f0fC105C611d2FCe8255A694E7c824Dc8072b +uniswap_v3,0xBb997310749DA0b4E51A7DaA2b3da7AF7101f293 +uniswap_v3,0x5D77c81A06691f223bd4bf90C6Bb42f92116401F +uniswap_v3,0x40fC7CDa03139eBF7a0D3fC01F12B9D9a878Cc92 +uniswap_v3,0x773983ED1Df6155D5470d60380272AdF43E7F266 +uniswap_v3,0x5cAf02e2AC327685893aef1ED7d9495fDa9E6e8E +uniswap_v3,0x83446d99BC69f8f3611D3020fB89FB97f50c6F43 +uniswap_v3,0xd6948DFC62d7033C27F12DDAA6A9007F1728C90A +uniswap_v3,0x7FD7f4df348fAf9A9e49eDeB31c32B0bcAd99e0E +uniswap_v3,0x9d07472F35Cb348abAc8a2491CbAa002C0Abd5D1 +uniswap_v3,0x25576A726aF81afB141e97713eb59e38aadC482D +uniswap_v3,0xc9B4B0F7AF9edeAb42cc2fa933d58773C9Baa2a9 +uniswap_v3,0xb43E476620Fa569F0b3814F6F2648a12CeECb158 +uniswap_v3,0x22eF9D2DDD293A190F678eb4dB330E43C0CB5Cd2 +uniswap_v3,0x9394e2a6C61b4A901684dF59A2c982CaD1bc6dB7 +uniswap_v3,0x640c56d30ad38b86033C0e3ae5042C381693529b +uniswap_v3,0xAD762c29f6db47EA24215dcA861c1d375E33956B +uniswap_v3,0x199bc5db9170BA4a5a0C723015985F93ac477dce +uniswap_v3,0xeB8225805E440D7173545B0C059280b352F5833e +uniswap_v3,0xf5e999bd1f048b1a67d830b28BAEA9688a61A63F +uniswap_v3,0x4612e5b0DA22Be7930cCe997eB4899c59463baE3 +uniswap_v3,0xb8ced903ed1Bca2FDDc198737E05d589223a04cd +uniswap_v3,0xcc6Dc14db24a0663De326d2FdE735DB38998EcDa +uniswap_v3,0xA0203b2dEf3734B1d804a9AfE16762aB40B2e0c0 +uniswap_v3,0xD44D02531832CD4b4f6d41DE6f9A819743e4Eade +uniswap_v3,0xB5C93C917587a8a332fAD2ea406fAA436D1D36E8 +uniswap_v3,0x7DbeD5B6b387a7a5bDd0Ba48D97E05300a9A9441 +uniswap_v3,0x72e4ecfD293EB591eeCF14F37C78F98991CC62d1 +uniswap_v3,0xA3Aa8cb8f23dcf7fF5273da646E328184D96AE37 +uniswap_v3,0x3D2E49F4462a6800E11Bb8357444107d64aa81D7 +uniswap_v3,0xB28A19Afd827C1FD3BDf38A6EeC8F27101bCfE64 +uniswap_v3,0x3B722aa71EC13d4FbFde2B59FDf20Ec8396f76B1 +uniswap_v3,0x96AD8E0Be13C73b16dfae25d8131e0AB72c0Db0c +uniswap_v3,0x0665816c53e1D59FE28d946C555c8633F8f5DfF2 +uniswap_v3,0x663001eb6d286c0aC32AdEAb5955B96c82BeFfEb +uniswap_v3,0x47d90D6dE5bBeb31a4b4D10C632abAe9db55Bf56 +uniswap_v3,0xe183015334Bd7d7714A2a7C0c5f6bd08c9C395B4 +uniswap_v3,0x231b30568C1D942269B72614Dc780d9c9916c1D5 +uniswap_v3,0x9CFF8640A9f81D45BE9a6E92cFC30ED6158f0230 +uniswap_v3,0x38Fa3DaBc97b3292F0f9F967F35A68b02C3424b0 +uniswap_v3,0x5fEc3B81e4984010b5bf8Bd0CE28095Ef6F4F38c +uniswap_v3,0x5fEa85287887C3833ded251bbc4F39FF83f910E2 +uniswap_v3,0x8409a92f639ef0963aed2Bc6A8c0922E4293902b +uniswap_v3,0xc2983d931B14ceDf2F972dE73a9A6f8aDB370915 +uniswap_v3,0x94AB1B4E65B783b61534F5586d7F34E300Dd89dE +uniswap_v3,0x0b1d608e1246fdDF16d32aA9D47a93Af34046022 +uniswap_v3,0x43E9708D8E24A6B6EE41F97069115Fc87001d1ad +uniswap_v3,0xeDd181B4D99ad426470A5fdE8aDfdd93751E6314 +uniswap_v3,0x7c2D26723AF47F13E5F3Db2628225FCaA5a56C5d +uniswap_v3,0xe4a5a2A346d13aFfFc13b81C765C1c29396CBF46 +uniswap_v3,0x1c4Cb3c9225473d2EbddbF851F37B7346e50177D +uniswap_v3,0x106D74082383601aDefb8403FdEfC9919252f7e7 +uniswap_v3,0x0fD5DB45f157beCEb55BE128E985A7C59A720F2f +uniswap_v3,0xAcc7C93F843dE89Ba932Bc6F18490e7ed2021620 +uniswap_v3,0x7b3fd71706Dba1a481A61830aab77aD38f7ef746 +uniswap_v3,0x1c123A7C3C00073141bc75f86Ae49aE48561C73b +uniswap_v3,0xd03083401DE8279d1a20Dc4FBFCb59e8D7136EDe +uniswap_v3,0x9e06Dd1615bEdB2ea8E593A8ee26497d8c57d8D2 +uniswap_v3,0x498ECfac8e7ed1d79e137CADc47902011529a0E8 +uniswap_v3,0xC4b3DF389cf1C0DC0c01C68C6dDf675E3b1DE24E +uniswap_v3,0xF12521beF898cE6c42C948a9F2cb9E0007dFAC91 +uniswap_v3,0x1a9f4AB57946b590449f2f5c51C6927b1299310D +uniswap_v3,0x5060a9980694cd75349e2e876771d23a04AC2A49 +uniswap_v3,0xc8C8F538127cc79aC9550F6d70eCaD45aA3a3eD2 +uniswap_v3,0xDA1730bef829FA8aa9Cf90c323180CED61eFC53d +uniswap_v3,0x7FA97D9bD213100AC49b2d7229A1C11bA1430379 +uniswap_v3,0x59942cE5a1277Dcc91edB27D9b5Aaa7841eC9c62 +uniswap_v3,0x390A7Ec0B8513E3f81285274E4Cd1976827Cb191 +uniswap_v3,0x1514a3e1a720f4419c972960b8c72ea356099440 +uniswap_v3,0x828CD0Ea15887588A5e20B0F5081dB521423373d +uniswap_v3,0x99981592754fE4D536D0Ab122Ae1269C3E8f4135 +uniswap_v3,0x3234a2d681C568FfBc86F855f728474960E2C5aC +uniswap_v3,0x586334D68873b5d836cd55B6da3Bd7Aa50aC74cF +uniswap_v3,0x7490B5E63fBe6AbB13C806D1DCFb95320E4374c9 +uniswap_v3,0xb2aF2E8D2247B89a4E312e1D71DDd2952736d245 +uniswap_v3,0x3c1c5B95E8e00134208b50c4deB4a9aC0324d450 +uniswap_v3,0x8b0B953111F1A58C7935b96a87530963F30d2f16 +uniswap_v3,0x51227b128d00E9f4dd62b3E38C4697784e1aDE2c +uniswap_v3,0xc07Cdc30F9997f22Ab4Ec4D681Aa35E38e4902D4 +uniswap_v3,0x7A9b53EC68B4A74e5e38CBF5aB4893Bd68e4CC3a +uniswap_v3,0x8afC079569A577fD6F1AAdd9e3a93c41a387c364 +uniswap_v3,0x77f80b528e49D87113889466bAbB1b403D736288 +uniswap_v3,0x00D1eF7AaEC204Dc27c6e0C7794e41BA200B81dC +uniswap_v3,0x884914B85ACc8743da64734D2B27f54a86253234 +uniswap_v3,0x574Ad9123803B072a36f798CBDDb8A0574A6314E +uniswap_v3,0x1767EDe97625bFA245Bc70D4B4a74887219CacAF +uniswap_v3,0xDa42fBd44F1627804676f4061C5e2C65F3849281 +uniswap_v3,0x15AB08F80865E5427Bda8698E493A3becF05FE6b +uniswap_v3,0x88D826d66A1C54Bc8Ed84336710109a8c80dcDAA +uniswap_v3,0x6eA096FFc90F0fabCf101D780EdC8DA0C72Ac2d5 +uniswap_v3,0xCe4F50e65Cfc7235E75Babef9C168AeCcC6059F2 +uniswap_v3,0x97E85C3d9599914e0A710eC42E34dF9fb5818b40 +uniswap_v3,0x27ADaEBf192692c653f1e6090651383bEB0366aD +uniswap_v3,0xAb8bB59A136B5d4883DEdca532b3fFC713D387FF +uniswap_v3,0xE18E0d0362200E7349aa161160f8E25a38a7757f +uniswap_v3,0x6a39c10ef2EA283213f0825903a9a53a4F365ff3 +uniswap_v3,0x03d0ADf4f986DEac3e864ed85a7FB58794D4f496 +uniswap_v3,0xC038355052380071b7dccc48b506d1925EeaA4d6 +uniswap_v3,0x1d3D7e2d236b546247c5717d18F581C28F34792D +uniswap_v3,0x761b3a207356f8298a0ba81Ad6349004c9E60AEE +uniswap_v3,0xA76Bce435943be992C4B1D03404f21B6c1b7475f +uniswap_v3,0xe4F30F4b059f912CC324952BBB081237DB40a85f +uniswap_v3,0x365f8D0f99e2E4662cF0E6D891C18F3f74317952 +uniswap_v3,0xE1846C99256C7a690347303E15BA64aC0f13E5ce +uniswap_v3,0xd2d3E7ebA629C28bb071Fe204D86533BB0Ef75cf +uniswap_v3,0x3204063e12faD10fEeF33a01dFaB94159f613FbF +uniswap_v3,0x9aE8084c21752971D867597c07F2673765D949a1 +uniswap_v3,0xE1B41ef1D7b9886085D59b5fB87Af7fBC58d785C +uniswap_v3,0xb735E6416fA09354543E7121f2b32841E4921314 +uniswap_v3,0xE91C63278FBb3322A27888658591F1bF0A8b72D9 +uniswap_v3,0xf552841f59A37d691b69C8EF5B77BB77cD4E2dcC +uniswap_v3,0x35Ea4a7Dbc27fEf911A56a9265D433761b9e85A6 +uniswap_v3,0x74Aed2BBf12EaabD114228a3C7D1ff5fAf279D25 +uniswap_v3,0x43fae2884FCa681fE14AF8E350Fc6DE60730b1Bc +uniswap_v3,0x9120Da471155A93f9120547832E61aDfb13900e6 +uniswap_v3,0xC0114C7d7bB0CA7B1A8B031585F3c51df4fB53DD +uniswap_v3,0x296840cF4ECAA8beb1AddD3C7fc03b99D1952CCC +uniswap_v3,0xabed0D60Ba5f516d7B5e18935D83F3EE738719d3 +uniswap_v3,0x74A416f94Bfe8E4fAC006606a008a5450605790f +uniswap_v3,0x2dbe9d2D89188Ec871290927c6940769FD598425 +uniswap_v3,0xe7Ee403DBda5e626683Deca6B8F576c1Cfe75F11 +uniswap_v3,0x9d0B7Db1f54cD8A9B95CCcEAF8bdBf7f3c36c93A +uniswap_v3,0xa3A6125aa6469017352Fc504e9ae5B78A31579c4 +uniswap_v3,0x693f1E8048aEd2389fDc4CE6F2FE71eD65bf2095 +uniswap_v3,0xD107d4412172a9F0232Ce6C39281DCCc3F22E0CE +uniswap_v3,0x43375F7295E9e4B5051e52b96B8b6bFd53358E45 +uniswap_v3,0x0cF40Af54895b8C2C30b1bDBb7871757E0A39B93 +uniswap_v3,0x5f9f4a07E938AFbc9EBDD19BA4B7851446d6D53E +uniswap_v3,0xABBB876dD9B6C9A3587a9C452B5EF343d05c9c76 +uniswap_v3,0xc823EAfA867682667c8922A38693cda1f26aCA6F +uniswap_v3,0x7F38120B85223584b858A2Af65988347E6815646 +uniswap_v3,0xfBD99cb1155f644FfC9366e4446b6031AC24Bd23 +uniswap_v3,0x7CB22dE647fc9546eC6c2F238A10299Ab22Bfe59 +uniswap_v3,0x760F273108727c754Bf4a2f5A41C32878E1eE951 +uniswap_v3,0xE11956c2F0A6bCCca896a0710A978883B7170f62 +uniswap_v3,0x4847dA79CCC0Cc4Ac56D08CE1f34C749b03b47c9 +uniswap_v3,0x7Fc5D44A9aD029E0c78E96a36A89975688F29CA3 +uniswap_v3,0x1827D48591aa20934cE01e87E0a5335b55bB01B1 +uniswap_v3,0x7b3DF2a5D003A256b04e3cb11acF7132e6bB861B +uniswap_v3,0x161dbC1294fe9FeC931Ff34D2EC09b2409C8EE5D +uniswap_v3,0x6017933991a693D88754FE426b6A2ac77fbc35AF +uniswap_v3,0x06185F3B09a95a6EaC0d053E6c5ab122dCc4B260 +uniswap_v3,0x6B4264F2fd46f69e82a37A4e926715a7F24201C6 +uniswap_v3,0x32A8DA894947B67d4be554a5e91Fc92293Ab1e12 +uniswap_v3,0x34CE9B2c560C0e1b5Fa305699452d96CA238F65C +uniswap_v3,0xd7b7A5A3C21987Dc9170111D96575Cf5d97bDb55 +uniswap_v3,0x5aA583184fCBD355210F5579a205Af64d088Ab39 +uniswap_v3,0x06aB5216D969CEc5b5059376bb8C8999F7faAe39 +uniswap_v3,0x04570BDb5984b775Cc4a92B8cF052f7624fbf7c2 +uniswap_v3,0xcAC2987Bab0863aCc6E117f9f01854CC7290FF5D +uniswap_v3,0xBF89Ed1F68A73393d1F43CB739A6EE30BD93Cb30 +uniswap_v3,0xC77270aEAE2D2e986a5d7e5c5BD5e78bC0F43ACd +uniswap_v3,0x4Df59c6Abc9446Fd4DB592591F1205C36dC7d9E7 +uniswap_v3,0x73A71b0d202cA3c1ff2E4DE1539cA0923A2bBe79 +uniswap_v3,0xA8fE1c628C8B38D3fA90fD001E01C37b97ec333C +uniswap_v3,0xa9e6A14ed4891c478112CdeBc3e1C0A0029cF6DA +uniswap_v3,0x3Ec11ebF73DeEb69d4c09D18ea08B9bf6732C154 +uniswap_v3,0x9e92144aB2FEc4c9fe5A0a0C656Dac12555D2775 +uniswap_v3,0x1B883bad94a71855D353b61c5922Ce3AB4622c75 +uniswap_v3,0x77374d874e262657115462879DD8DD059abcF531 +uniswap_v3,0xC9604Bc06dE0BEC84BEab696C3eFe932504E4BA9 +uniswap_v3,0xCf622f09216Ef4834255F6CF02C087aef4323745 +uniswap_v3,0xF57326E3b9e86bFBC0dA65814DC4F8c0c9C473b2 +uniswap_v3,0xa9dFE04eAC59Da39B9fad30565Db6cD7dE864a79 +uniswap_v3,0x4cCD366293a6A948d9E230bC10f419d0835F19cF +uniswap_v3,0x75CBdcBb85F72543e41c7003d394D3ba657d4312 +uniswap_v3,0x66c7cF41bB27493Ed670917752990d9a45eD7612 +uniswap_v3,0x8AC5fF0CC45028ef36d637c475C0f261cCf2F4f0 +uniswap_v3,0xd7190Dc993b7e3984f1490b187586D6B51999063 +uniswap_v3,0xc4E681F7A1fCe04ddf7eDcD5E5964DAFA93A8A7B +uniswap_v3,0x3167Cc3f46bB81CACcD09e526037E2c3BbdD0294 +uniswap_v3,0x9e2c630a9F352EA0F152B2bf6A932A318c101b77 +uniswap_v3,0x0197c18A6041146678B68452611fE74B4a35d6F8 +uniswap_v3,0x26592bD76427641504593c7d97E505b80E1fDc68 +uniswap_v3,0x63Fd38BF3C264644B80aD3b9104CA22b93Ae636b +uniswap_v3,0xb6420bb8f4F0499b9e01658Bd5BA7fAC26cF0A57 +uniswap_v3,0x7d601c20fbAa0069c08B978a71B86C2f63e7C323 +uniswap_v3,0x3dceF3dacBA0Da074fF45694C5b58da665cE7129 +uniswap_v3,0x85ad29859fAf1E267259825eD2aa1c3522Aeb5Bb +uniswap_v3,0xB68707A16161511207aa7c19e6067501202163d4 +uniswap_v3,0x981f56B9A89cBFb72eFe8e609797CEbfc6703d82 +uniswap_v3,0x6655A4a0948D2d3c8DF0d7218045024E9b300f80 +uniswap_v3,0x4Fc75Ee535D3d3Ffe5bd5F8e8aAF2368d6931740 +uniswap_v3,0xF8887769F2C215858284759F99733ca7E998Ec63 +uniswap_v3,0xF98480B0A999432bcbF2f2041076b4A55ab5e315 +uniswap_v3,0x449bcFd119cC4769aEe0D202C9927c169644B715 +uniswap_v3,0x60789047A769B16BCdD3036eC0396d93909105b0 +uniswap_v3,0x87Ff708Ca97BA82Cd652620Fd0A9E2C29B5E5a22 +uniswap_v3,0xD8AaBC726613C08770A3f554E7d227C7422daFB0 +uniswap_v3,0x845482A18f86eF43EE51d8D1bd03de59f5E6262C +uniswap_v3,0xD7E39B23908F4658D791Af048C915A42d973eAa0 +uniswap_v3,0xd436C8804e2C3621e2B48d5E848393767F3cdE29 +uniswap_v3,0x4D5d67Ede3B3E82083211ebEf73c83516Cac33dc +uniswap_v3,0x028C8E58FEF26b92BfD5F7830BD626ec6eAD12Bb +uniswap_v3,0x6bcA101240AB2404fE25862488BBD547ff97F7DC +uniswap_v3,0x5e162C404c518010B420d325414A7715396DA075 +uniswap_v3,0x3212eEd120045cABED45b69Bc6f589399A53f9e8 +uniswap_v3,0x5D073b03A2B7262CA2ec868495769143Bd831830 +uniswap_v3,0xd24b0F1837A68495F6d6fb765b9F51cC11E314Df +uniswap_v3,0xe801B3282C218C320127c835480c1ECe285D1331 +uniswap_v3,0xB7E0977CEb6CBC6dEb41e45cb2594d29aAF138e1 +uniswap_v3,0x47baECce6D6b3c6d0FE58e45283374F90E4076B7 +uniswap_v3,0xe717780594614bB36F64B5c587576Eb80164DeC3 +uniswap_v3,0x65BA51C91a29678299B90b768737E277BEe219A7 +uniswap_v3,0x5aDdb0c9a709A375403538434d3a7643c759daEd +uniswap_v3,0xF1515b4D84dd4adF346382Bf090DB745f6AE45a7 +uniswap_v3,0xc2912E99645Ac9883FB7f9716e36B5C8D71240b1 +uniswap_v3,0x798F43c6c12163A8A475CeCE5F481D4c67dEDF19 +uniswap_v3,0x3f3E3354a1b54e4f47De2484f38a676ea19b2Bf3 +uniswap_v3,0x268E576999ef599202a4a4Cad9b915854151953E +uniswap_v3,0x44F9700d99bfF9785B5Ea29757a1F1Eb97FfB1DC +uniswap_v3,0x42e317B4fc52e90d99a7D9FF87e3B64EB0806132 +uniswap_v3,0x35FBC8E27261eCcBB4ed1b91021E0F317415fD10 +uniswap_v3,0x83cA2898a7A97cBAF4852aBF39857EAb43cC519B +uniswap_v3,0x8f5858B961D233175598B86DEeD57CBfc64A497c +uniswap_v3,0x81bdF969e3Ba2D49c400c8B1dfAa8b4309B246bf +uniswap_v3,0xF274CA6Bd898DAd4FF75eDfB16c51D76f9fF7Fe1 +uniswap_v3,0x3CA53Eba44fD5F10dc280dc0Ec97fCEe6ce850f0 +uniswap_v3,0x48837669E288366361ae9bBe63dB9004108648aA +uniswap_v3,0x2c193c0F7e78578d5CD8b488dB157C683FD6af18 +uniswap_v3,0x0B735B4DC52319aF3A4e14E357567D0F2153942E +uniswap_v3,0xeeeA3E464eEa483c0922C4E5377928Cb70b177a3 +uniswap_v3,0xFF81421e729B5Fe797885df1aB21A0693eD38bA0 +uniswap_v3,0x986627BD7d4690ae12910C40088Fe0Fe6db8A4de +uniswap_v3,0x537fe118aB1Cbf9378cf25ddd9CB4E2A52d14Cf8 +uniswap_v3,0xF9bEE7850ABb4045b20A89caf7233FbA67606b6e +uniswap_v3,0x054F4C73f2359D39f519CE846fec66ab84671F7e +uniswap_v3,0x888412eA5A6B7A9a417f2ba635e8adb4c370c145 +uniswap_v3,0x053879a49A8c3E758125FeF937B9Ea5e2F8D5751 +uniswap_v3,0x47FA443440fC5De1E4B60c7937AaD857a8b81E32 +uniswap_v3,0x3FF464afb3885C80A9577BdE11DdAC16f9918803 +uniswap_v3,0x490569Cc436b92055Dc6F87a3f5443eB2f1B900c +uniswap_v3,0x3D4A58e658C82f024dF6cA6290a9904Bb3BB4601 +uniswap_v3,0x1ee446EE412545CDF2CF1b532B84B6bAF5523185 +uniswap_v3,0xef93EBBB5EDcF0200C46200A79F55f20318CBd9C +uniswap_v3,0x285251EDf017860b3b2C50C714d9121E94aEA62C +uniswap_v3,0xAbf24505ee597cFD1361f97e0725147F829f28e6 +uniswap_v3,0x71FE8Fcd4dccdE5cECC6980E644B092c72780576 +uniswap_v3,0x1E99beD4F2BCD1842CC2eAF1Da449299b99Df638 +uniswap_v3,0x2d6143F451fd47fc3b97cd15c574168c3e989e55 +uniswap_v3,0x18A785Ca45C00af61afF483C711FC84E06390975 +uniswap_v3,0x5a03e9BB64FDDF08F487ED98C5fc276bd7c152bf +uniswap_v3,0x4B27C55DfA6237A5773Ae49ebB347A2f889bd6f6 +uniswap_v3,0xb48980875A709C26c3dD23067dE7852dDF2efE97 +uniswap_v3,0x1DfEeD65e092cD7B0Fc8FDF15B522ab3257D87b1 +uniswap_v3,0x31AAe92a1B668BBc190ac1e37772a7988a440f2E +uniswap_v3,0x27FbFa6F617B7F40F436C643AF153b527B0Af115 +uniswap_v3,0x57507312D07f3C1fAbF7952fd90e9d3FB1bd1374 +uniswap_v3,0xa4E5331d42319291202f3AE427EEAF7C025cAE91 +uniswap_v3,0x041bB62ce34F4f49e3298015BDD478E545a5C847 +uniswap_v3,0x4E4474ddf11854e8c8575cd2339b6394558D5484 +uniswap_v3,0x8CA8F81909DCB262EB53679319E3f0AE7D4A7b6f +uniswap_v3,0x6128d71bC6Fb40f397920e22d5BC204631BF0ed5 +uniswap_v3,0xADE24FC68F5aaA006b917173c8896e3A4F1e5DaD +uniswap_v3,0x1e9B08f69fa226485Df77fddEcA6995Cb3a4fb3D +uniswap_v3,0x2eEBe0422cc44811C2d27F9c43CFA35D5EEA785c +uniswap_v3,0xC70Ab94d861C4d803ab7a3af3dc1739b0602B01b +uniswap_v3,0x602e7A9AAb816F3e7102EfC4878FAA83A05086Fc +uniswap_v3,0xfbf033A57282bD923d2f1e13Bf04deb53871A56A +uniswap_v3,0x0659AB4aa456b61b534d270568306f985E8f106c +uniswap_v3,0x7bA497675d28B8dcF229140257C2a4c4579E7A42 +uniswap_v3,0x01046B39b600A9e4b1270933B6B59E1e456Da6E2 +uniswap_v3,0x7a048b5848c66cCaba3ACf50Eb38e360F0a63211 +uniswap_v3,0xC85AbA950E77F05943D6E47Ef2F24c1E247D2983 +uniswap_v3,0xc7062fcd3Cb6ce3D7dA5d1Ca713Ba9Ca9565E36d +uniswap_v3,0x8afA029cDb92569F19ee88042A909d79a7c75f88 +uniswap_v3,0x318eC2aEF8E8B5fCC7b98c3bB426A2a34c748EF1 +uniswap_v3,0x51fdb3C8415Fb87409Ff5D7C3f599d26a32CF740 +uniswap_v3,0xF62394Ae51f4dc773C3Fe208F5683BF0364a9fD1 +uniswap_v3,0x73811672aa57fbDA1E6BFF0B51c567B0aa22f34D +uniswap_v3,0x873C399f99Ed0cF19c8858DBC34B2f6A956dB755 +uniswap_v3,0x255fA7eC9264F83a76C833F1c9eCa4D493b146C4 +uniswap_v3,0x95574FAB05ABb685B8E885FA0642518F18abf09E +uniswap_v3,0xC886634AD71444fa89D9ff28A33707Bf4E569E95 +uniswap_v3,0x369A6EB55465d5474047b91449b47C6f1EC5CEbA +uniswap_v3,0x69C0674117a0f5a2D4F0db000b32B122C801618c +uniswap_v3,0xfB13E4a82A79CBB562d3F39B2568279Fa39a34dB +uniswap_v3,0x25eeF152BbFb1535EF88C8A39769F43d2b5Fa816 +uniswap_v3,0xf343b3d04828c232eEb93e83E78E3fA6fcF43e01 +uniswap_v3,0xCBE85d834FB2FcdD4453Db35c3fbd016EA50195E +uniswap_v3,0x606e5Da46617E6E7d61FCDb14F29477E9588a895 +uniswap_v3,0x175A4294f8D4992118D54F427DCCB68A40c53768 +uniswap_v3,0x155494e3250846aB4aD084B13B5020a17aC98aaC +uniswap_v3,0xac823A1779cF82b2E0A888879a29787a14E819d2 +uniswap_v3,0xFdCE167cd271801437f01F1FD796B0C6DdDe404d +uniswap_v3,0xDCe8d151E004b2c465A70c723CEFAdA6327c2d92 +uniswap_v3,0x794FeE340F57C0337575e01A8b6F2D6FaEa84DDC +uniswap_v3,0x80C3D9E2dd7497F32A8545Fe18458E1c05B622aC +uniswap_v3,0xDD69bbD7E5B3e12a52F47E63890686fD1489e616 +uniswap_v3,0xAF8B5cC6818DaCEC2E1c636F7C76Ee0a1A1E6057 +uniswap_v3,0xAca96D4Ad56dE5756FAF93046941E7eD66B1E80b +uniswap_v3,0xfea28169E91a9eb16DE11fA6F919f8317A59c010 +uniswap_v3,0x393C78a8Cf1F0740cdc3Def50F92201236DdCB62 +uniswap_v3,0x8C2b70ABc6E53F4D628f5594df5AaE1B2b84D7C7 +uniswap_v3,0x062618903596F6998B2f4fB311D4b56A5138194A +uniswap_v3,0x071A4FB6A15be9268E02B2374cD5B429dC7388D3 +uniswap_v3,0x85DBfe0050151Ea0f886201232D2aea249877Ad0 +uniswap_v3,0x3Da96163D4aa22300766e283346FEB41CA67d970 +uniswap_v3,0x1a2C7430C6658B9ce14aa4c3765aF8dabAa390c0 +uniswap_v3,0xb0c11511496441371154C3BF180a625f36fd4684 +uniswap_v3,0x7439a03B03909e5E167FA4cD4c1970c856e116A3 +uniswap_v3,0x488CD9047d6dcF3C1DfE2e580D4D2C199F434f2b +uniswap_v3,0x6793bdEBb8d556Dc91D137F99cCc8aF6b6628e5d +uniswap_v3,0x4122C18Ec60A4ea55A998F3E4B2Da8faa2AC7fe6 +uniswap_v3,0xF878c1be1e0D8D91DD957B0D0fE270f79439Dba7 +uniswap_v3,0x40431fd5B08f5b501dDcFE31c83D022F128e3FB7 +uniswap_v3,0x0258FdD7EDc69F8F79DD471ab8Ad6D0cF9E45A5b +uniswap_v3,0xCd5e833FCf58DD1eD2512315272471Af122B21EC +uniswap_v3,0xc8279B3a8aCbB83643a1E7aA4e55211Be90F0C3b +uniswap_v3,0xc98Ad03ea733A9082564A6bf0218fABe9bAD1560 +uniswap_v3,0xEFB35AC3965f46B5e6969E4bE10F2819b27103fF +uniswap_v3,0xA385737cf7C91df93b48B12Dea7f4B60c6a8F8CA +uniswap_v3,0x1108E8fD6d054a5AdC73387e035C2F5AacA9b799 +uniswap_v3,0x41B6846cA08Ef41A4d89E4fF82E362c0D73856Ba +uniswap_v3,0xD06e653085315C5d5A7A5Dcb5A8cF5c103174D9e +uniswap_v3,0x3FaE0C5eaad223484Cb417A03037b256c6D98A76 +uniswap_v3,0xc67f3397CEC4f145ca1aabD9bC42724B94931455 +uniswap_v3,0x3Af1de8989a16783034E0DC87d27AC028399A5E5 +uniswap_v3,0xb9a0D925E49CDCDA7b9D44c3b0F9898682cab71E +uniswap_v3,0x5b0655938f48DAD5f87Da245970031A57934eB62 +uniswap_v3,0xbFd07375340a17761a5e32919aE94701DB0d507e +uniswap_v3,0x4f758f3a3b419912fA977b5f9B023B138D579046 +uniswap_v3,0xD22eB692d8686e92EAAC145e91CfA7bb00F4f0d3 +uniswap_v3,0x1420F9E3c275822452aa5Ba63f224D5499f58001 +uniswap_v3,0xFD52E46EAA291bc226b7340293aa3E98D3a67840 +uniswap_v3,0x8e3FbA4f69D344A684f258fEc88bb84a2b48252a +uniswap_v3,0x2709e96186E88B0b3177e704Bf0319cBaD4e3592 +uniswap_v3,0xfD989E46a201c89DB9F96649572e8a1F100b1af3 +uniswap_v3,0xF390419Ab48c963fE310695fc2B2F51a234FeC61 +uniswap_v3,0xA246099686A6f433fC863009C763d6DB95602442 +uniswap_v3,0x27587eDB395Fe753fB55ACc0D3B99ea5cb653227 +uniswap_v3,0xE87CFcd89D0Df664Bfd0C04857d4e2C60020e6cD +uniswap_v3,0x3399e01383e6fAe9036fD363bbA64Bcf90e82b51 +uniswap_v3,0xF289fBEa43c809bAd27373dd6E1A1CA8a8148692 +uniswap_v3,0xc95976F5E9F45F3E25F85Bdcc0384Eaf2725DAD7 +uniswap_v3,0x2Ca096154e9A5F64EBd7DD95ee7266702822d27A +uniswap_v3,0xE5B445921A313330F4aCDe22cfdCC064b66F4066 +uniswap_v3,0x3b44F847D07fFa785CE3B785712942Cb70072e4c +uniswap_v3,0x21Ae3ADcb8D0778a4903e29248441BC30dCcc0AF +uniswap_v3,0x89b21E36A54A69bB68b77D9d8220636a55E6d745 +uniswap_v3,0x99a237c999d80100c416f595A5CDE2E77DBf56b1 +uniswap_v3,0x143d8Fc7AD7C1865f736788423323e672547e01b +uniswap_v3,0xb0594eA6D89dF4F5085aBF9F91dff7E23E70d88b +uniswap_v3,0x330bbF44E1DEf58CCd39bb257731fc32Dc9D2CdF +uniswap_v3,0xc75E7396a6B938E762640885fDE33f60fEB3E9BC +uniswap_v3,0xFfEC10fe1355c2d8df4F62AffCdEfFdB04f06569 +uniswap_v3,0x91e276996273F15BaF1a562a3B6477065c46a5D1 +uniswap_v3,0xC38236a403931A8b6a29Db6C4BdCf1559B756A91 +uniswap_v3,0x9EA84264B10Dcb032Ad0E62A09464973fd133afA +uniswap_v3,0x77ea3F0286BC6c4DC3803BbCA585FC1BBeDFbF38 +uniswap_v3,0xF7B5Be68caB9262D013d8A7C51E6A127fb06a8fA +uniswap_v3,0x8127BA07dB73de5c6F327F9E7d81c1AF11Df28c6 +uniswap_v3,0x0e6D06CF7174639BB133E8e9D1fa9189961c21af +uniswap_v3,0xE87ed1B461Fc539f97C9AC6a2953b4f0EA7f7c3d +uniswap_v3,0xaD5D637A010d2B8b37d8e8d825Ad1ee91cc6174A +uniswap_v3,0xD8D0fFF0599e9b4BaB9276E0CA964EB6a89c1E11 +uniswap_v3,0xdddefc3Eda6663Acd594D45231540176e675EA96 +uniswap_v3,0x36B3bCe466C1F8597f3BD7b376f091FFEd969647 +uniswap_v3,0xB64Fc50C4450eDbA5798614fe69f492F293988B1 +uniswap_v3,0x39106A3E5087EC6c30c1377233e02a44B96fF50F +uniswap_v3,0xd7e36ebEb6925157E68Ac0e96AD256Ae8D8d2Ff0 +uniswap_v3,0xc4b8F41039d322798d009Bd6AdCD4002A44bce57 +uniswap_v3,0xd9997C36E50fF1bDB09c1a63A00A7B0375b0e196 +uniswap_v3,0xe7c62b30624d4834CdC1f0cBc263f6049AB5b090 +uniswap_v3,0x39442607e10a7793c4da22Cf640B994dFE3001Db +uniswap_v3,0xF13220f14442A1b632A03A59C79b8D8A8b862c23 +uniswap_v3,0x8Dd59657c59CEDb06577F0fbCc4dbF725c0c0C24 +uniswap_v3,0xE2A5B5c900DAd9C2c57f8bdE56eb3626c2277Bc6 +uniswap_v3,0x6A045696cF8D1294F83ECE0D2fEc30FfBa2b5dbc +uniswap_v3,0x3883025F9b568D258B2d9dF5968f133152eD6115 +uniswap_v3,0x4979d6dbeBb215d7AAeBeb79353Cf113E954eF4C +uniswap_v3,0x2F4f7C17460C8941939f787dbd566919f41a623e +uniswap_v3,0x6b85399a9d4173D367211c8D199D6E7FDd68aC9f +uniswap_v3,0xE45a15D349d519F47AD43de73aEe0D61e4fA81b0 +uniswap_v3,0xECd617C4561cE69D76B1f05F4D6A7741d5369e32 +uniswap_v3,0x922f7b5499af470854D06Da4C144dB550B81Ac39 +uniswap_v3,0x73ed4f2f0158Ab815820d05C47a56eF76E5C3537 +uniswap_v3,0x0B57435E9Ef5F87F34f5931Ce4d7DD0A5D28c6d9 +uniswap_v3,0x3AD7BF9cd27d8e55bf7eF2527f1B00aa1d2A2b9b +uniswap_v3,0x667dD4a383707B9a3d79deA5A2794c8861D235D8 +uniswap_v3,0xe6db5d34Effcb6B53aA950b04f2b5fa0605FD300 +uniswap_v3,0x5eC562A1F4A1b0D5Fb7E7edC20E8A1f8CFa1dd95 +uniswap_v3,0xe067a9c17bc3cB4E8EC067E0D1cC5C83aAbde4A4 +uniswap_v3,0xD116e700bC2098DE60bfD9D15D9802FC5DEBF247 +uniswap_v3,0xF6DbbD87444174E25fFC9BA4f24d38eBf8ED4e41 +uniswap_v3,0x9Ef71A892574C26F69C66174dE4b412A52b74D14 +uniswap_v3,0xB4f23E3839b1315352f70155B1fBf1dFe89F802F +uniswap_v3,0x3928895b43A0A0EE5b5DE0a01b8b0478B4678ED4 +uniswap_v3,0x68192A9015869FE183FeA7FBAeb50b653e335872 +uniswap_v3,0x4ce7B7b4A3AdA3499392e82fD2bd8bf2259728F8 +uniswap_v3,0xC840A91eb7366C939674C60449a4CF7a28542Db9 +uniswap_v3,0xf51889092c21c169d9aCb40Eb8fC40Cf4EdE606F +uniswap_v3,0xf3c02A13C8415909FC3407Bb328F9939d2173549 +uniswap_v3,0xa2045949991D1808eCa6354e495E44B051D3f7fd +uniswap_v3,0x0AD8a455Bb1e27BBf3fE1bA1f4e14BCe40d5b3ad +uniswap_v3,0x2eDBB5F855740615e05EA4f70B24F5E535bca4b7 +uniswap_v3,0x68ae4e47eCD82298E28A4dfb105486ec944A64B4 +uniswap_v3,0xa1d8111fF253b2E690722a9B89c2Abc35e97Ded0 +uniswap_v3,0xacDA76aE653664bc386eCFE6C7218F0a4ebcd60B +uniswap_v3,0x927096707ffA01e78806d62688F55f38b9f4af26 +uniswap_v3,0xbccdCc8A0cd8ff44e745ad05A850586Fa5F7120D +uniswap_v3,0xEA8D1c922E30ba6D0409E3c927389b939207c942 +uniswap_v3,0x428d8942EB7709b869beFC7d44F42fCe43acd5Ce +uniswap_v3,0x1E232f31f62b515dE36C825eA055B68529a2890D +uniswap_v3,0x2565AdC1eE618DF14D92a999C7F155526d8eFc73 +uniswap_v3,0x180FB45AdBae01adBF3947b74b2D22d0daD3918a +uniswap_v3,0x116E7022871f9e225e622800fEF91b45e62f0685 +uniswap_v3,0x6473F2C341097693138a92FeC90f7117BB923367 +uniswap_v3,0xe9820bA963ec8BfD52Ec324BE7FF4BA32e4AF9ab +uniswap_v3,0x6e668dcafaaAB8e9dC9B8255FE125622230Fb9a6 +uniswap_v3,0xF718DaecB8EF3717F50388a71F44BD97a7Dd0462 +uniswap_v3,0x641401240B993F443EF22de1B0cC72F421439582 +uniswap_v3,0x6536c82C4350b1e23f013da42AD2cDD064071841 +uniswap_v3,0x99E9cBD77E43E865964284631b3ED9b535A7eCe1 +uniswap_v3,0xA6E057Fc14a44C3f427d11B2C0461cc090311679 +uniswap_v3,0x2aC27dc124f1599a241E16A7e7B1945f7E30572A +uniswap_v3,0xC81B79D82b7Fd37d5D187dd82Fe2dF8a854394bd +uniswap_v3,0x3978fD9D3b307e6F505194C0Ab28faA9857b183e +uniswap_v3,0xd48FbCc0492d95F1ffEB002489834610c253C069 +uniswap_v3,0x0af52953F8BDFbb9e56c1d144AA45915718b763a +uniswap_v3,0xEC9Feda966BbA819f6568675440824B47B234852 +uniswap_v3,0x0047416619a51afE9cd118D977A3649F492be923 +uniswap_v3,0x300d6362B86B58b8C0F34371089FD30f088E3a47 +uniswap_v3,0x90aF8A4Be28eFfcc27c1A69aF614186D5c8af16B +uniswap_v3,0x4C08D81cdadA3C7dB1147015F18e47EC439891C3 +uniswap_v3,0x4002cA421AA9001B43C3C5dde35cb9E5b476A14D +uniswap_v3,0xaAAdB7E7FB5985DCe4d42C4a2a50E6583cecCe87 +uniswap_v3,0x21f473c132fB5420EDfF6Ec71E4929C5dBd4231d +uniswap_v3,0x4b006174c70624b27d9879B5f3455611A36436dd +uniswap_v3,0xD5a649383dDA71282cdb7318a537B85f0994dCc6 +uniswap_v3,0xB0b5044287F9aaaF11d5363A15D43976A3E4e50C +uniswap_v3,0x1c2aA9c1E467517F95B51764c6e3Ef06C46fd8EB +uniswap_v3,0xb2D8aFD1c8d2D677095672B80104750c5a16074a +uniswap_v3,0x2eeE827E607ba2D2Fc649017E5b5Fd8a5d1F4945 +uniswap_v3,0x3b4EEdB7Dd66d63Ad320D4CA6055CD68B5268dEE +uniswap_v3,0x20dbCC4B8F30b023eabe2635B171c3dAE5Ef22e8 +uniswap_v3,0x8Ca9A6F457B69cBcEb346DB72B8d9722C118eCD3 +uniswap_v3,0xDCE84CBab8C8827408E92C6A79bC631F06f179fa +uniswap_v3,0x0D2837ccDfE86E78A938f78c20DD2754BB87faD1 +uniswap_v3,0x994B2D8e1a526892D3c84D799F040484092AddBC +uniswap_v3,0xf812B8b54Daeb45E1Fc896f9743d324D3dB30F5C +uniswap_v3,0x472d34F39E3448349F8CcF956D7c38d021f1b401 +uniswap_v3,0x72beEeBcD50Cc262ADF5E9a7ebfe6C51D662c02D +uniswap_v3,0x462c6DFe516914d8Cf26c5dCFcbA8372251810e5 +uniswap_v3,0x19786D706Aef023272d82AB2ec394019d100A145 +uniswap_v3,0x4E89281b68032b317C30cC84FD9fF08D733B8cd0 +uniswap_v3,0x96a11709eBae0Ea19494b6732b29BCab6738811F +uniswap_v3,0x3a88D78D5C775D6A972bdC111D15cfE83eDB3095 +uniswap_v3,0xb8c91CB8b1DFF426b6360527b6D684e7A38128ae +uniswap_v3,0x1C4d723F8aC449a9248E392dC7a1041F60a1c449 +uniswap_v3,0x5423CAC215898c005b2930e53881dD5E142a6be5 +uniswap_v3,0x20A925C67bCc4B08c8D283a27a2498bBF2BDf17E +uniswap_v3,0xE203906F83C8aDE3D53658e8b39694714c0802E2 +uniswap_v3,0x9AdC0B9dc0E2EfA811C8e85D6387b97E22fbe82e +uniswap_v3,0xd091dFc67d4b1D2a0f40823Fa3526824E9B8Dc5d +uniswap_v3,0xd75A39E19c3Af2b9eeA03c291A5c1f247403482C +uniswap_v3,0x99C954327a01455300d276567ae5B9C8DF966810 +uniswap_v3,0x1779A093fA10e569E64f4bA48A70397A5A50e589 +uniswap_v3,0x7a4cd01F03937A529199F5cA1DD7883b5dC68fB8 +uniswap_v3,0x6791CCAd57b0a31Cb071B078ba95c2eF5F701E04 +uniswap_v3,0x55c4D68922e341bBE40E3ab924Bee05C69fD68A8 +uniswap_v3,0xb25D805B3929fD6aEd9FF72780d985e20552c005 +uniswap_v3,0xbe098BfFa2E295D2Dc96896Db58662F7cb9747B2 +uniswap_v3,0xb902755a3a90Bf29Ea241f5F2FDB86DC1127c7bc +uniswap_v3,0xDf182D163cad217d78B05b19289b694c8E720e7C +uniswap_v3,0x81d9FbDbA53effDe62E981AE2304eB499364B59F +uniswap_v3,0xD4269a4dd6FA2285a2C448C4B6dB78275332c4B5 +uniswap_v3,0xfA2Bb0688aacd7865B6DBef2AED35D87800a1DDD +uniswap_v3,0xa82C8664b24FDFb74cA7E47E6A11d4640399414f +uniswap_v3,0xA9b8c620917178aeB85c912dEb7797590DEbA084 +uniswap_v3,0x81fbaBfF9FCD418E4D15B0b12f747Af8CB621bE9 +uniswap_v3,0xD62D6eF9bE2D1CeeaF7396B62fB2EC6fbF17440A +uniswap_v3,0xA954C6EE915941C7c7d773C0a1E20Bc584e31BE7 +uniswap_v3,0x709753C44eB210861f5dCC392715e60E26a2113e +uniswap_v3,0xCb0b332Ed71b269503199356b90525a5B1021434 +uniswap_v3,0x20513f6a316B4714Cf239acd820b88CdFc532c84 +uniswap_v3,0x49287eD1e5C456bC7C1FA742779E069e822495C6 +uniswap_v3,0x22861bA40bAb063fF24E796ccDE602944245f85c +uniswap_v3,0xE8D84a741D56d6ff45ab174D3CdA9af9F23aaaB3 +uniswap_v3,0xbD910F82A12ff1Dfa2565322CfFb4CCf896C51B7 +uniswap_v3,0x71896F870aebA742C778101b56b715Aba4E11Fe6 +uniswap_v3,0x93771cac40D3e0bbE18484550352667C7EE6732D +uniswap_v3,0x86fCA06B28396a10F75a446D72a254c273fD3f82 +uniswap_v3,0x18b668907172c773088a3881418Dc8c975557603 +uniswap_v3,0x94347f39D137Bb2CEF7a259f86c5828897835016 +uniswap_v3,0x9039549B07493581Deca4f8f4De12E89C39D56cD +uniswap_v3,0xf15eC1D8f13B208d420f257ebbd9D5e14c5a9433 +uniswap_v3,0x6bF2F3b3bbe496805c1a2236f5673Ba19Ddfd05E +uniswap_v3,0xD3a3288D61f8f1de036802cE7b17ca19d3cC66bb +uniswap_v3,0x2A3DA497Bc37CbEC585c36d6060f57aEBfB2Ec1d +uniswap_v3,0x26a1103623C2feF94358F9171d93645170C12f78 +uniswap_v3,0xB5c42F5659bf81CE0a7Ef955E268b3D7C7d285fF +uniswap_v3,0x4a39909c4dcB170F51313F5032BcAa417b7cCef8 +uniswap_v3,0x49109875eb77b4D847568651d476Be2D8aAAB359 +uniswap_v3,0x01fD7BcF6Ac63DE46Aa3f9dFcBd276a2183d4ADc +uniswap_v3,0x49c0Df3d99B6741f2154E769CcA1a1B86Db62489 +uniswap_v3,0x08D0f609fe8D05aafdb3e7CeEfdc6e3a2af792F5 +uniswap_v3,0xb2Fe6902899376A5639013c312c8Cb9272Deb31d +uniswap_v3,0x6470193120d6efEA17559a04e617cCc596793B46 +uniswap_v3,0xE18759f34fbA2A4547ce3947260642392c80F977 +uniswap_v3,0x15FA6098BD82E1985a15E5F95056920AcF1ef8b3 +uniswap_v3,0xb0f2F7E815f2a9c495FF27608df1677e1Fb2F582 +uniswap_v3,0xEB31A15e081ceAFe59Aa64999567BafBBA1e9b6a +uniswap_v3,0x92Cd4d5c4a6236758AA51aB642347cFC58FB393a +uniswap_v3,0x6Ee76C2f77195950ad214783cd105928f93156cb +uniswap_v3,0x1ecA1B81133D046d4a7DF6F45D76BbdE6bb0699C +uniswap_v3,0x26e3fec532c9b08D68D1C4DA9468bCF1ccA2D697 +uniswap_v3,0xc30716709f431bEfd2dd8f841afdFF1e4878edA5 +uniswap_v3,0x37E5119B9c4Bb50857981CdD8d3b87be935355A5 +uniswap_v3,0xa9334beF520779Ba6bEa987d9CA1e0140e82D25E +uniswap_v3,0x27C0021D7b867bFbC3ABfcF8b525458d8099fc35 +uniswap_v3,0x528FA6Ea67E7D1b4BA3000Eda840c90cb97A93Fd +uniswap_v3,0x9b8903B0B6882FE30DE2a30F6B73618D6eE960AD +uniswap_v3,0xD0D363064Df138F7714F135a815Bbf7577069953 +uniswap_v3,0x9Aa7CD82BF46d4790Fb18a1453956Cc10f06EFcd +uniswap_v3,0x3796e20B915A7663692B8A063Db86292b3e89767 +uniswap_v3,0x029a7d9072BCb7E5821167C373aa738B641b6638 +uniswap_v3,0x5AAcC13aBE5CA6f8D82EC5024e6fB6B6A77B9cC6 +uniswap_v3,0x9E3e307DE2445E459A450Eb219B9b1A9EFb6b2ec +uniswap_v3,0xF59e3d4405854EE54E62A576CFE71d93dc077549 +uniswap_v3,0x130940B41dEC48a1607FE5BF758990c1dD52EDEa +uniswap_v3,0x55EcD0D1fc82cC1F1688603F78aD6437E096101e +uniswap_v3,0x25a151dC4AF3b83f6D921758C87E253e164CC66c +uniswap_v3,0x006c0d9b9009a9Aa528C424Be15f106B29E95236 +uniswap_v3,0x9e695393216bEb8acA196fBCB51aD3b9d8217133 +uniswap_v3,0x4E71c3bC1E48CADe4F35f87eF223eE444a22e0B0 +uniswap_v3,0x2DC036BBfe9B7c314c5d20cBCb39a8287584574d +uniswap_v3,0x4bF5c396b826E75D9D286cc838374F56bE1E5f05 +uniswap_v3,0x552db460D58F4B031e9332aC350e0ff59A1D5687 +uniswap_v3,0xE0AC67ab5eafbaaE6544F0eC4f031d0b2299Ea92 +uniswap_v3,0x14a8B991F50eA5F165F1Ac4a7B726521d8167B87 +uniswap_v3,0x0936104E4575Db55C8A202b170cF5fe3558171cF +uniswap_v3,0x9ec6e275Bb64B4D89e9f2121b32b69De3a9435Fc +uniswap_v3,0xb268c5675EE74e9168F255Ec7f4ACA4BA02FDFAA +uniswap_v3,0xB74b58A74D964408eF45D19cb135773352615555 +uniswap_v3,0x062761C4Fe70c1f89ea0546fd299a133569A88e6 +uniswap_v3,0x7c244feAFffe00763152140aD0e3943FDfc6a088 +uniswap_v3,0xe76766d0e692AFeC6105733c4Ac552170F271785 +uniswap_v3,0xf07DdB59570f39eE6c77e82124e735363e6ADab8 +uniswap_v3,0xC84E17b0C029DEc1Cb4695956Eb61f0c46D1CEb2 +uniswap_v3,0x25F75ff0a5fC68115eeA2Ea9823B592c3828cF1f +uniswap_v3,0x86d4c639C369BDf2b56d3F5e15D4c6614c1C55Af +uniswap_v3,0x999dB70e82553A4602C929fa305B2A3952d4f046 +uniswap_v3,0x1988AF2ecE3E583af94fF70C159019DF7ba3b43d +uniswap_v3,0x80a363667bf53Ea96fB550691FDE390411f9B163 +uniswap_v3,0x1d4840E910Ff24fc4241c8b78867c9d9161Bc46C +uniswap_v3,0x57776b43B7f9106E053C23d3d89EFD57783a5DDc +uniswap_v3,0xef23E1eE9d945323701ea172DCB950010C7d394B +uniswap_v3,0xc09dde21d05c689Cd6fdD16ae206770e0993b7B9 +uniswap_v3,0x331bB064EF2Fa441ce546446d5e1249622ce11CA +uniswap_v3,0xeCB55B637e718F020dd80D6fe7839AE8E5e23711 +uniswap_v3,0xfeEd26eA7Cd94bAc96717067f61a4FfeBd127172 +uniswap_v3,0xc53165F07f65fEda7cA2b7D856A4CC95f0327d12 +uniswap_v3,0x24d194168FA8E62ae4e2641F26F6811FF6C4EfdA +uniswap_v3,0xc36B4E5ba909b4aFC5B71Cf88eaf4ED6a1bC9b4d +uniswap_v3,0xf1b7648F559355816E0320EEbD525F4f0C237D73 +uniswap_v3,0x2d7A876d5bb163183F0E3128B2f8b60d044CbfC9 +uniswap_v3,0x3793C099342f59e0566ab49830f7B52009c1873e +uniswap_v3,0xb7ce128e317E97f9d3AebE271b2DB2d7f46B70f1 +uniswap_v3,0xBaCBB26a11176498E0FE3230EA0C0A09Cc8C64f0 +uniswap_v3,0xe0A7b3b73F498e316Cd2007f84B17703CC20d0c3 +uniswap_v3,0xCCeDe5DF36277Bae218D295C6Cc063E637Ac1486 +uniswap_v3,0xb5b79d4607Fe1C39De8E9F4e725BCFbaC7CC5924 +uniswap_v3,0x23a4c43F7Ee6582e5BedbBea143494E72f144877 +uniswap_v3,0x4bAB0e1b701c3d447B571CE6C2E6537e3038E37E +uniswap_v3,0x18983a4208DB3e66FaEb74f84f2C7e95Bf66075e +uniswap_v3,0xeb5975BB17E76eAF99c6c824ff03144CEC817552 +uniswap_v3,0x8055e6de251e414e8393b20AdAb096AfB3cF8399 +uniswap_v3,0x339ba9D4753e31F55f52F67D3B051e8567270C44 +uniswap_v3,0x1dB430eEd29E5385Fc273D10E86b9BCBe52BDd4c +uniswap_v3,0xea8abCD7C22E0f31f29537eeAcf80BDEb6cBA384 +uniswap_v3,0xCe8897B4D2e7A6e9Cf0a7b015DA62B146d94bE72 +uniswap_v3,0x3043EEC0c8Aa33D6f5108Fc4672612a77470c20E +uniswap_v3,0xB28Ccff39B6cA4dd2c7c693DEF27B8153466db6e +uniswap_v3,0x33Ff43749c7f41C1252F3bb9b306DeC0C4701fc4 +uniswap_v3,0x32FD245795bb176659E0faEac09A65eF0F589f40 +uniswap_v3,0x9F058e360e6446500D690aF1FE75cD889c65cb02 +uniswap_v3,0x3d854EF84ecBd3D324D8D06830a8826a17838c56 +uniswap_v3,0x066f421c90a427f499E1069120C8fB2E8019d874 +uniswap_v3,0xa1CDACc16e62655EdcBea4EDD5682d68769D998b +uniswap_v3,0xdD35A4dAB2A0c411e5AB263B242B00bD4a135B23 +uniswap_v3,0x8eeB093b25226381E1c5A10e4A8bc9d239Dc49AF +uniswap_v3,0xB38f6f127EB86e5c14Ad506f465CBB35602D8859 +uniswap_v3,0x444836cD350F98477a885D81280559d97Ed9c6a5 +uniswap_v3,0xF236D9235D3A5376cd0310A17a7479e9812C9C5a +uniswap_v3,0x98BA928D946ee5Ae6323A33fD7D461fc0D6C19Cf +uniswap_v3,0x0eA41928A7c31396834f6e6Ba566715e6FC348e5 +uniswap_v3,0x78F4ef3DC93d6Df85daD99FC69FF514e5d5e9305 +uniswap_v3,0x8fc70B8302Ba18219235d299e32EDCD7A8B5aE70 +uniswap_v3,0xC70a931C5014a4B40B7F1A12ea20030BBDC176e5 +uniswap_v3,0x8876c96bb97a025110E08A79a684dFEAbb9F198b +uniswap_v3,0x2998d7394E3D63EaBd1F21F2476B260eaCFb439A +uniswap_v3,0xE5580fbeb25D945601190E41C99b1b027e40b241 +uniswap_v3,0x423DADF8D35BB805197aA70e1cDb82fb1aDC9AEA +uniswap_v3,0x16c6745b24F5c2080BbE6692eF8BaD90f53A1D75 +uniswap_v3,0xD013bC0064DF63988788C479c23899bc4B002D24 +uniswap_v3,0x461603EAF9E2F2150688ee66c67F2f719fBbAe91 +uniswap_v3,0xEC831fCC2Ba32b065d687ff144Ced0AA82Fae718 +uniswap_v3,0x5962e3A8DCB706e23398E790175c58E2964072DF +uniswap_v3,0xcc5669F7483B54c5b0dD6a97b4E5c867e998C664 +uniswap_v3,0x1B355d10C25A1Df3BFCCa9Af38b5C351bF677967 +uniswap_v3,0x495E84e34FC53922bA4dB00899a5A6939323B0b8 +uniswap_v3,0xCeDA0F9A38e9caB5ec15bb299a784eBFE58eE0E0 +uniswap_v3,0xC681d7394BbFc948b388B0601C924AA5557D2317 +uniswap_v3,0x302a4112d9c32D1282e6361e0b17CCBF66fE0dCD +uniswap_v3,0xFffBe4edD2c066D48140D35C3715307f7A1f55c2 +uniswap_v3,0x1eb3622a4dc578Ee3374d8F11F40fb6acecD96Dc +uniswap_v3,0xea0c164DC2ADb5e7DBA37E00FE80D16BEa4BA633 +uniswap_v3,0x3d3a2e615295d4838AbAF644B7DA85ef002A87E0 +uniswap_v3,0xB377364D2A8d330f5138E691E99258A01B53B71C +uniswap_v3,0x43CbE4247fF2Dc19B4c76649aCBade508f6Cc758 +uniswap_v3,0x192641E77A8c84623A73A03B5104bb5158E9518D +uniswap_v3,0x96B410bd280063D2b681cc4b363A2173CfbB452b +uniswap_v3,0x32BF775F157EB9Cf5E74F4a0B62aE4b2aE376a3A +uniswap_v3,0x8b2813fe7867eA52a93ADc6EA535662FF53257C1 +uniswap_v3,0x77a5dd003050bd9a5f786a6c2A1013Fe767B69B6 +uniswap_v3,0xB77968F7eF167E2741a048CC6D556A686f1d6DA6 +uniswap_v3,0x5aD48F58Fc36CaC4dad318eE72Ee0dc41C5Eb8Ad +uniswap_v3,0x174A678B04B7fE02Db66F7Bcff467a9f693CF266 +uniswap_v3,0x4Abc97949B13DA9fADa0273B4fC7F634aD0D2158 +uniswap_v3,0x35e36D4Fb9C65D220A7B563c6554D58e0151979E +uniswap_v3,0x429f93cD422117620CB7eDb99d6ed1eEfEc95877 +uniswap_v3,0x13B16817F115DEA194bCFF026d18503847c22032 +uniswap_v3,0x67E7CC5991453BAd2b7e02d16F24817947dEd0BF +uniswap_v3,0x4aE8d6FFC39C074e895a53723159C1f5Ef1b57Bf +uniswap_v3,0x45e86af08d0Dd5E04ef53E27432389c064852b51 +uniswap_v3,0x6ff5CfbBe53B68404A9B8d023B56C41cb7e7C78D +uniswap_v3,0xe18E640496800b49E92fD8cC6925650c5924A0d5 +uniswap_v3,0xC26F24Ba6c8132fEC335F92f6922581e2E8E1367 +uniswap_v3,0xD3F3A538CFcC42d0d042cC1c24EFE5dfB1B4cb29 +uniswap_v3,0x524B4b22d650053FC10c6F5d45C9BD4a30881F00 +uniswap_v3,0x2a990D0928e0016F83fD42f86732F8c9042a192f +uniswap_v3,0xe7c6A0CDfbf46CA1cd107A7c6c1f5D988FBa2996 +uniswap_v3,0x41CF577896646A623Af0eC4098c304fC184dB354 +uniswap_v3,0xC2D0Fb86DBb24658881f12E548bDF29BC5bA4Be2 +uniswap_v3,0x3848B674A732d53c24389A10ab7E087eF151F27A +uniswap_v3,0xa79E33b2F428f868d44aE26db99EC0154e68f5ae +uniswap_v3,0x748992cd77FF948439a5fE2c092f28cbCf625D11 +uniswap_v3,0x9c34a602e5E2876d4c1c87E92abe34a2Ec6cDd56 +uniswap_v3,0xB07E787A09855fc8350abfB04A3E218f6795c5cd +uniswap_v3,0x07b74776484743CF0C76618D37dFAfB7f7d4d7b2 +uniswap_v3,0xBBD1461423d3c78C72f8d28850993CE7047712eF +uniswap_v3,0xf8c1F3a53154f86C5b5c24c46548b4831981EB96 +uniswap_v3,0x1Db0f32f0C50343B58b3916E797dF612Db3df3BD +uniswap_v3,0x70bB61F15070409e3A5B3A258Fc49ed31FA03966 +uniswap_v3,0x9210a3cca359e0dF796678afF2238518cA88dd95 +uniswap_v3,0xFc19F7b0E322a997E2a9eC25CE36c75d7A6effc1 +uniswap_v3,0x00F822b2999c933d19A488317849705a12fE1B21 +uniswap_v3,0x123aAB2600483eD53bA42d708b9Ee0A6E4D05C21 +uniswap_v3,0xA83c4a992de829163cDd78dDFDd41e8184Fb3fb8 +uniswap_v3,0x32f431FE65b4cB7018F3c5Bc92D952B55c480604 +uniswap_v3,0x6dec47F7fA5F4B8D2AF3d46fda1df7F313903194 +uniswap_v3,0x413a4ee2E3a6b0B3DD40c12dDDF465F9cCB3271F +uniswap_v3,0xBAf1AD5f93EC077916683D5C26828D531528957a +uniswap_v3,0xEd800580ddC1817E12223D2Ac58dEcD257E5430c +uniswap_v3,0xd764fbdA43A0b4d1e23fda0Fd9A538Fb7e20582b +uniswap_v3,0x37f190ac2b6E709b3397Bd11A79ceE6A737c2a1E +uniswap_v3,0x0C4703e221166290F2FcD61e23694ab3892b0972 +uniswap_v3,0xdeC15dEE99B1a723AcC3fDd6Fa7b7f922D4c3D0f +uniswap_v3,0x16456E50ccefe406894DA030ef3A1e0b6dA7b3E6 +uniswap_v3,0x11a1b3f66380091e2268d114eE19da9323435E4A +uniswap_v3,0x38882c7D396d711bDdeB73dca1296332b1D90EDe +uniswap_v3,0x8F9D75A9bF27B32FE1A67949AeF13172D50a32a5 +uniswap_v3,0xd0a1d68b61D9c147f7438Df6AAaDCBA9199Aa51a +uniswap_v3,0x73036ff9215897E0C5E90a980F309A6FCb9f820C +uniswap_v3,0xBb0Eb8b3818df65799523256069fd0dbf5d36d68 +uniswap_v3,0x83fDE978990cd409085224c4a2f5E3540735bCb6 +uniswap_v3,0xD14AE3529C37A11DeD3B773E048Abd66D7fC4cAa +uniswap_v3,0xA28eCB862343cCbe85eC9d6C5A08dCFc0bF92B45 +uniswap_v3,0x1Ae8e97D5e5cDFB2a8cF43bf5c1dA473dd6BB75a +uniswap_v3,0xB12d16c8A623a741DBAC676407180d68CFAE0c20 +uniswap_v3,0xc9C50aB485eC3c4445D9119A226363bD5663742F +uniswap_v3,0x2D533b8920B5597A1b420C2095BEA02E223e6f3c +uniswap_v3,0x235a13E4F582832865b7525fADbe2993E62129A3 +uniswap_v3,0x678a9f28Fa506EfD220C182d0787185b578b752a +uniswap_v3,0x540282B014bDDC7c93f2Ed5aB0e58963875d63E0 +uniswap_v3,0x5C22c0Aeb18c0B3E86794DE8734BB3627521F303 +uniswap_v3,0xD991CC798c3e5684aC4Aa8Ec1Dbf43fa28290557 +uniswap_v3,0xa74F821f336eedCE2395913846e2E99C90819E32 +uniswap_v3,0x5977C38FD0990E62eDF91B40Fa9Ff3e65912d576 From cb7b549714bac72ae3698590ce780ea80df07ea4 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Mon, 6 May 2024 11:40:15 +0300 Subject: [PATCH 029/131] Fix test 072 --- fastlane_bot/tests/test_072_TestTerraformer.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/fastlane_bot/tests/test_072_TestTerraformer.py b/fastlane_bot/tests/test_072_TestTerraformer.py index 8c151b811..b4a6d5db4 100644 --- a/fastlane_bot/tests/test_072_TestTerraformer.py +++ b/fastlane_bot/tests/test_072_TestTerraformer.py @@ -102,15 +102,9 @@ def test_organize_pool_details_balancer_strategy_id(): ], "swapFee": "0.003" } - token_prices = { - "0x456": {"usd": "1"}, - "0x789": {"usd": "2"} - } - web3 = MagicMock() - web3.to_checksum_address.side_effect = lambda x: x # Mock checksum address to return the same value # Call the function - pool_info = organize_pool_details_balancer(pool_data, token_prices, web3) + pool_info = organize_pool_details_balancer(pool_data) # Check the 'strategy_id' in the output assert "strategy_id" in pool_info From d36864a844be409d786b71cd1cde5af8debcac11 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Mon, 6 May 2024 11:57:58 +0300 Subject: [PATCH 030/131] Fix test 072 --- fastlane_bot/tests/test_072_TestTerraformer.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fastlane_bot/tests/test_072_TestTerraformer.py b/fastlane_bot/tests/test_072_TestTerraformer.py index b4a6d5db4..95e345e18 100644 --- a/fastlane_bot/tests/test_072_TestTerraformer.py +++ b/fastlane_bot/tests/test_072_TestTerraformer.py @@ -103,6 +103,9 @@ def test_organize_pool_details_balancer_strategy_id(): "swapFee": "0.003" } + web3 = MagicMock() + web3.to_checksum_address.side_effect = lambda x: x # Mock checksum address to return the same value + # Call the function pool_info = organize_pool_details_balancer(pool_data) From add03596f66e8fcaa61f7ddc85426ab5ff2af4e6 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Mon, 6 May 2024 15:30:19 +0300 Subject: [PATCH 031/131] Fix test 072 --- .../tests/test_072_TestTerraformer.py | 70 +++++++++---------- 1 file changed, 33 insertions(+), 37 deletions(-) diff --git a/fastlane_bot/tests/test_072_TestTerraformer.py b/fastlane_bot/tests/test_072_TestTerraformer.py index 95e345e18..fbc8eb016 100644 --- a/fastlane_bot/tests/test_072_TestTerraformer.py +++ b/fastlane_bot/tests/test_072_TestTerraformer.py @@ -4,31 +4,33 @@ ''' from unittest.mock import MagicMock, AsyncMock -from run_blockchain_terraformer import organize_pool_details_balancer, organize_pool_details_uni_v2, organize_pool_details_solidly_v2, organize_pool_details_uni_v3 +import run_blockchain_terraformer as terraformer +ADDRESS_1 = "0x".ljust(42, "1") +ADDRESS_2 = "0x".ljust(42, "2") +ADDRESS_3 = "0x".ljust(42, "3") def test_organize_pool_details_uni_v2_strategy_id(): # Mock the input parameters pool_data = { "args": { - "pair": "0x123", - "token0": "0x456", - "token1": "0x789" + "pair": ADDRESS_1, + "token0": ADDRESS_2, + "token1": ADDRESS_3 }, "blockNumber": 123456 } token_manager = MagicMock() - exchange = "test_exchange" + exchange = terraformer.UNISWAP_V2_NAME default_fee = "0.3" web3 = MagicMock() - web3.to_checksum_address.return_value = "0x123" - # Process the function - result = organize_pool_details_uni_v2( + # Call the tested function + result = terraformer.organize_pool_details_uni_v2( pool_data, token_manager, exchange, default_fee, web3 ) - # Check if the result contains 'strategy_id' with value 0 + # Assert that the output 'strategy_id' is 0 assert "strategy_id" in result assert result["strategy_id"] == 0 @@ -36,25 +38,24 @@ def test_organize_pool_details_uni_v3_strategy_id(): # Mock the input parameters pool_data = { "args": { - "pool": "0x123", - "token0": "0x456", - "token1": "0x789", + "pool": ADDRESS_1, + "token0": ADDRESS_2, + "token1": ADDRESS_3, "tickSpacing": 10, "fee": "3000" }, "blockNumber": 123456 } token_manager = MagicMock() - exchange = "test_exchange" + exchange = terraformer.UNISWAP_V3_NAME web3 = MagicMock() - web3.to_checksum_address.return_value = "0x123" - # Call the function with the mock objects - pool_info = organize_pool_details_uni_v3( + # Call the tested function + pool_info = terraformer.organize_pool_details_uni_v3( pool_data, token_manager, exchange, web3 ) - # Assert the 'strategy_id' in the output is 0 + # Assert that the output 'strategy_id' is 0 assert "strategy_id" in pool_info assert pool_info["strategy_id"] == 0 @@ -62,30 +63,28 @@ def test_organize_pool_details_solidly_v2_strategy_id(): # Mock the input parameters pool_data = { "args": { - "pair": "0x123", - "token0": "0x456", - "token1": "0x789", + "pair": ADDRESS_1, + "token0": ADDRESS_2, + "token1": ADDRESS_3, "stable": True }, "blockNumber": 123456 } token_manager = MagicMock() - exchange = "test_exchange" + exchange = terraformer.SOLIDLY_V2_NAME exchange_object = MagicMock() exchange_object.get_abi.return_value = "test_abi" exchange_object.get_fee = AsyncMock(return_value=("0.3", 0.3)) web3 = MagicMock() - web3.to_checksum_address.return_value = "0x123" async_web3 = MagicMock() async_web3.eth.contract.return_value = AsyncMock() - # Run the coroutine with asyncio.run (Python 3.7+) - pool_info = organize_pool_details_solidly_v2( - pool_data, token_manager, exchange, exchange_object, web3, async_web3 - ) - + # Call the tested function + pool_info = terraformer.organize_pool_details_solidly_v2( + pool_data, token_manager, exchange, exchange_object, web3, async_web3 + ) - # Check if the result contains 'strategy_id' with value 0 + # Assert that the output 'strategy_id' is 0 assert "strategy_id" in pool_info assert pool_info["strategy_id"] == 0 @@ -95,20 +94,17 @@ def test_organize_pool_details_balancer_strategy_id(): "swapEnabled": True, "id": "pool123", "poolType": "type1", - "address": "0x123", + "address": ADDRESS_1, "tokens": [ - {"address": "0x456", "symbol": "TKN1", "decimals": 18, "weight": 0.5}, - {"address": "0x789", "symbol": "TKN2", "decimals": 18, "weight": 0.5} + {"address": ADDRESS_2, "symbol": "TKN1", "decimals": 18, "weight": 0.5}, + {"address": ADDRESS_3, "symbol": "TKN2", "decimals": 18, "weight": 0.5} ], "swapFee": "0.003" } - web3 = MagicMock() - web3.to_checksum_address.side_effect = lambda x: x # Mock checksum address to return the same value - - # Call the function - pool_info = organize_pool_details_balancer(pool_data) + # Call the tested function + pool_info = terraformer.organize_pool_details_balancer(pool_data) - # Check the 'strategy_id' in the output + # Assert that the output 'strategy_id' is 0 assert "strategy_id" in pool_info assert pool_info["strategy_id"] == 0 \ No newline at end of file From 41989eb0accc425db2b0d19747e207dd56b6462a Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Tue, 7 May 2024 15:34:21 +0300 Subject: [PATCH 032/131] Fix function `async_update_pools_from_contracts` --- .../events/async_event_update_utils.py | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/fastlane_bot/events/async_event_update_utils.py b/fastlane_bot/events/async_event_update_utils.py index 19a898eb5..bbfa99273 100644 --- a/fastlane_bot/events/async_event_update_utils.py +++ b/fastlane_bot/events/async_event_update_utils.py @@ -442,22 +442,26 @@ def async_update_pools_from_contracts(mgr: Any, current_block: int): duplicate_new_pool_ct = len(duplicate_cid_rows) - all_pools_df = ( - pd.DataFrame(mgr.pool_data) - .sort_values("last_updated_block", ascending=False) - .drop_duplicates(subset=["cid"]) - .set_index("cid") - ) + if len(mgr.pool_data) > 0: + all_pools_df = ( + pd.DataFrame(mgr.pool_data) + .sort_values("last_updated_block", ascending=False) + .drop_duplicates(subset=["cid"]) + .set_index("cid") + ) - new_pool_data_df = new_pool_data_df[all_pools_df.columns] + new_pool_data_df = new_pool_data_df[all_pools_df.columns] - # add new_pool_data to pool_data, ensuring no duplicates - all_pools_df.update(new_pool_data_df, overwrite=True) + # add new_pool_data to pool_data, ensuring no duplicates + all_pools_df.update(new_pool_data_df, overwrite=True) + + new_pool_data_df = new_pool_data_df[ + ~new_pool_data_df.index.isin(all_pools_df.index) + ] + all_pools_df = pd.concat([all_pools_df, new_pool_data_df]) + else: + all_pools_df = new_pool_data_df - new_pool_data_df = new_pool_data_df[ - ~new_pool_data_df.index.isin(all_pools_df.index) - ] - all_pools_df = pd.concat([all_pools_df, new_pool_data_df]) all_pools_df[["tkn0_decimals", "tkn1_decimals"]] = ( all_pools_df[["tkn0_decimals", "tkn1_decimals"]].fillna(0).astype(int) ) From 666b549a85cb0e32074e03273271a43c2ca4eccc Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Thu, 9 May 2024 22:51:35 +0300 Subject: [PATCH 033/131] Move from `Multicall2.aggregate` to `Multicall3.tryAggregate` --- fastlane_bot/config/multicaller.py | 8 ++------ fastlane_bot/data/abi.py | 6 +++--- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/fastlane_bot/config/multicaller.py b/fastlane_bot/config/multicaller.py index 9687db79c..bb68322da 100644 --- a/fastlane_bot/config/multicaller.py +++ b/fastlane_bot/config/multicaller.py @@ -157,15 +157,11 @@ def multicall(self) -> List[Any]: encoded_data = self.web3.eth.contract( abi=MULTICALL_ABI, address=self.MULTICALL_CONTRACT_ADDRESS - ).functions.aggregate(calls_for_aggregate).call(block_identifier=self.block_identifier) + ).functions.tryAggregate(True, calls_for_aggregate).call(block_identifier=self.block_identifier) - if not isinstance(encoded_data, list): - raise TypeError(f"Expected encoded_data to be a list, got {type(encoded_data)} instead.") - - encoded_data = encoded_data[1] decoded_data_list = [] for output_types, encoded_output in zip(output_types_list, encoded_data): - decoded_data = decode(output_types, encoded_output) + decoded_data = decode(output_types, encoded_output[1]) decoded_data_list.append(decoded_data) return_data = [i[0] for i in decoded_data_list if len(i) == 1] diff --git a/fastlane_bot/data/abi.py b/fastlane_bot/data/abi.py index 4d0d9f788..ec6f102f4 100644 --- a/fastlane_bot/data/abi.py +++ b/fastlane_bot/data/abi.py @@ -676,10 +676,10 @@ MULTICALL_ABI = [ { "type": "function", - "name": "aggregate", + "name": "tryAggregate", "stateMutability": "view", - "inputs": [{"components": [{"internalType": "address", "name": "target", "type": "address"}, {"internalType": "bytes", "name": "callData", "type": "bytes"}], "internalType": "struct Multicall2.Call[]", "name": "calls", "type": "tuple[]"}], - "outputs": [{"internalType": "uint256", "name": "blockNumber", "type": "uint256"}, {"internalType": "bytes[]", "name": "returnData", "type": "bytes[]"}] + "inputs": [{"internalType": "bool", "name": "requireSuccess", "type": "bool"}, {"components": [{"internalType": "address", "name": "target", "type": "address"}, {"internalType": "bytes", "name": "callData", "type": "bytes"}], "internalType": "struct Multicall3.Call[]", "name": "calls", "type": "tuple[]"}], + "outputs": [{"components": [{"internalType": "bool", "name": "success", "type": "bool"}, {"internalType": "bytes", "name": "returnData", "type": "bytes"}], "internalType": "struct Multicall3.Result[]", "name": "returnData", "type": "tuple[]"}] } ] From 2743d33f7b256720767d39e479e33d5aeee5b963 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Thu, 9 May 2024 23:12:05 +0300 Subject: [PATCH 034/131] Refactor --- fastlane_bot/config/multicaller.py | 12 ---- fastlane_bot/events/managers/base.py | 37 ++++++------ fastlane_bot/events/multicall_utils.py | 78 ++++++++------------------ 3 files changed, 38 insertions(+), 89 deletions(-) diff --git a/fastlane_bot/config/multicaller.py b/fastlane_bot/config/multicaller.py index bb68322da..6cbd7bd4d 100644 --- a/fastlane_bot/config/multicaller.py +++ b/fastlane_bot/config/multicaller.py @@ -167,16 +167,4 @@ def multicall(self) -> List[Any]: return_data = [i[0] for i in decoded_data_list if len(i) == 1] return_data += [i[1] for i in decoded_data_list if len(i) > 1] - # Handling for Bancor POL - combine results into a Tuple - if "tokenPrice" in _calls_for_aggregate and "amountAvailableForTrading" in _calls_for_aggregate: - new_return = [] - returned_items = int(len(return_data)) - total_pools = int(returned_items / 2) - assert returned_items % 2 == 0, f"[multicaller.py multicall] non-even number of returned calls for Bancor POL {returned_items}" - total_pools = int(total_pools) - - for idx in range(total_pools): - new_return.append((return_data[idx][0], return_data[idx][1], return_data[idx + total_pools])) - return_data = new_return - return return_data diff --git a/fastlane_bot/events/managers/base.py b/fastlane_bot/events/managers/base.py index b76a2d592..eee06bc66 100644 --- a/fastlane_bot/events/managers/base.py +++ b/fastlane_bot/events/managers/base.py @@ -552,22 +552,18 @@ def get_strats_by_contract( web3=self.web3 ) - with multicaller as mc: - for pair in pairs: - try: - # Loading the strategies for each pair without executing the calls yet - mc.add_call( - carbon_controller.functions.strategiesByPair, - pair[0], - pair[1], - pair[2], - pair[3], - ) - except ValueError: - print(f"Error fetching strategiesByPair {pair}") - - # Fetch strategies for each pair from the CarbonController contract object - strategies_by_pair = mc.multicall() + for pair in pairs: + # Loading the strategies for each pair without executing the calls yet + multicaller.add_call( + carbon_controller.functions.strategiesByPair, + pair[0], + pair[1], + pair[2], + pair[3], + ) + + # Fetch strategies for each pair from the CarbonController contract object + strategies_by_pair = multicaller.multicall() self.carbon_inititalized[exchange_name] = True @@ -692,11 +688,10 @@ def get_fees_by_pair( web3=self.web3 ) - with multicaller as mc: - for pair in all_pairs: - mc.add_call( - carbon_controller.functions.pairTradingFeePPM, pair[0], pair[1] - ) + for pair in all_pairs: + multicaller.add_call( + carbon_controller.functions.pairTradingFeePPM, pair[0], pair[1] + ) return multicaller.multicall() diff --git a/fastlane_bot/events/multicall_utils.py b/fastlane_bot/events/multicall_utils.py index b88147dd7..4a3906430 100644 --- a/fastlane_bot/events/multicall_utils.py +++ b/fastlane_bot/events/multicall_utils.py @@ -141,64 +141,30 @@ def multicall_helper(exchange: str, rows_to_update: List, multicall_contract: An """ multicaller = MultiCaller(contract=multicall_contract, block_identifier=current_block, web3=mgr.web3, multicall_address=mgr.cfg.MULTICALL_CONTRACT_ADDRESS) - with multicaller as mc: - for row in rows_to_update: - pool_info = mgr.pool_data[row] - pool_info["last_updated_block"] = current_block - # Function to be defined elsewhere based on what each exchange type needs - multicall_fn(exchange, mc, mgr, multicall_contract, pool_info) - result_list = mc.multicall() - process_results_for_multicall(exchange, rows_to_update, result_list, mgr) - - -def multicall_fn(exchange: str, mc: Any, mgr: Any, multicall_contract: Any, pool_info: Dict[str, Any]) -> None: - """ - Function to be defined elsewhere based on what each exchange type needs. - - Parameters - ---------- - exchange : str - Name of the exchange. - mc : Any - The multicaller. - mgr : Any - Manager object containing configuration and pool data. - multicall_contract : Any - The multicall contract. - pool_info : Dict - The pool info. - - """ - if exchange == "bancor_v3": - mc.add_call(multicall_contract.functions.tradingLiquidity, pool_info["tkn1_address"]) - elif exchange == "bancor_pol": - mc.add_call(multicall_contract.functions.tokenPrice, pool_info["tkn0_address"]) - mc.add_call(multicall_contract.functions.amountAvailableForTrading, pool_info["tkn0_address"]) - elif exchange in mgr.cfg.CARBON_V1_FORKS: - mc.add_call(multicall_contract.functions.strategy, pool_info["cid"]) - elif exchange == 'balancer': - mc.add_call(multicall_contract.functions.getPoolTokens, pool_info["anchor"]) - else: - raise ValueError(f"Exchange {exchange} not supported.") - - -def process_results_for_multicall(exchange: str, rows_to_update: List, result_list: List, mgr: Any) -> None: - """ - Process the results for multicall. - - Parameters - ---------- - exchange : str - Name of the exchange. - rows_to_update : List - List of rows to update. - result_list : List - List of results. - mgr : Any - Manager object containing configuration and pool data. + for row in rows_to_update: + pool_info = mgr.pool_data[row] + pool_info["last_updated_block"] = current_block + if exchange == "bancor_v3": + multicaller.add_call(multicall_contract.functions.tradingLiquidity, pool_info["tkn1_address"]) + elif exchange == "bancor_pol": + multicaller.add_call(multicall_contract.functions.tokenPrice, pool_info["tkn0_address"]) + multicaller.add_call(multicall_contract.functions.amountAvailableForTrading, pool_info["tkn0_address"]) + elif exchange in mgr.cfg.CARBON_V1_FORKS: + multicaller.add_call(multicall_contract.functions.strategy, pool_info["cid"]) + elif exchange == 'balancer': + multicaller.add_call(multicall_contract.functions.getPoolTokens, pool_info["anchor"]) + else: + raise ValueError(f"Exchange {exchange} not supported") + + result_list = multicaller.multicall() + + # Handling for Bancor POL - combine results into a list of tuples + if exchange == "bancor_pol": + assert len(result_list) % 2 == 0, f"[multicall_helper] odd number of results for Bancor POL {len(result_list)}" + total_pools = len(result_list) // 2 + result_list = [(result_list[idx][0], result_list[idx][1], result_list[idx + total_pools]) for idx in range(total_pools)] - """ for row, result in zip(rows_to_update, result_list): pool_info = mgr.pool_data[row] params = extract_params_for_multicall(exchange, result, pool_info, mgr) From b6d38fb1f2be21ed6924ccaaf549fb156d6b97b9 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Thu, 9 May 2024 23:19:11 +0300 Subject: [PATCH 035/131] Update contract address --- fastlane_bot/config/multicaller.py | 2 +- fastlane_bot/config/network.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fastlane_bot/config/multicaller.py b/fastlane_bot/config/multicaller.py index 6cbd7bd4d..47c68c383 100644 --- a/fastlane_bot/config/multicaller.py +++ b/fastlane_bot/config/multicaller.py @@ -113,7 +113,7 @@ class MultiCaller(ContextManager): def __init__(self, contract: web3.contract.Contract, web3: Web3, - block_identifier: Any = 'latest', multicall_address = "0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696"): + block_identifier: Any = 'latest', multicall_address = "0xcA11bde05977b3631167028862bE2a173976CA11"): self._contract_calls: List[Callable] = [] self.contract = contract self.block_identifier = block_identifier diff --git a/fastlane_bot/config/network.py b/fastlane_bot/config/network.py index 0bed6b542..3785788cb 100644 --- a/fastlane_bot/config/network.py +++ b/fastlane_bot/config/network.py @@ -426,7 +426,7 @@ class _ConfigNetworkMainnet(ConfigNetwork): RPC_ENDPOINT = "https://eth-mainnet.alchemyapi.io/v2/" WEB3_ALCHEMY_PROJECT_ID = os.environ.get("WEB3_ALCHEMY_PROJECT_ID") - MULTICALL_CONTRACT_ADDRESS = "0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696" + MULTICALL_CONTRACT_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11" # NATIVE_GAS_TOKEN_KEY = "ETH-EEeE" # WRAPPED_GAS_TOKEN_KEY = "WETH-6Cc2" # STABLECOIN_KEY = "USDC-eB48" @@ -810,7 +810,7 @@ class _ConfigNetworkTenderly(ConfigNetwork): FASTLANE_CONTRACT_ADDRESS = "0x41Eeba3355d7D6FF628B7982F3F9D055c39488cB" CARBON_CONTROLLER_ADDRESS = "0xC537e898CD774e2dCBa3B14Ea6f34C93d5eA45e1" CARBON_CONTROLLER_VOUCHER = "0x3660F04B79751e31128f6378eAC70807e38f554E" - MULTICALL_CONTRACT_ADDRESS = "0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696" + MULTICALL_CONTRACT_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11" # Uniswap UNISWAP_V2_ROUTER_ADDRESS = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D" From 0c41f7fcd9b829401573d5754b4487b7b6e80241 Mon Sep 17 00:00:00 2001 From: Nicholas Welch Date: Fri, 10 May 2024 11:24:01 +1000 Subject: [PATCH 036/131] TEMP: focus the pol to ETH only temp solve multicall --- fastlane_bot/events/pools/bancor_pol.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane_bot/events/pools/bancor_pol.py b/fastlane_bot/events/pools/bancor_pol.py index 12acc7b95..58e58bc83 100644 --- a/fastlane_bot/events/pools/bancor_pol.py +++ b/fastlane_bot/events/pools/bancor_pol.py @@ -58,7 +58,7 @@ def event_matches_format( """ event_args = event["args"] - return "token" in event_args and "token0" not in event_args + return ("token" in event_args) and ("token0" not in event_args) and (event_args['token'] == "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE") def update_from_event( self, event_args: Dict[str, Any], data: Dict[str, Any] From 70a197a2f84e44d23160f71a43784c88fcf3d372 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Fri, 10 May 2024 11:04:17 +0300 Subject: [PATCH 037/131] Cleanup --- fastlane_bot/config/multicaller.py | 17 ----------------- fastlane_bot/tests/test_899_CustomMulticall.py | 18 ++++++++++++++++-- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/fastlane_bot/config/multicaller.py b/fastlane_bot/config/multicaller.py index 47c68c383..f482ced30 100644 --- a/fastlane_bot/config/multicaller.py +++ b/fastlane_bot/config/multicaller.py @@ -86,23 +86,6 @@ def get_output_types_from_abi(abi: List[Dict[str, Any]], function_name: str) -> raise ValueError(f"No function named {function_name} found in ABI.") -class ContractMethodWrapper: - """ - Wraps a contract method to be used with multicall. - """ - __DATE__ = "2022-09-26" - __VERSION__ = "0.0.2" - - def __init__(self, original_method, multicaller): - self.original_method = original_method - self.multicaller = multicaller - - def __call__(self, *args, **kwargs): - contract_call = self.original_method(*args, **kwargs) - self.multicaller.add_call(contract_call) - return contract_call - - class MultiCaller(ContextManager): """ Context manager for multicalls. diff --git a/fastlane_bot/tests/test_899_CustomMulticall.py b/fastlane_bot/tests/test_899_CustomMulticall.py index da5628765..a3a978395 100644 --- a/fastlane_bot/tests/test_899_CustomMulticall.py +++ b/fastlane_bot/tests/test_899_CustomMulticall.py @@ -15,12 +15,10 @@ load_dotenv() import time from fastlane_bot.config.multicaller import MultiCaller -from fastlane_bot.config.multicaller import ContractMethodWrapper from web3 import Web3 print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(MultiCaller)) -print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(ContractMethodWrapper)) from fastlane_bot.testing import * @@ -34,6 +32,22 @@ RPC_URL = f"https://eth-mainnet.alchemyapi.io/v2/{WEB3_ALCHEMY_PROJECT_ID}" CARBON_CONTROLLER_ADDRESS = "0xC537e898CD774e2dCBa3B14Ea6f34C93d5eA45e1" + +class ContractMethodWrapper: + """ + Wraps a contract method to be used with multicall. + """ + + def __init__(self, original_method, multicaller): + self.original_method = original_method + self.multicaller = multicaller + + def __call__(self, *args, **kwargs): + contract_call = self.original_method(*args, **kwargs) + self.multicaller.add_call(contract_call) + return contract_call + + class MockWeb3: class HTTPProvider: pass From 0d0cc343dad6661bac29b3f92589a73561cc143e Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Fri, 10 May 2024 16:56:38 +0300 Subject: [PATCH 038/131] Simplify the MulitiCaller class --- fastlane_bot/config/__init__.py | 9 - fastlane_bot/config/multicaller.py | 127 +++--------- fastlane_bot/events/managers/base.py | 28 +-- fastlane_bot/events/multicall_utils.py | 28 +-- .../tests/test_899_CustomMulticall.py | 192 ++---------------- 5 files changed, 69 insertions(+), 315 deletions(-) diff --git a/fastlane_bot/config/__init__.py b/fastlane_bot/config/__init__.py index a49c6ee0b..cd0646ca5 100644 --- a/fastlane_bot/config/__init__.py +++ b/fastlane_bot/config/__init__.py @@ -10,15 +10,6 @@ - ``ConfigProvider`` (``provider``; provider for network access) - ``Config`` (``config``; main configuration class, integrates the above) -Submodules provide the following - -- Constants (``constants`` and ``selectors``; various constants) -- ``MultiCaller`` and related (``multicaller``; TODO: what is this?) -- ``NetworkBase`` and ``EthereumNetwork`` (``connect``; network/chain connection code TODO: details) -- ``Cloaker`` (``cloaker``; deprecated) - - - --- (c) Copyright Bprotocol foundation 2023-24. All rights reserved. diff --git a/fastlane_bot/config/multicaller.py b/fastlane_bot/config/multicaller.py index f482ced30..a5bc87499 100644 --- a/fastlane_bot/config/multicaller.py +++ b/fastlane_bot/config/multicaller.py @@ -1,34 +1,18 @@ """ -This is the multicaller module. TODO: BETTER NAME - -TODO-MIKE: What exactly does this do and is it a bona fide config module? +MultiCaller class --- (c) Copyright Bprotocol foundation 2023-24. All rights reserved. Licensed under MIT. """ -from functools import partial -from typing import List, Callable, ContextManager, Any, Dict +from typing import Callable, ContextManager, Any, List, Dict -import web3 from eth_abi import decode -from web3 import Web3 from fastlane_bot.data.abi import MULTICALL_ABI -def cast(typ, val): - """Cast a value to a type. - - This returns the value unchanged. To the type checker this - signals that the return value has the designated type, but at - runtime we intentionally don't check anything (we want this - to be as fast as possible). - """ - return val - - def collapse_if_tuple(abi: Dict[str, Any]) -> str: """ Converts a tuple from a dict to a parenthesized list of its types. @@ -46,44 +30,10 @@ def collapse_if_tuple(abi: Dict[str, Any]) -> str: ... ) '(address,uint256,bytes)' """ - typ = abi["type"] - if not isinstance(typ, str): - raise TypeError( - "The 'type' must be a string, but got %r of type %s" % (typ, type(typ)) - ) - elif not typ.startswith("tuple"): - return typ - - delimited = ",".join(collapse_if_tuple(c) for c in abi["components"]) - # Whatever comes after "tuple" is the array dims. The ABI spec states that - # this will have the form "", "[]", or "[k]". - array_dim = typ[5:] - collapsed = "({}){}".format(delimited, array_dim) - - return collapsed - - -def get_output_types_from_abi(abi: List[Dict[str, Any]], function_name: str) -> List[str]: - """ - Get the output types from an ABI. - - Parameters - ---------- - abi : List[Dict[str, Any]] - The ABI - function_name : str - The function name - - Returns - ------- - List[str] - The output types - - """ - for item in abi: - if item['type'] == 'function' and item['name'] == function_name: - return [collapse_if_tuple(cast(Dict[str, Any], item)) for item in item['outputs']] - raise ValueError(f"No function named {function_name} found in ABI.") + if abi["type"].startswith("tuple"): + delimited = ",".join(collapse_if_tuple(c) for c in abi["components"]) + return "({}){}".format(delimited, abi["type"][len("tuple"):]) + return abi["type"] class MultiCaller(ContextManager): @@ -93,15 +43,14 @@ class MultiCaller(ContextManager): __DATE__ = "2022-09-26" __VERSION__ = "0.0.2" - - def __init__(self, contract: web3.contract.Contract, - web3: Web3, - block_identifier: Any = 'latest', multicall_address = "0xcA11bde05977b3631167028862bE2a173976CA11"): - self._contract_calls: List[Callable] = [] - self.contract = contract - self.block_identifier = block_identifier - self.web3 = web3 - self.MULTICALL_CONTRACT_ADDRESS = self.web3.to_checksum_address(multicall_address) + def __init__(self, target_contract: Any, multicall_contract_address: str): + self.multicall_contract = target_contract.w3.eth.contract( + abi=MULTICALL_ABI, + address=multicall_contract_address + ) + self.target_contract = target_contract + self.contract_calls: List[Callable] = [] + self.output_types_list: List[List[str]] = [] def __enter__(self) -> 'MultiCaller': return self @@ -109,41 +58,23 @@ def __enter__(self) -> 'MultiCaller': def __exit__(self, exc_type, exc_val, exc_tb): pass - def add_call(self, fn: Callable, *args, **kwargs) -> None: - self._contract_calls.append(partial(fn, *args, **kwargs)) - - def multicall(self) -> List[Any]: - calls_for_aggregate = [] - output_types_list = [] - _calls_for_aggregate = {} - _output_types_list = {} - for fn in self._contract_calls: - fn_name = str(fn).split('functools.partial(')[0] - output_types = get_output_types_from_abi(self.contract.abi, fn_name) - if fn_name in _calls_for_aggregate: - _calls_for_aggregate[fn_name].append({ - 'target': self.contract.address, - 'callData': fn()._encode_transaction_data() - }) - _output_types_list[fn_name].append(output_types) - else: - _calls_for_aggregate[fn_name] = [{ - 'target': self.contract.address, - 'callData': fn()._encode_transaction_data() - }] - _output_types_list[fn_name] = [output_types] - - for fn_list in _calls_for_aggregate.keys(): - calls_for_aggregate += (_calls_for_aggregate[fn_list]) - output_types_list += (_output_types_list[fn_list]) - - encoded_data = self.web3.eth.contract( - abi=MULTICALL_ABI, - address=self.MULTICALL_CONTRACT_ADDRESS - ).functions.tryAggregate(True, calls_for_aggregate).call(block_identifier=self.block_identifier) + def add_call(self, call: Callable): + self.contract_calls.append({ + 'target': self.target_contract.address, + 'callData': call._encode_transaction_data() + }) + self.output_types_list.append([ + collapse_if_tuple(item) for item in call.abi['outputs'] + ]) + + def run_calls(self, block_identifier: Any = 'latest') -> List[Any]: + encoded_data = self.multicall_contract.functions.tryAggregate( + True, + self.contract_calls + ).call(block_identifier=block_identifier) decoded_data_list = [] - for output_types, encoded_output in zip(output_types_list, encoded_data): + for output_types, encoded_output in zip(self.output_types_list, encoded_data): decoded_data = decode(output_types, encoded_output[1]) decoded_data_list.append(decoded_data) diff --git a/fastlane_bot/events/managers/base.py b/fastlane_bot/events/managers/base.py index eee06bc66..0da5a89a4 100644 --- a/fastlane_bot/events/managers/base.py +++ b/fastlane_bot/events/managers/base.py @@ -546,24 +546,16 @@ def get_strats_by_contract( """ multicaller = MultiCaller( - contract=carbon_controller, - block_identifier=self.replay_from_block or "latest", - multicall_address=self.cfg.MULTICALL_CONTRACT_ADDRESS, - web3=self.web3 + target_contract=carbon_controller, + multicall_contract_address=self.cfg.MULTICALL_CONTRACT_ADDRESS ) for pair in pairs: # Loading the strategies for each pair without executing the calls yet - multicaller.add_call( - carbon_controller.functions.strategiesByPair, - pair[0], - pair[1], - pair[2], - pair[3], - ) + multicaller.add_call(carbon_controller.functions.strategiesByPair(*pair)) # Fetch strategies for each pair from the CarbonController contract object - strategies_by_pair = multicaller.multicall() + strategies_by_pair = multicaller.run_calls(self.replay_from_block or "latest") self.carbon_inititalized[exchange_name] = True @@ -682,18 +674,14 @@ def get_fees_by_pair( """ multicaller = MultiCaller( - contract=carbon_controller, - block_identifier=self.replay_from_block or "latest", - multicall_address=self.cfg.MULTICALL_CONTRACT_ADDRESS, - web3=self.web3 + target_contract=carbon_controller, + multicall_contract_address=self.cfg.MULTICALL_CONTRACT_ADDRESS ) for pair in all_pairs: - multicaller.add_call( - carbon_controller.functions.pairTradingFeePPM, pair[0], pair[1] - ) + multicaller.add_call(carbon_controller.functions.pairTradingFeePPM(*pair)) - return multicaller.multicall() + return multicaller.run_calls(self.replay_from_block or "latest") def get_tkn_symbol_and_decimals( self, web3: Web3, erc20_contracts: Dict[str, Contract], cfg: Config, addr: str diff --git a/fastlane_bot/events/multicall_utils.py b/fastlane_bot/events/multicall_utils.py index 4a3906430..d77a03820 100644 --- a/fastlane_bot/events/multicall_utils.py +++ b/fastlane_bot/events/multicall_utils.py @@ -122,7 +122,7 @@ def get_pools_for_exchange(exchange: str, mgr: Any) -> [Any]: ] -def multicall_helper(exchange: str, rows_to_update: List, multicall_contract: Any, mgr: Any, current_block: int): +def multicall_helper(exchange: str, rows_to_update: List, target_contract: Any, mgr: Any, current_block: int): """ Helper function for multicall. @@ -132,36 +132,38 @@ def multicall_helper(exchange: str, rows_to_update: List, multicall_contract: An Name of the exchange. rows_to_update : List List of rows to update. - multicall_contract : Any - The multicall contract. + target_contract : Any + The target contract. mgr : Any Manager object containing configuration and pool data. current_block : int The current block. """ - multicaller = MultiCaller(contract=multicall_contract, block_identifier=current_block, web3=mgr.web3, multicall_address=mgr.cfg.MULTICALL_CONTRACT_ADDRESS) + multicaller = MultiCaller( + target_contract=target_contract, + multicall_contract_address=mgr.cfg.MULTICALL_CONTRACT_ADDRESS + ) for row in rows_to_update: pool_info = mgr.pool_data[row] pool_info["last_updated_block"] = current_block if exchange == "bancor_v3": - multicaller.add_call(multicall_contract.functions.tradingLiquidity, pool_info["tkn1_address"]) + multicaller.add_call(target_contract.functions.tradingLiquidity(pool_info["tkn1_address"])) elif exchange == "bancor_pol": - multicaller.add_call(multicall_contract.functions.tokenPrice, pool_info["tkn0_address"]) - multicaller.add_call(multicall_contract.functions.amountAvailableForTrading, pool_info["tkn0_address"]) + multicaller.add_call(target_contract.functions.tokenPrice(pool_info["tkn0_address"])) + multicaller.add_call(target_contract.functions.amountAvailableForTrading(pool_info["tkn0_address"])) elif exchange in mgr.cfg.CARBON_V1_FORKS: - multicaller.add_call(multicall_contract.functions.strategy, pool_info["cid"]) + multicaller.add_call(target_contract.functions.strategy(pool_info["cid"])) elif exchange == 'balancer': - multicaller.add_call(multicall_contract.functions.getPoolTokens, pool_info["anchor"]) + multicaller.add_call(target_contract.functions.getPoolTokens(pool_info["anchor"])) else: raise ValueError(f"Exchange {exchange} not supported") - result_list = multicaller.multicall() + result_list = multicaller.run_calls(current_block) # Handling for Bancor POL - combine results into a list of tuples if exchange == "bancor_pol": - assert len(result_list) % 2 == 0, f"[multicall_helper] odd number of results for Bancor POL {len(result_list)}" total_pools = len(result_list) // 2 result_list = [(result_list[idx][0], result_list[idx][1], result_list[idx + total_pools]) for idx in range(total_pools)] @@ -377,6 +379,6 @@ def multicall_every_iteration(current_block: int, mgr: Any): ] for idx, exchange in enumerate(multicallable_exchanges): - multicall_contract = get_multicall_contract_for_exchange(mgr, exchange) + target_contract = get_multicall_contract_for_exchange(mgr, exchange) rows_to_update = multicallable_pool_rows[idx] - multicall_helper(exchange, rows_to_update, multicall_contract, mgr, current_block) + multicall_helper(exchange, rows_to_update, target_contract, mgr, current_block) diff --git a/fastlane_bot/tests/test_899_CustomMulticall.py b/fastlane_bot/tests/test_899_CustomMulticall.py index a3a978395..49b0782c5 100644 --- a/fastlane_bot/tests/test_899_CustomMulticall.py +++ b/fastlane_bot/tests/test_899_CustomMulticall.py @@ -9,11 +9,10 @@ from fastlane_bot.data.abi import CARBON_CONTROLLER_ABI import os -from unittest.mock import Mock, patch +import json from dotenv import load_dotenv load_dotenv() -import time from fastlane_bot.config.multicaller import MultiCaller from web3 import Web3 @@ -31,191 +30,34 @@ WEB3_ALCHEMY_PROJECT_ID = os.environ.get("WEB3_ALCHEMY_PROJECT_ID") RPC_URL = f"https://eth-mainnet.alchemyapi.io/v2/{WEB3_ALCHEMY_PROJECT_ID}" CARBON_CONTROLLER_ADDRESS = "0xC537e898CD774e2dCBa3B14Ea6f34C93d5eA45e1" +MULTICALL_CONTRACT_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11" - -class ContractMethodWrapper: - """ - Wraps a contract method to be used with multicall. - """ - - def __init__(self, original_method, multicaller): - self.original_method = original_method - self.multicaller = multicaller - - def __call__(self, *args, **kwargs): - contract_call = self.original_method(*args, **kwargs) - self.multicaller.add_call(contract_call) - return contract_call - - -class MockWeb3: - class HTTPProvider: - pass - - class eth: - @staticmethod - def contract(address, abi): - return Mock() - - @staticmethod - def to_checksum_address(address): - return address - - @staticmethod - def to_checksum_address(address): - return address - -class MockContract: - - def __init__(self, address, abi): - self.address = address - self.abi = abi - - def functions(self): - return Mock() - - def encodeABI(self): - return Mock() - - def address(self): - return self.address - - def abi(self): - return self.abi - - def to_checksum_address(self, address): - return address - - # handle encoded data - def encode_abi(self): - return Mock() - - def decode_abi(self): - return Mock() - -start_time = time.time() - -w3 = Web3(Web3.HTTPProvider(RPC_URL, request_kwargs={'timeout': 60})) +w3 = Web3(Web3.HTTPProvider(RPC_URL)) contract = w3.eth.contract(address=CARBON_CONTROLLER_ADDRESS, abi=CARBON_CONTROLLER_ABI) - -mainnet_pairs = contract.caller.pairs() - -if len(mainnet_pairs) > 10: - mainnet_pairs = mainnet_pairs[:10] - -pair_fees_without_multicall = [contract.caller.pairTradingFeePPM(pair[0], pair[1]) for pair in mainnet_pairs] - -pair_fees_time_without_multicall = time.time() - start_time - -start_time = time.time() - -strats_by_pair_without_multicall = [contract.caller.strategiesByPair(pair[0], pair[1], 0, 5000) for pair in mainnet_pairs] - -strats_by_pair_time_without_multicall = time.time() - start_time - - +multicaller = MultiCaller(target_contract=contract, multicall_contract_address=MULTICALL_CONTRACT_ADDRESS) # ------------------------------------------------------------ # Test 899 # File test_899_CustomMulticall.py -# Segment test_multicaller_init +# Segment test_multi_caller # ------------------------------------------------------------ -def test_test_multicaller_init(): +def test_test_multi_caller(): # ------------------------------------------------------------ # + - - original_method = Mock() - multicaller = Mock() - - wrapper = ContractMethodWrapper(original_method, multicaller) - - assert wrapper.original_method == original_method - assert wrapper.multicaller == multicaller - # - - + pairs = contract.caller.pairs()[:10] + fee_funcs = [contract.functions.pairTradingFeePPM(pair[0], pair[1]) for pair in pairs] + strat_funcs = [contract.functions.strategiesByPair(pair[0], pair[1], 0, 5000) for pair in pairs] + funcs = fee_funcs + strat_funcs -# ------------------------------------------------------------ -# Test 899 -# File test_899_CustomMulticall.py -# Segment test_contract_method_wrapper_call -# ------------------------------------------------------------ -def test_test_contract_method_wrapper_call(): -# ------------------------------------------------------------ - - # + - original_method = Mock() - multicaller = Mock() - - wrapper = ContractMethodWrapper(original_method, multicaller) - - result = wrapper('arg1', kwarg1='kwarg1') - - original_method.assert_called_with('arg1', kwarg1='kwarg1') - multicaller.add_call.assert_called_with(result) - # - - + for func in funcs: + multicaller.add_call(func) -# ------------------------------------------------------------ -# Test 899 -# File test_899_CustomMulticall.py -# Segment test_multi_caller_init -# ------------------------------------------------------------ -def test_test_multi_caller_init(): -# ------------------------------------------------------------ - - # + - contract = Mock() - web3 = MockWeb3() - - multicaller = MultiCaller(contract, web3=web3) - - assert multicaller.contract == contract - assert multicaller.block_identifier == 'latest' - assert multicaller._contract_calls == [] - # - - + block_number = w3.eth.get_block('latest').number -# ------------------------------------------------------------ -# Test 899 -# File test_899_CustomMulticall.py -# Segment test_multi_caller_add_call -# ------------------------------------------------------------ -def test_test_multi_caller_add_call(): -# ------------------------------------------------------------ - - # + - contract = Mock() - web3 = MockWeb3() - - multicaller = MultiCaller(contract, web3=web3) - fn = Mock() - - multicaller.add_call(fn, 'arg1', kwarg1='kwarg1') - - assert len(multicaller._contract_calls) == 1 - # - - + sc_calls = [func.call(block_identifier=block_number) for func in funcs] + mc_calls = multicaller.run_calls(block_identifier=block_number) -# ------------------------------------------------------------ -# Test 899 -# File test_899_CustomMulticall.py -# Segment test_multi_caller_context_manager -# ------------------------------------------------------------ -def test_test_multi_caller_context_manager(): -# ------------------------------------------------------------ - - # + - contract = Mock() - web3 = MockWeb3() - multicaller = MultiCaller(contract, web3=web3) - - with patch.object(multicaller, 'multicall') as mock_multicall: - with multicaller: - multicaller.multicall() - pass - - mock_multicall.assert_called_once() + for sc_output, mc_output in zip(sc_calls, mc_calls): + assert sc_output == mc_output, f"sc_output = {json.dumps(sc_output, indent=4)}, mc_output = {json.dumps(mc_output, indent=4)}" # - - - \ No newline at end of file From 4fcfd167792ad8d29b40ea5cef89efb150bc66ac Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Fri, 10 May 2024 20:59:00 +0300 Subject: [PATCH 039/131] Fix test 899 --- fastlane_bot/tests/test_899_CustomMulticall.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fastlane_bot/tests/test_899_CustomMulticall.py b/fastlane_bot/tests/test_899_CustomMulticall.py index 49b0782c5..04b30dd26 100644 --- a/fastlane_bot/tests/test_899_CustomMulticall.py +++ b/fastlane_bot/tests/test_899_CustomMulticall.py @@ -9,13 +9,13 @@ from fastlane_bot.data.abi import CARBON_CONTROLLER_ABI import os -import json from dotenv import load_dotenv load_dotenv() from fastlane_bot.config.multicaller import MultiCaller from web3 import Web3 +from json import dumps print("{0.__name__} v{0.__VERSION__} ({0.__DATE__})".format(MultiCaller)) @@ -59,5 +59,7 @@ def test_test_multi_caller(): mc_calls = multicaller.run_calls(block_identifier=block_number) for sc_output, mc_output in zip(sc_calls, mc_calls): - assert sc_output == mc_output, f"sc_output = {json.dumps(sc_output, indent=4)}, mc_output = {json.dumps(mc_output, indent=4)}" + sc_output_str = dumps(sc_output, indent=4).lower() + mc_output_str = dumps(mc_output, indent=4).lower() + assert sc_output_str == mc_output_str, f"sc_output = {sc_output_str}, mc_output = {mc_output_str}" # - From 4b555ec08b6b429a3120bef4b36158c3c869bc01 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Fri, 10 May 2024 21:07:55 +0300 Subject: [PATCH 040/131] Cleanup --- fastlane_bot/config/multicaller.py | 17 ++++------------- fastlane_bot/events/managers/base.py | 2 ++ fastlane_bot/events/multicall_utils.py | 4 +--- fastlane_bot/tests/test_899_CustomMulticall.py | 8 ++++---- 4 files changed, 11 insertions(+), 20 deletions(-) diff --git a/fastlane_bot/config/multicaller.py b/fastlane_bot/config/multicaller.py index a5bc87499..4bbd0c5a1 100644 --- a/fastlane_bot/config/multicaller.py +++ b/fastlane_bot/config/multicaller.py @@ -6,7 +6,7 @@ All rights reserved. Licensed under MIT. """ -from typing import Callable, ContextManager, Any, List, Dict +from typing import Callable, Any, List, Dict from eth_abi import decode @@ -36,28 +36,19 @@ def collapse_if_tuple(abi: Dict[str, Any]) -> str: return abi["type"] -class MultiCaller(ContextManager): +class MultiCaller: """ Context manager for multicalls. """ __DATE__ = "2022-09-26" __VERSION__ = "0.0.2" - def __init__(self, target_contract: Any, multicall_contract_address: str): - self.multicall_contract = target_contract.w3.eth.contract( - abi=MULTICALL_ABI, - address=multicall_contract_address - ) + def __init__(self, web3: Any, target_contract: Any, multicall_contract_address: str): + self.multicall_contract = web3.eth.contract(abi=MULTICALL_ABI, address=multicall_contract_address) self.target_contract = target_contract self.contract_calls: List[Callable] = [] self.output_types_list: List[List[str]] = [] - def __enter__(self) -> 'MultiCaller': - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - pass - def add_call(self, call: Callable): self.contract_calls.append({ 'target': self.target_contract.address, diff --git a/fastlane_bot/events/managers/base.py b/fastlane_bot/events/managers/base.py index 0da5a89a4..f9206cd9b 100644 --- a/fastlane_bot/events/managers/base.py +++ b/fastlane_bot/events/managers/base.py @@ -546,6 +546,7 @@ def get_strats_by_contract( """ multicaller = MultiCaller( + web3=self.web3, target_contract=carbon_controller, multicall_contract_address=self.cfg.MULTICALL_CONTRACT_ADDRESS ) @@ -674,6 +675,7 @@ def get_fees_by_pair( """ multicaller = MultiCaller( + web3=self.web3, target_contract=carbon_controller, multicall_contract_address=self.cfg.MULTICALL_CONTRACT_ADDRESS ) diff --git a/fastlane_bot/events/multicall_utils.py b/fastlane_bot/events/multicall_utils.py index d77a03820..0e5719537 100644 --- a/fastlane_bot/events/multicall_utils.py +++ b/fastlane_bot/events/multicall_utils.py @@ -12,10 +12,7 @@ from typing import Dict, Any from typing import List, Tuple -import web3.exceptions - from fastlane_bot.config.multicaller import MultiCaller -from fastlane_bot.data.abi import ERC20_ABI from fastlane_bot.events.pools import CarbonV1Pool from fastlane_bot.events.pools.base import Pool @@ -141,6 +138,7 @@ def multicall_helper(exchange: str, rows_to_update: List, target_contract: Any, """ multicaller = MultiCaller( + web3=mgr.web3, target_contract=target_contract, multicall_contract_address=mgr.cfg.MULTICALL_CONTRACT_ADDRESS ) diff --git a/fastlane_bot/tests/test_899_CustomMulticall.py b/fastlane_bot/tests/test_899_CustomMulticall.py index 04b30dd26..db0b801cc 100644 --- a/fastlane_bot/tests/test_899_CustomMulticall.py +++ b/fastlane_bot/tests/test_899_CustomMulticall.py @@ -32,9 +32,9 @@ CARBON_CONTROLLER_ADDRESS = "0xC537e898CD774e2dCBa3B14Ea6f34C93d5eA45e1" MULTICALL_CONTRACT_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11" -w3 = Web3(Web3.HTTPProvider(RPC_URL)) -contract = w3.eth.contract(address=CARBON_CONTROLLER_ADDRESS, abi=CARBON_CONTROLLER_ABI) -multicaller = MultiCaller(target_contract=contract, multicall_contract_address=MULTICALL_CONTRACT_ADDRESS) +web3 = Web3(Web3.HTTPProvider(RPC_URL)) +contract = web3.eth.contract(address=CARBON_CONTROLLER_ADDRESS, abi=CARBON_CONTROLLER_ABI) +multicaller = MultiCaller(web3=web3, target_contract=contract, multicall_contract_address=MULTICALL_CONTRACT_ADDRESS) # ------------------------------------------------------------ # Test 899 @@ -53,7 +53,7 @@ def test_test_multi_caller(): for func in funcs: multicaller.add_call(func) - block_number = w3.eth.get_block('latest').number + block_number = web3.eth.get_block('latest').number sc_calls = [func.call(block_identifier=block_number) for func in funcs] mc_calls = multicaller.run_calls(block_identifier=block_number) From e512e5c6341e1a8fe70d1d253e110d776c3f25a7 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Fri, 10 May 2024 21:23:25 +0300 Subject: [PATCH 041/131] Cleanup --- fastlane_bot/events/multicall_utils.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/fastlane_bot/events/multicall_utils.py b/fastlane_bot/events/multicall_utils.py index 0e5719537..7fe0fa4b3 100644 --- a/fastlane_bot/events/multicall_utils.py +++ b/fastlane_bot/events/multicall_utils.py @@ -96,7 +96,7 @@ def encode_token_price(price: Decimal) -> int: return encode_float(encode_rate((price))) -def get_pools_for_exchange(exchange: str, mgr: Any) -> [Any]: +def get_pools_for_exchange(exchange: str, mgr: Any) -> List[Any]: """ Handles the initial iteration of the bot. @@ -203,9 +203,7 @@ def extract_params_for_multicall(exchange: str, result: Any, pool_info: Dict, mg params = CarbonV1Pool.parse_event(pool_info["state"], fake_event, "None") params["exchange_name"] = exchange elif exchange == "bancor_pol": - params = _extract_pol_params_for_multicall( - result, pool_info, mgr - ) + params = extract_pol_params_for_multicall(result, pool_info) elif exchange == "bancor_v3": pool_balances = result params = { @@ -233,7 +231,7 @@ def extract_params_for_multicall(exchange: str, result: Any, pool_info: Dict, mg return params -def _extract_pol_params_for_multicall(result: Any, pool_info: Dict, mgr: Any) -> Dict[str, Any]: +def extract_pol_params_for_multicall(result: Any, pool_info: Dict) -> Dict[str, Any]: """ Extract the Bancor POL params for multicall. @@ -243,8 +241,6 @@ def _extract_pol_params_for_multicall(result: Any, pool_info: Dict, mgr: Any) -> The result. pool_info : Dict The pool info. - mgr : Any - Manager object containing configuration and pool data. Returns ------- @@ -252,7 +248,6 @@ def _extract_pol_params_for_multicall(result: Any, pool_info: Dict, mgr: Any) -> The extracted params. """ - tkn0_address = pool_info["tkn0_address"] p0, p1, tkn_balance = result token_price = Decimal(p1) / Decimal(p0) token_price = int(str(encode_token_price(token_price))) @@ -328,9 +323,9 @@ def update_mgr_exchanges_for_multicall(mgr: Any, exchange: str, pool: Any, pool_ mgr.exchanges[exchange].pools[exchange_pool_idx] = pool -def get_multicall_contract_for_exchange(mgr: Any, exchange: str) -> str: +def get_pool_contract_for_exchange(mgr: Any, exchange: str) -> str: """ - Get the multicall contract for the exchange. + Get the pool contract for the exchange. Parameters ---------- @@ -342,7 +337,7 @@ def get_multicall_contract_for_exchange(mgr: Any, exchange: str) -> str: Returns ------- str - The multicall contract for the exchange. + The pool contract for the exchange. """ if exchange == "bancor_v3": @@ -377,6 +372,6 @@ def multicall_every_iteration(current_block: int, mgr: Any): ] for idx, exchange in enumerate(multicallable_exchanges): - target_contract = get_multicall_contract_for_exchange(mgr, exchange) + pool_contract = get_pool_contract_for_exchange(mgr, exchange) rows_to_update = multicallable_pool_rows[idx] - multicall_helper(exchange, rows_to_update, target_contract, mgr, current_block) + multicall_helper(exchange, rows_to_update, pool_contract, mgr, current_block) From c6f9219cf626b95dc15a18cb4c57bf9173eed5d3 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Fri, 10 May 2024 21:40:33 +0300 Subject: [PATCH 042/131] Cleanup --- fastlane_bot/config/multicaller.py | 12 +++--------- fastlane_bot/events/managers/base.py | 12 ++---------- fastlane_bot/events/multicall_utils.py | 6 +----- fastlane_bot/tests/test_899_CustomMulticall.py | 12 ++++++------ 4 files changed, 12 insertions(+), 30 deletions(-) diff --git a/fastlane_bot/config/multicaller.py b/fastlane_bot/config/multicaller.py index 4bbd0c5a1..5641319b5 100644 --- a/fastlane_bot/config/multicaller.py +++ b/fastlane_bot/config/multicaller.py @@ -43,20 +43,14 @@ class MultiCaller: __DATE__ = "2022-09-26" __VERSION__ = "0.0.2" - def __init__(self, web3: Any, target_contract: Any, multicall_contract_address: str): + def __init__(self, web3: Any, multicall_contract_address: str): self.multicall_contract = web3.eth.contract(abi=MULTICALL_ABI, address=multicall_contract_address) - self.target_contract = target_contract self.contract_calls: List[Callable] = [] self.output_types_list: List[List[str]] = [] def add_call(self, call: Callable): - self.contract_calls.append({ - 'target': self.target_contract.address, - 'callData': call._encode_transaction_data() - }) - self.output_types_list.append([ - collapse_if_tuple(item) for item in call.abi['outputs'] - ]) + self.contract_calls.append({'target': call.address, 'callData': call._encode_transaction_data()}) + self.output_types_list.append([collapse_if_tuple(item) for item in call.abi['outputs']]) def run_calls(self, block_identifier: Any = 'latest') -> List[Any]: encoded_data = self.multicall_contract.functions.tryAggregate( diff --git a/fastlane_bot/events/managers/base.py b/fastlane_bot/events/managers/base.py index f9206cd9b..900506e77 100644 --- a/fastlane_bot/events/managers/base.py +++ b/fastlane_bot/events/managers/base.py @@ -545,11 +545,7 @@ def get_strats_by_contract( The strategies. """ - multicaller = MultiCaller( - web3=self.web3, - target_contract=carbon_controller, - multicall_contract_address=self.cfg.MULTICALL_CONTRACT_ADDRESS - ) + multicaller = MultiCaller(self.web3, self.cfg.MULTICALL_CONTRACT_ADDRESS) for pair in pairs: # Loading the strategies for each pair without executing the calls yet @@ -674,11 +670,7 @@ def get_fees_by_pair( The fees by pair. """ - multicaller = MultiCaller( - web3=self.web3, - target_contract=carbon_controller, - multicall_contract_address=self.cfg.MULTICALL_CONTRACT_ADDRESS - ) + multicaller = MultiCaller(self.web3, self.cfg.MULTICALL_CONTRACT_ADDRESS) for pair in all_pairs: multicaller.add_call(carbon_controller.functions.pairTradingFeePPM(*pair)) diff --git a/fastlane_bot/events/multicall_utils.py b/fastlane_bot/events/multicall_utils.py index 7fe0fa4b3..e13bbb11a 100644 --- a/fastlane_bot/events/multicall_utils.py +++ b/fastlane_bot/events/multicall_utils.py @@ -137,11 +137,7 @@ def multicall_helper(exchange: str, rows_to_update: List, target_contract: Any, The current block. """ - multicaller = MultiCaller( - web3=mgr.web3, - target_contract=target_contract, - multicall_contract_address=mgr.cfg.MULTICALL_CONTRACT_ADDRESS - ) + multicaller = MultiCaller(mgr.web3, mgr.cfg.MULTICALL_CONTRACT_ADDRESS) for row in rows_to_update: pool_info = mgr.pool_data[row] diff --git a/fastlane_bot/tests/test_899_CustomMulticall.py b/fastlane_bot/tests/test_899_CustomMulticall.py index db0b801cc..b1bff830f 100644 --- a/fastlane_bot/tests/test_899_CustomMulticall.py +++ b/fastlane_bot/tests/test_899_CustomMulticall.py @@ -29,12 +29,12 @@ WEB3_ALCHEMY_PROJECT_ID = os.environ.get("WEB3_ALCHEMY_PROJECT_ID") RPC_URL = f"https://eth-mainnet.alchemyapi.io/v2/{WEB3_ALCHEMY_PROJECT_ID}" -CARBON_CONTROLLER_ADDRESS = "0xC537e898CD774e2dCBa3B14Ea6f34C93d5eA45e1" MULTICALL_CONTRACT_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11" +CARBON_CONTROLLER_ADDRESS = "0xC537e898CD774e2dCBa3B14Ea6f34C93d5eA45e1" web3 = Web3(Web3.HTTPProvider(RPC_URL)) -contract = web3.eth.contract(address=CARBON_CONTROLLER_ADDRESS, abi=CARBON_CONTROLLER_ABI) -multicaller = MultiCaller(web3=web3, target_contract=contract, multicall_contract_address=MULTICALL_CONTRACT_ADDRESS) +multicaller = MultiCaller(web3, MULTICALL_CONTRACT_ADDRESS) +carbon_contract = web3.eth.contract(address=CARBON_CONTROLLER_ADDRESS, abi=CARBON_CONTROLLER_ABI) # ------------------------------------------------------------ # Test 899 @@ -45,9 +45,9 @@ def test_test_multi_caller(): # ------------------------------------------------------------ # + - pairs = contract.caller.pairs()[:10] - fee_funcs = [contract.functions.pairTradingFeePPM(pair[0], pair[1]) for pair in pairs] - strat_funcs = [contract.functions.strategiesByPair(pair[0], pair[1], 0, 5000) for pair in pairs] + pairs = carbon_contract.caller.pairs()[:10] + fee_funcs = [carbon_contract.functions.pairTradingFeePPM(pair[0], pair[1]) for pair in pairs] + strat_funcs = [carbon_contract.functions.strategiesByPair(pair[0], pair[1], 0, 5000) for pair in pairs] funcs = fee_funcs + strat_funcs for func in funcs: From 800a1a9886a0b67fc156ae0c7601896ff75ea230 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Fri, 10 May 2024 22:03:17 +0300 Subject: [PATCH 043/131] Fix base.py --- fastlane_bot/events/managers/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane_bot/events/managers/base.py b/fastlane_bot/events/managers/base.py index 900506e77..65c0c2db0 100644 --- a/fastlane_bot/events/managers/base.py +++ b/fastlane_bot/events/managers/base.py @@ -673,7 +673,7 @@ def get_fees_by_pair( multicaller = MultiCaller(self.web3, self.cfg.MULTICALL_CONTRACT_ADDRESS) for pair in all_pairs: - multicaller.add_call(carbon_controller.functions.pairTradingFeePPM(*pair)) + multicaller.add_call(carbon_controller.functions.pairTradingFeePPM(pair[0], pair[1])) return multicaller.run_calls(self.replay_from_block or "latest") From de1952c161297db2fc683d2a02fff0d803044d29 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Fri, 10 May 2024 23:00:23 +0300 Subject: [PATCH 044/131] Preparation for allowing multi-call failures --- fastlane_bot/config/multicaller.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fastlane_bot/config/multicaller.py b/fastlane_bot/config/multicaller.py index 5641319b5..c3b6398a2 100644 --- a/fastlane_bot/config/multicaller.py +++ b/fastlane_bot/config/multicaller.py @@ -58,10 +58,10 @@ def run_calls(self, block_identifier: Any = 'latest') -> List[Any]: self.contract_calls ).call(block_identifier=block_identifier) - decoded_data_list = [] - for output_types, encoded_output in zip(self.output_types_list, encoded_data): - decoded_data = decode(output_types, encoded_output[1]) - decoded_data_list.append(decoded_data) + decoded_data_list = [ + decode(output_types, encoded_output[1]) if encoded_output[0] else (None,) + for output_types, encoded_output in zip(self.output_types_list, encoded_data) + ] return_data = [i[0] for i in decoded_data_list if len(i) == 1] return_data += [i[1] for i in decoded_data_list if len(i) > 1] From 8c15662c2befa8394f61d5689dcbf7e99e9593c8 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 11 May 2024 11:34:31 +0300 Subject: [PATCH 045/131] Improve code structure --- fastlane_bot/events/managers/base.py | 24 +++++++++---------- .../tests/test_899_CustomMulticall.py | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/fastlane_bot/events/managers/base.py b/fastlane_bot/events/managers/base.py index 65c0c2db0..5f0e9233a 100644 --- a/fastlane_bot/events/managers/base.py +++ b/fastlane_bot/events/managers/base.py @@ -203,14 +203,14 @@ def set_carbon_v1_fee_pairs(self): self._fee_pairs[ex] = fee_pairs def get_fee_pairs( - self, all_pairs: List[Tuple[str, str, int, int]], carbon_controller: Contract + self, all_pairs: List[Tuple[str, str]], carbon_controller: Contract ) -> Dict[Tuple[str, str], int]: """ Get the fees for each pair and store in a dictionary. Parameters ---------- - all_pairs : List[Tuple] + all_pairs : List[Tuple[str, str]] A list of pairs. carbon_controller : Contract The CarbonController contract object. @@ -408,7 +408,7 @@ def update_carbon(self, current_block: int, exchange_name: str): def get_carbon_pairs( self, carbon_controller: Contract, exchange_name: str, target_tokens: List[str] = None - ) -> List[Tuple[str, str, int, int]]: + ) -> List[Tuple[str, str]]: """ Get the carbon pairs. @@ -423,7 +423,7 @@ def get_carbon_pairs( Returns ------- - List[Tuple[str, str, int, int]] + List[Tuple[str, str]] The carbon pairs. """ @@ -444,7 +444,7 @@ def get_carbon_pairs( if pair[1] not in target_tokens: target_tokens.append(pair[1]) return [ - (pair[0], pair[1], 0, 5000) + pair for pair in pairs if pair[0] in target_tokens and pair[1] in target_tokens ] @@ -523,7 +523,7 @@ def create_or_get_carbon_controller(self, exchange_name: str): def get_strats_by_contract( self, - pairs: List[Tuple[str, str, int, int]], + pairs: List[Tuple[str, str]], carbon_controller: Contract, exchange_name: str, ) -> List[List[Any]]: @@ -532,7 +532,7 @@ def get_strats_by_contract( Parameters ---------- - pairs : List[Tuple[str, str, int, int]] + pairs : List[Tuple[str, str]] The pairs. carbon_controller : Contract The CarbonController contract object. @@ -549,7 +549,7 @@ def get_strats_by_contract( for pair in pairs: # Loading the strategies for each pair without executing the calls yet - multicaller.add_call(carbon_controller.functions.strategiesByPair(*pair)) + multicaller.add_call(carbon_controller.functions.strategiesByPair(*pair, 0, 5000)) # Fetch strategies for each pair from the CarbonController contract object strategies_by_pair = multicaller.run_calls(self.replay_from_block or "latest") @@ -571,7 +571,7 @@ def get_strats_by_state(self, pairs: List[List[Any]], exchange_name: str) -> Lis Parameters ---------- - pairs : List[Tuple[str, str, int, int]] + pairs : List[Tuple[str, str]] The pairs. exchange_name : str The carbon exchange/fork name. @@ -620,14 +620,14 @@ def get_strats_by_state(self, pairs: List[List[Any]], exchange_name: str) -> Lis return strategies def get_strategies( - self, pairs: List[Tuple[str, str, int, int]], carbon_controller: Contract, exchange_name: str + self, pairs: List[Tuple[str, str]], carbon_controller: Contract, exchange_name: str ) -> List[List[str]]: """ Get the strategies. Parameters ---------- - pairs : List[Tuple[str, str, int, int]] + pairs : List[Tuple[str, str]] The pairs. carbon_controller : Contract The CarbonController contract object. @@ -673,7 +673,7 @@ def get_fees_by_pair( multicaller = MultiCaller(self.web3, self.cfg.MULTICALL_CONTRACT_ADDRESS) for pair in all_pairs: - multicaller.add_call(carbon_controller.functions.pairTradingFeePPM(pair[0], pair[1])) + multicaller.add_call(carbon_controller.functions.pairTradingFeePPM(*pair)) return multicaller.run_calls(self.replay_from_block or "latest") diff --git a/fastlane_bot/tests/test_899_CustomMulticall.py b/fastlane_bot/tests/test_899_CustomMulticall.py index b1bff830f..01ce9b732 100644 --- a/fastlane_bot/tests/test_899_CustomMulticall.py +++ b/fastlane_bot/tests/test_899_CustomMulticall.py @@ -46,8 +46,8 @@ def test_test_multi_caller(): # + pairs = carbon_contract.caller.pairs()[:10] - fee_funcs = [carbon_contract.functions.pairTradingFeePPM(pair[0], pair[1]) for pair in pairs] - strat_funcs = [carbon_contract.functions.strategiesByPair(pair[0], pair[1], 0, 5000) for pair in pairs] + fee_funcs = [carbon_contract.functions.pairTradingFeePPM(*pair) for pair in pairs] + strat_funcs = [carbon_contract.functions.strategiesByPair(*pair, 0, 5000) for pair in pairs] funcs = fee_funcs + strat_funcs for func in funcs: From abedadee402c963ba0bbb5db61d01af1e22490ae Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 11 May 2024 11:55:16 +0300 Subject: [PATCH 046/131] Support multicall failures --- fastlane_bot/config/multicaller.py | 11 +++-------- fastlane_bot/events/managers/base.py | 10 +++++++++- fastlane_bot/events/multicall_utils.py | 10 +++++++--- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/fastlane_bot/config/multicaller.py b/fastlane_bot/config/multicaller.py index c3b6398a2..7dbc3db1a 100644 --- a/fastlane_bot/config/multicaller.py +++ b/fastlane_bot/config/multicaller.py @@ -54,16 +54,11 @@ def add_call(self, call: Callable): def run_calls(self, block_identifier: Any = 'latest') -> List[Any]: encoded_data = self.multicall_contract.functions.tryAggregate( - True, + False, self.contract_calls ).call(block_identifier=block_identifier) - decoded_data_list = [ - decode(output_types, encoded_output[1]) if encoded_output[0] else (None,) + return [ + decode(output_types, encoded_output[1])[0] if encoded_output[0] else None for output_types, encoded_output in zip(self.output_types_list, encoded_data) ] - - return_data = [i[0] for i in decoded_data_list if len(i) == 1] - return_data += [i[1] for i in decoded_data_list if len(i) > 1] - - return return_data diff --git a/fastlane_bot/events/managers/base.py b/fastlane_bot/events/managers/base.py index 5f0e9233a..7295103b7 100644 --- a/fastlane_bot/events/managers/base.py +++ b/fastlane_bot/events/managers/base.py @@ -554,6 +554,9 @@ def get_strats_by_contract( # Fetch strategies for each pair from the CarbonController contract object strategies_by_pair = multicaller.run_calls(self.replay_from_block or "latest") + # Assert that no result is None + assert all(result is not None for result in strategies_by_pair) + self.carbon_inititalized[exchange_name] = True # Log that Carbon is initialized @@ -675,7 +678,12 @@ def get_fees_by_pair( for pair in all_pairs: multicaller.add_call(carbon_controller.functions.pairTradingFeePPM(*pair)) - return multicaller.run_calls(self.replay_from_block or "latest") + fees_by_pair = multicaller.run_calls(self.replay_from_block or "latest") + + # Assert that no result is None + assert all(result is not None for result in fees_by_pair) + + return fees_by_pair def get_tkn_symbol_and_decimals( self, web3: Web3, erc20_contracts: Dict[str, Contract], cfg: Config, addr: str diff --git a/fastlane_bot/events/multicall_utils.py b/fastlane_bot/events/multicall_utils.py index e13bbb11a..01935c1c2 100644 --- a/fastlane_bot/events/multicall_utils.py +++ b/fastlane_bot/events/multicall_utils.py @@ -156,10 +156,14 @@ def multicall_helper(exchange: str, rows_to_update: List, target_contract: Any, result_list = multicaller.run_calls(current_block) - # Handling for Bancor POL - combine results into a list of tuples if exchange == "bancor_pol": - total_pools = len(result_list) // 2 - result_list = [(result_list[idx][0], result_list[idx][1], result_list[idx + total_pools]) for idx in range(total_pools)] + # Assert that no `amountAvailableForTrading` result is None + assert all(result is not None for result in result_list[1::2]) + # Replace every `tokenPrice` result which is None with (0, 0) + result_list = [result if result is not None else (0, 0) for result in result_list] + else: + # Assert that no result is None + assert all(result is not None for result in result_list) for row, result in zip(rows_to_update, result_list): pool_info = mgr.pool_data[row] From 62602cf237d49bb4ad85bebdae2ce38a680f487e Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 11 May 2024 11:58:08 +0300 Subject: [PATCH 047/131] Improve documentation --- fastlane_bot/events/managers/base.py | 4 ++-- fastlane_bot/events/multicall_utils.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fastlane_bot/events/managers/base.py b/fastlane_bot/events/managers/base.py index 7295103b7..a2c8c0c70 100644 --- a/fastlane_bot/events/managers/base.py +++ b/fastlane_bot/events/managers/base.py @@ -554,7 +554,7 @@ def get_strats_by_contract( # Fetch strategies for each pair from the CarbonController contract object strategies_by_pair = multicaller.run_calls(self.replay_from_block or "latest") - # Assert that no result is None + # Assert that all results are valid assert all(result is not None for result in strategies_by_pair) self.carbon_inititalized[exchange_name] = True @@ -680,7 +680,7 @@ def get_fees_by_pair( fees_by_pair = multicaller.run_calls(self.replay_from_block or "latest") - # Assert that no result is None + # Assert that all results are valid assert all(result is not None for result in fees_by_pair) return fees_by_pair diff --git a/fastlane_bot/events/multicall_utils.py b/fastlane_bot/events/multicall_utils.py index 01935c1c2..a0921306f 100644 --- a/fastlane_bot/events/multicall_utils.py +++ b/fastlane_bot/events/multicall_utils.py @@ -157,12 +157,12 @@ def multicall_helper(exchange: str, rows_to_update: List, target_contract: Any, result_list = multicaller.run_calls(current_block) if exchange == "bancor_pol": - # Assert that no `amountAvailableForTrading` result is None + # Assert that all `amountAvailableForTrading` results are valid assert all(result is not None for result in result_list[1::2]) - # Replace every `tokenPrice` result which is None with (0, 0) + # Replace every invalid `tokenPrice` result with (0, 0) result_list = [result if result is not None else (0, 0) for result in result_list] else: - # Assert that no result is None + # Assert that all results are valid assert all(result is not None for result in result_list) for row, result in zip(rows_to_update, result_list): From 1e6fdbfd70b9e8c960bdc2ffbabf0bb7eccaf4e3 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 11 May 2024 17:47:43 +0300 Subject: [PATCH 048/131] Fix the handling of POL data --- fastlane_bot/events/multicall_utils.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fastlane_bot/events/multicall_utils.py b/fastlane_bot/events/multicall_utils.py index a0921306f..69de8f636 100644 --- a/fastlane_bot/events/multicall_utils.py +++ b/fastlane_bot/events/multicall_utils.py @@ -159,8 +159,8 @@ def multicall_helper(exchange: str, rows_to_update: List, target_contract: Any, if exchange == "bancor_pol": # Assert that all `amountAvailableForTrading` results are valid assert all(result is not None for result in result_list[1::2]) - # Replace every invalid `tokenPrice` result with (0, 0) - result_list = [result if result is not None else (0, 0) for result in result_list] + # Rearrange the results as a list of `(tokenPrice, amountAvailableForTrading)` tuples + result_list = zip(result_list[0::2], result_list[1::2]) else: # Assert that all results are valid assert all(result is not None for result in result_list) @@ -248,9 +248,8 @@ def extract_pol_params_for_multicall(result: Any, pool_info: Dict) -> Dict[str, The extracted params. """ - p0, p1, tkn_balance = result - token_price = Decimal(p1) / Decimal(p0) - token_price = int(str(encode_token_price(token_price))) + p, tkn_balance = result + token_price = encode_token_price(Decimal(p[1]) / Decimal(p[0])) if p is not None else 0 result = { "fee": "0.000", From 49be886b7337547029b3243e42fb8e6fddd59189 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 11 May 2024 19:36:42 +0300 Subject: [PATCH 049/131] Minor improvement --- fastlane_bot/events/managers/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane_bot/events/managers/base.py b/fastlane_bot/events/managers/base.py index a2c8c0c70..becf27d89 100644 --- a/fastlane_bot/events/managers/base.py +++ b/fastlane_bot/events/managers/base.py @@ -566,7 +566,7 @@ def get_strats_by_contract( self.cfg.logger.debug( f"[events.managers.base] Retrieved {len(strategies_by_pair)} {exchange_name} strategies" ) - return [s for strat in strategies_by_pair if strat for s in strat if s] + return [strategy for strategies in strategies_by_pair for strategy in strategies] def get_strats_by_state(self, pairs: List[List[Any]], exchange_name: str) -> List[List[int]]: """ From eb09106ab01380cc6100ffe2a6792ede8003b9c2 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 11 May 2024 20:41:47 +0300 Subject: [PATCH 050/131] Fix the handling of multicall output --- fastlane_bot/config/multicaller.py | 6 ++++-- fastlane_bot/events/multicall_utils.py | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/fastlane_bot/config/multicaller.py b/fastlane_bot/config/multicaller.py index 7dbc3db1a..96692579e 100644 --- a/fastlane_bot/config/multicaller.py +++ b/fastlane_bot/config/multicaller.py @@ -58,7 +58,9 @@ def run_calls(self, block_identifier: Any = 'latest') -> List[Any]: self.contract_calls ).call(block_identifier=block_identifier) - return [ - decode(output_types, encoded_output[1])[0] if encoded_output[0] else None + results_list = [ + decode(output_types, encoded_output[1]) if encoded_output[0] else (None,) for output_types, encoded_output in zip(self.output_types_list, encoded_data) ] + + return [results if len(results) > 1 else results[0] for results in results_list] diff --git a/fastlane_bot/events/multicall_utils.py b/fastlane_bot/events/multicall_utils.py index 69de8f636..26970f667 100644 --- a/fastlane_bot/events/multicall_utils.py +++ b/fastlane_bot/events/multicall_utils.py @@ -160,7 +160,7 @@ def multicall_helper(exchange: str, rows_to_update: List, target_contract: Any, # Assert that all `amountAvailableForTrading` results are valid assert all(result is not None for result in result_list[1::2]) # Rearrange the results as a list of `(tokenPrice, amountAvailableForTrading)` tuples - result_list = zip(result_list[0::2], result_list[1::2]) + result_list = [result for result in zip(result_list[0::2], result_list[1::2])] else: # Assert that all results are valid assert all(result is not None for result in result_list) @@ -215,15 +215,15 @@ def extract_params_for_multicall(exchange: str, result: Any, pool_info: Dict, mg "address": pool_info["address"], } elif exchange == "balancer": - pool_balances = result + token, balances, last_change_block = result params = { "exchange_name": exchange, "address": pool_info["address"], } - for idx, bal in enumerate(pool_balances): - params[f"tkn{str(idx)}_balance"] = int(bal) + for idx, balance in enumerate(balances): + params[f"tkn{str(idx)}_balance"] = balance else: raise ValueError(f"Exchange {exchange} not supported.") From c0eb9fde494f0567e333c5da7ed25b0be03ba8ae Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 11 May 2024 20:46:02 +0300 Subject: [PATCH 051/131] Semantic --- fastlane_bot/config/multicaller.py | 4 ++-- fastlane_bot/events/multicall_utils.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fastlane_bot/config/multicaller.py b/fastlane_bot/config/multicaller.py index 96692579e..136398743 100644 --- a/fastlane_bot/config/multicaller.py +++ b/fastlane_bot/config/multicaller.py @@ -58,9 +58,9 @@ def run_calls(self, block_identifier: Any = 'latest') -> List[Any]: self.contract_calls ).call(block_identifier=block_identifier) - results_list = [ + result_list = [ decode(output_types, encoded_output[1]) if encoded_output[0] else (None,) for output_types, encoded_output in zip(self.output_types_list, encoded_data) ] - return [results if len(results) > 1 else results[0] for results in results_list] + return [result if len(result) > 1 else result[0] for result in result_list] diff --git a/fastlane_bot/events/multicall_utils.py b/fastlane_bot/events/multicall_utils.py index 26970f667..2fcbf7acc 100644 --- a/fastlane_bot/events/multicall_utils.py +++ b/fastlane_bot/events/multicall_utils.py @@ -215,7 +215,7 @@ def extract_params_for_multicall(exchange: str, result: Any, pool_info: Dict, mg "address": pool_info["address"], } elif exchange == "balancer": - token, balances, last_change_block = result + tokens, balances, last_change_block = result params = { "exchange_name": exchange, From 7a3c69b6a057db729cef7b7b2bc0575c260a6551 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 11 May 2024 20:51:47 +0300 Subject: [PATCH 052/131] Improve documentation --- fastlane_bot/config/multicaller.py | 1 + 1 file changed, 1 insertion(+) diff --git a/fastlane_bot/config/multicaller.py b/fastlane_bot/config/multicaller.py index 136398743..d68760942 100644 --- a/fastlane_bot/config/multicaller.py +++ b/fastlane_bot/config/multicaller.py @@ -63,4 +63,5 @@ def run_calls(self, block_identifier: Any = 'latest') -> List[Any]: for output_types, encoded_output in zip(self.output_types_list, encoded_data) ] + # Convert every single-value tuple into a single value return [result if len(result) > 1 else result[0] for result in result_list] From 1ad43cb33805e2f804a5a5336e14a28c9c246e99 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 11 May 2024 21:01:25 +0300 Subject: [PATCH 053/131] Remove unneeded return values --- fastlane_bot/events/multicall_utils.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/fastlane_bot/events/multicall_utils.py b/fastlane_bot/events/multicall_utils.py index 2fcbf7acc..ef2465336 100644 --- a/fastlane_bot/events/multicall_utils.py +++ b/fastlane_bot/events/multicall_utils.py @@ -169,8 +169,7 @@ def multicall_helper(exchange: str, rows_to_update: List, target_contract: Any, pool_info = mgr.pool_data[row] params = extract_params_for_multicall(exchange, result, pool_info, mgr) pool = mgr.get_or_init_pool(pool_info) - pool, pool_info = update_pool_for_multicall(params, pool_info, pool) - mgr.pool_data[row] = pool_info + update_pool_for_multicall(params, pool_info, pool) update_mgr_exchanges_for_multicall(mgr, exchange, pool, pool_info) @@ -270,7 +269,7 @@ def extract_pol_params_for_multicall(result: Any, pool_info: Dict) -> Dict[str, return result -def update_pool_for_multicall(params: Dict[str, Any], pool_info: Dict, pool: Any) -> Tuple[Pool, Dict]: +def update_pool_for_multicall(params: Dict[str, Any], pool_info: Dict, pool: Any): """ Update the pool for multicall. @@ -283,16 +282,10 @@ def update_pool_for_multicall(params: Dict[str, Any], pool_info: Dict, pool: Any pool : Any The pool. - Returns - ------- - Tuple[Pool, Dict] - The updated pool and pool info. - """ for key, value in params.items(): pool_info[key] = value pool.state[key] = value - return pool, pool_info def update_mgr_exchanges_for_multicall(mgr: Any, exchange: str, pool: Any, pool_info: Dict[str, Any]): From ee7e665465cc65c695473587757230e0c892f277 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 11 May 2024 21:01:53 +0300 Subject: [PATCH 054/131] Semantic --- fastlane_bot/events/multicall_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane_bot/events/multicall_utils.py b/fastlane_bot/events/multicall_utils.py index ef2465336..56c5dadf6 100644 --- a/fastlane_bot/events/multicall_utils.py +++ b/fastlane_bot/events/multicall_utils.py @@ -149,7 +149,7 @@ def multicall_helper(exchange: str, rows_to_update: List, target_contract: Any, multicaller.add_call(target_contract.functions.amountAvailableForTrading(pool_info["tkn0_address"])) elif exchange in mgr.cfg.CARBON_V1_FORKS: multicaller.add_call(target_contract.functions.strategy(pool_info["cid"])) - elif exchange == 'balancer': + elif exchange == "balancer": multicaller.add_call(target_contract.functions.getPoolTokens(pool_info["anchor"])) else: raise ValueError(f"Exchange {exchange} not supported") From 4e3ae9510b4d28fe869184a53bddcfb0dd481840 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 11 May 2024 21:10:22 +0300 Subject: [PATCH 055/131] General improvements --- fastlane_bot/events/multicall_utils.py | 64 ++++++++------------------ 1 file changed, 19 insertions(+), 45 deletions(-) diff --git a/fastlane_bot/events/multicall_utils.py b/fastlane_bot/events/multicall_utils.py index 56c5dadf6..ba56f62f7 100644 --- a/fastlane_bot/events/multicall_utils.py +++ b/fastlane_bot/events/multicall_utils.py @@ -167,8 +167,8 @@ def multicall_helper(exchange: str, rows_to_update: List, target_contract: Any, for row, result in zip(rows_to_update, result_list): pool_info = mgr.pool_data[row] - params = extract_params_for_multicall(exchange, result, pool_info, mgr) pool = mgr.get_or_init_pool(pool_info) + params = extract_params_for_multicall(exchange, result, pool_info, mgr) update_pool_for_multicall(params, pool_info, pool) update_mgr_exchanges_for_multicall(mgr, exchange, pool, pool_info) @@ -189,7 +189,6 @@ def extract_params_for_multicall(exchange: str, result: Any, pool_info: Dict, mg Manager object containing configuration and pool data. """ - params = {} if exchange in mgr.cfg.CARBON_V1_FORKS: strategy = result fake_event = { @@ -202,7 +201,24 @@ def extract_params_for_multicall(exchange: str, result: Any, pool_info: Dict, mg params = CarbonV1Pool.parse_event(pool_info["state"], fake_event, "None") params["exchange_name"] = exchange elif exchange == "bancor_pol": - params = extract_pol_params_for_multicall(result, pool_info) + p, tkn_balance = result + token_price = encode_token_price(Decimal(p[1]) / Decimal(p[0])) if p is not None else 0 + params = { + "fee": "0.000", + "fee_float": 0.000, + "tkn0_balance": 0, + "tkn1_balance": 0, + "exchange_name": pool_info["exchange_name"], + "address": pool_info["address"], + "y_0": tkn_balance, + "z_0": tkn_balance, + "A_0": 0, + "B_0": token_price, + "y_1": 0, + "z_1": 0, + "A_1": 0, + "B_1": 0, + } elif exchange == "bancor_v3": pool_balances = result params = { @@ -215,60 +231,18 @@ def extract_params_for_multicall(exchange: str, result: Any, pool_info: Dict, mg } elif exchange == "balancer": tokens, balances, last_change_block = result - params = { "exchange_name": exchange, "address": pool_info["address"], } - for idx, balance in enumerate(balances): params[f"tkn{str(idx)}_balance"] = balance - else: raise ValueError(f"Exchange {exchange} not supported.") return params -def extract_pol_params_for_multicall(result: Any, pool_info: Dict) -> Dict[str, Any]: - """ - Extract the Bancor POL params for multicall. - - Parameters - ---------- - result : Any - The result. - pool_info : Dict - The pool info. - - Returns - ------- - Dict[str, Any] - The extracted params. - - """ - p, tkn_balance = result - token_price = encode_token_price(Decimal(p[1]) / Decimal(p[0])) if p is not None else 0 - - result = { - "fee": "0.000", - "fee_float": 0.000, - "tkn0_balance": 0, - "tkn1_balance": 0, - "exchange_name": pool_info["exchange_name"], - "address": pool_info["address"], - "y_0": tkn_balance, - "z_0": tkn_balance, - "A_0": 0, - "B_0": token_price, - "y_1": 0, - "z_1": 0, - "A_1": 0, - "B_1": 0, - } - return result - - def update_pool_for_multicall(params: Dict[str, Any], pool_info: Dict, pool: Any): """ Update the pool for multicall. From 3fb5c7ff9e57ccbc56fe52f7290dae7ce36e580e Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Wed, 15 May 2024 14:16:14 +0300 Subject: [PATCH 056/131] Switch from flashbots to mevblocker, and enable access-lists --- fastlane_bot/helpers/txhelpers.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fastlane_bot/helpers/txhelpers.py b/fastlane_bot/helpers/txhelpers.py index bc7e19b03..b0a22e9fd 100644 --- a/fastlane_bot/helpers/txhelpers.py +++ b/fastlane_bot/helpers/txhelpers.py @@ -49,7 +49,7 @@ def __post_init__(self): self.wallet_address = self.cfg.w3.eth.account.from_key(self.cfg.ETH_PRIVATE_KEY_BE_CAREFUL).address if self.cfg.NETWORK == self.cfg.NETWORK_ETHEREUM: - self.use_access_list = False # TODO: figure out why flashbots is unable to handle this + self.use_access_list = True self.send_transaction = self._send_private_transaction else: self.use_access_list = False @@ -184,12 +184,12 @@ def _send_regular_transaction(self, raw_tx: str) -> str: def _send_private_transaction(self, raw_tx: str) -> str: response = post( - "https://rpc.flashbots.net/fast", + "https://rpc.mevblocker.io/noreverts", json = { "id": 1, "jsonrpc": "2.0", - "method": "eth_sendPrivateTransaction", - "params": [{"tx": raw_tx, "maxBlockNumber": hex(self.cfg.w3.eth.block_number + 10)}] + "method": "eth_sendRawTransaction", + "params": [raw_tx] } ) text = loads(response.text) From b73ccc26ab1fa3a3da89e370320c7ce665fbb165 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Thu, 16 May 2024 11:49:47 +0300 Subject: [PATCH 057/131] Remove redundant logging --- fastlane_bot/helpers/txhelpers.py | 2 +- fastlane_bot/utils.py | 2 +- main.py | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/fastlane_bot/helpers/txhelpers.py b/fastlane_bot/helpers/txhelpers.py index b0a22e9fd..0fdf166fc 100644 --- a/fastlane_bot/helpers/txhelpers.py +++ b/fastlane_bot/helpers/txhelpers.py @@ -199,5 +199,5 @@ def _send_private_transaction(self, raw_tx: str) -> str: def _wait_for_transaction_receipt(self, tx_hash: str) -> Optional[dict]: try: return loads(self.cfg.w3.to_json(self.cfg.w3.eth.wait_for_transaction_receipt(tx_hash))) - except TimeExhausted as _: + except TimeExhausted: return None diff --git a/fastlane_bot/utils.py b/fastlane_bot/utils.py index e1692d086..e449c6dd8 100644 --- a/fastlane_bot/utils.py +++ b/fastlane_bot/utils.py @@ -23,7 +23,7 @@ def safe_int(value: int or float) -> int: def num_format(value: int or float) -> str: try: return "{0:.4f}".format(value) - except Exception as _: + except Exception: return str(value) diff --git a/main.py b/main.py index cb61544f2..69a64dd57 100644 --- a/main.py +++ b/main.py @@ -524,10 +524,9 @@ def run(mgr, args, tenderly_uri=None) -> None: f"\n********************************************\n\n" ) - except Exception as e: + except Exception: mgr.cfg.logger.error(f"Error in main loop: {format_exc()}") mgr.cfg.logger.error( - f"[main] Error in main loop: {e}. Continuing... " f"Please report this error to the Fastlane Telegram channel if it persists." f"{mgr.cfg.logging_header}" ) From 1e661b85f2bd4da90e8d955399d45502496f4f3d Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Thu, 16 May 2024 12:48:00 +0300 Subject: [PATCH 058/131] Add `PAAL` to the list of Ethereum tax tokens --- fastlane_bot/config/network.py | 1 + 1 file changed, 1 insertion(+) diff --git a/fastlane_bot/config/network.py b/fastlane_bot/config/network.py index 3785788cb..7f956e7f5 100644 --- a/fastlane_bot/config/network.py +++ b/fastlane_bot/config/network.py @@ -443,6 +443,7 @@ class _ConfigNetworkMainnet(ConfigNetwork): "0xf94e7d0710709388bCe3161C32B4eEA56d3f91CC", # DSync "0x1258D60B224c0C5cD888D37bbF31aa5FCFb7e870", # GPU "0x6A7eFF1e2c355AD6eb91BEbB5ded49257F3FED98", # OPSEC + "0x14feE680690900BA0ccCfC76AD70Fd1b95D10e16", # PAAL ] # FACTORY, CONVERTER, AND CONTROLLER ADDRESSES From e1f8c8cbf77cbafae1f856b87acd87858726efde Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Thu, 16 May 2024 13:00:16 +0300 Subject: [PATCH 059/131] Improve logging messages --- fastlane_bot/bot.py | 6 +++--- fastlane_bot/helpers/poolandtokens.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fastlane_bot/bot.py b/fastlane_bot/bot.py index 9d9f347da..5fe5800d5 100644 --- a/fastlane_bot/bot.py +++ b/fastlane_bot/bot.py @@ -144,19 +144,19 @@ def get_curves(self) -> CPCContainer: ADDRDEC = {t.address: (t.address, int(t.decimals)) for t in tokens} for p in pools_and_tokens: + p.ADDRDEC = ADDRDEC try: - p.ADDRDEC = ADDRDEC curves += [ curve for curve in p.to_cpc() if all(curve.params[tkn] not in self.ConfigObj.TAX_TOKENS for tkn in ['tknx_addr', 'tkny_addr']) ] except SolidlyV2StablePoolsNotSupported as e: self.ConfigObj.logger.debug( - f"[bot.get_curves] SolidlyV2StablePoolsNotSupported: {e}\n" + f"[bot.get_curves] Solidly V2 stable pools not supported: {e}\n" ) except NotImplementedError as e: self.ConfigObj.logger.error( - f"[bot.get_curves] Pool type not yet supported, error: {e}\n" + f"[bot.get_curves] Not supported: {e}\n" ) except ZeroDivisionError as e: self.ConfigObj.logger.error( diff --git a/fastlane_bot/helpers/poolandtokens.py b/fastlane_bot/helpers/poolandtokens.py index c6ac1f61d..d4f10bc87 100644 --- a/fastlane_bot/helpers/poolandtokens.py +++ b/fastlane_bot/helpers/poolandtokens.py @@ -280,7 +280,7 @@ def to_cpc(self) -> Union[ConstantProductCurve, List[Any]]: elif self.exchange_name in self.ConfigObj.SUPPORTED_EXCHANGES: out = self._other_to_cpc() else: - raise NotImplementedError(f"Exchange {self.exchange_name} not implemented.") + raise NotImplementedError(f"exchange {self.exchange_name}") return out From 711278e9e7b54baf57dba79544cf0faad589b48b Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Thu, 16 May 2024 13:05:54 +0300 Subject: [PATCH 060/131] Add CSWAP to the list of Ethereum tax tokens --- fastlane_bot/config/network.py | 1 + 1 file changed, 1 insertion(+) diff --git a/fastlane_bot/config/network.py b/fastlane_bot/config/network.py index 7f956e7f5..501bb5047 100644 --- a/fastlane_bot/config/network.py +++ b/fastlane_bot/config/network.py @@ -440,6 +440,7 @@ class _ConfigNetworkMainnet(ConfigNetwork): TAX_TOKENS = [ "0x5a3e6A77ba2f983eC0d371ea3B475F8Bc0811AD5", # 0x0 "0x72e4f9F808C49A2a61dE9C5896298920Dc4EEEa9", # BITCOIN + "0xae41b275aaAF484b541A5881a2dDED9515184CCA", # CSWAP "0xf94e7d0710709388bCe3161C32B4eEA56d3f91CC", # DSync "0x1258D60B224c0C5cD888D37bbF31aa5FCFb7e870", # GPU "0x6A7eFF1e2c355AD6eb91BEbB5ded49257F3FED98", # OPSEC From 7e3dc4b71a6f18b84df1e0a69e4576863610862c Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Thu, 16 May 2024 13:10:23 +0300 Subject: [PATCH 061/131] Add HASHAI to the list of Ethereum tax tokens --- fastlane_bot/config/network.py | 1 + 1 file changed, 1 insertion(+) diff --git a/fastlane_bot/config/network.py b/fastlane_bot/config/network.py index 501bb5047..66d506c98 100644 --- a/fastlane_bot/config/network.py +++ b/fastlane_bot/config/network.py @@ -443,6 +443,7 @@ class _ConfigNetworkMainnet(ConfigNetwork): "0xae41b275aaAF484b541A5881a2dDED9515184CCA", # CSWAP "0xf94e7d0710709388bCe3161C32B4eEA56d3f91CC", # DSync "0x1258D60B224c0C5cD888D37bbF31aa5FCFb7e870", # GPU + "0x292fcDD1B104DE5A00250fEBbA9bC6A5092A0076", # HASHAI "0x6A7eFF1e2c355AD6eb91BEbB5ded49257F3FED98", # OPSEC "0x14feE680690900BA0ccCfC76AD70Fd1b95D10e16", # PAAL ] From 99859c5aca0da62a8598122a6ac18faf3d6e81de Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 18 May 2024 00:22:39 +0300 Subject: [PATCH 062/131] Add COSMIC, ELON and KENDU to the list of tax tokens for Ethereum --- fastlane_bot/config/network.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fastlane_bot/config/network.py b/fastlane_bot/config/network.py index 66d506c98..bd2e49cae 100644 --- a/fastlane_bot/config/network.py +++ b/fastlane_bot/config/network.py @@ -440,10 +440,13 @@ class _ConfigNetworkMainnet(ConfigNetwork): TAX_TOKENS = [ "0x5a3e6A77ba2f983eC0d371ea3B475F8Bc0811AD5", # 0x0 "0x72e4f9F808C49A2a61dE9C5896298920Dc4EEEa9", # BITCOIN + "0x40E64405F18e4FB01c6fc39f4F0c78df5eF9D0E0", # COSMIC "0xae41b275aaAF484b541A5881a2dDED9515184CCA", # CSWAP "0xf94e7d0710709388bCe3161C32B4eEA56d3f91CC", # DSync + "0x69420E3A3aa9E17Dea102Bb3a9b3B73dcDDB9528", # ELON "0x1258D60B224c0C5cD888D37bbF31aa5FCFb7e870", # GPU "0x292fcDD1B104DE5A00250fEBbA9bC6A5092A0076", # HASHAI + "0xaa95f26e30001251fb905d264Aa7b00eE9dF6C18", # KENDU "0x6A7eFF1e2c355AD6eb91BEbB5ded49257F3FED98", # OPSEC "0x14feE680690900BA0ccCfC76AD70Fd1b95D10e16", # PAAL ] From ccfafb08a9d63b762c31586511c12f2548a9ffe6 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sat, 18 May 2024 11:32:40 +0300 Subject: [PATCH 063/131] Change `TAX_TOKENS` from a list to a set --- fastlane_bot/config/network.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fastlane_bot/config/network.py b/fastlane_bot/config/network.py index bd2e49cae..ca18856fe 100644 --- a/fastlane_bot/config/network.py +++ b/fastlane_bot/config/network.py @@ -194,7 +194,7 @@ class ConfigNetwork(ConfigBase): USDT_ADDRESS = "0xdAC17F958D2ee523a2206206994597C13D831ec7" WETH_ADDRESS = WETH9_ADDRESS = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" - TAX_TOKENS = [] + TAX_TOKENS = set([]) # BNT_KEY = "BNT-FF1C" # ETH_KEY = "ETH-EEeE" @@ -437,7 +437,7 @@ class _ConfigNetworkMainnet(ConfigNetwork): WRAPPED_GAS_TOKEN_SYMBOL = "WETH" STABLECOIN_ADDRESS = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" - TAX_TOKENS = [ + TAX_TOKENS = set([ "0x5a3e6A77ba2f983eC0d371ea3B475F8Bc0811AD5", # 0x0 "0x72e4f9F808C49A2a61dE9C5896298920Dc4EEEa9", # BITCOIN "0x40E64405F18e4FB01c6fc39f4F0c78df5eF9D0E0", # COSMIC @@ -449,7 +449,7 @@ class _ConfigNetworkMainnet(ConfigNetwork): "0xaa95f26e30001251fb905d264Aa7b00eE9dF6C18", # KENDU "0x6A7eFF1e2c355AD6eb91BEbB5ded49257F3FED98", # OPSEC "0x14feE680690900BA0ccCfC76AD70Fd1b95D10e16", # PAAL - ] + ]) # FACTORY, CONVERTER, AND CONTROLLER ADDRESSES ####################################################################################### @@ -768,9 +768,9 @@ class _ConfigNetworkLinea(ConfigNetwork): WRAPPED_GAS_TOKEN_SYMBOL = "WETH" STABLECOIN_ADDRESS = "0x176211869ca2b568f2a7d4ee941e073a821ee1ff" - TAX_TOKENS = [ + TAX_TOKENS = set([ "0x1bE3735Dd0C0Eb229fB11094B6c277192349EBbf", # LUBE - ] + ]) IS_INJECT_POA_MIDDLEWARE = True # Balancer From 064fb950cceb5180d5214c501ff89e326f229807 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Mon, 6 May 2024 16:14:37 +0200 Subject: [PATCH 064/131] fix: produce a correct release tag --- .github/workflows/release-and-pypi-publish.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release-and-pypi-publish.yml b/.github/workflows/release-and-pypi-publish.yml index 2893f5056..057dd4798 100644 --- a/.github/workflows/release-and-pypi-publish.yml +++ b/.github/workflows/release-and-pypi-publish.yml @@ -83,6 +83,7 @@ jobs: id: bump_version_and_set_output run: | poetry version patch + echo new_version=$(poetry version | cut -d' ' -f2) >> $GITHUB_OUTPUT git checkout main git config --local user.email "action@github.com" git config --local user.name "GitHub Action" From ed78c20c1fd1eafa1a542057a67679325fbab2fc Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Thu, 9 May 2024 09:22:42 +0200 Subject: [PATCH 065/131] feat: chain config feat: strategy overlap --- .env.example | 1 + fastlane_bot/config/network.py | 41 ++++- fastlane_bot/config/selectors.py | 1 + .../sei/solidly_v2_event_mappings.csv | 1 + .../blockchain_data/sei/static_pool_data.csv | 4 + .../data/blockchain_data/sei/tokens.csv | 9 + .../sei/uniswap_v2_event_mappings.csv | 5 + .../sei/uniswap_v3_event_mappings.csv | 1 + fastlane_bot/data/multichain_addresses.csv | 4 + fastlane_bot/helpers/poolandtokens.py | 67 +++++++ fastlane_bot/tests/test_039_TestMultiMode.py | 3 + fastlane_bot/utils.py | 19 +- main.py | 2 +- .../NBTest/NBTest_002_CPCandOptimizer.ipynb | 12 ++ .../NBTest/NBTest_002_CPCandOptimizer.py | 4 + .../NBTest/NBTest_003_Serialization.ipynb | 163 ++++++++++++------ resources/NBTest/NBTest_003_Serialization.py | 22 ++- run_blockchain_terraformer.py | 9 +- 18 files changed, 295 insertions(+), 73 deletions(-) create mode 100644 fastlane_bot/data/blockchain_data/sei/solidly_v2_event_mappings.csv create mode 100644 fastlane_bot/data/blockchain_data/sei/static_pool_data.csv create mode 100644 fastlane_bot/data/blockchain_data/sei/tokens.csv create mode 100644 fastlane_bot/data/blockchain_data/sei/uniswap_v2_event_mappings.csv create mode 100644 fastlane_bot/data/blockchain_data/sei/uniswap_v3_event_mappings.csv diff --git a/.env.example b/.env.example index 5f1f4a5ae..5cb8f2b48 100644 --- a/.env.example +++ b/.env.example @@ -3,6 +3,7 @@ export ETH_PRIVATE_KEY_BE_CAREFUL="0x123-USE-YOUR-OWN-PRIVATE-KEY-HERE" export WEB3_FANTOM="FANTOM-API-KEY-HERE" // "public" can be used in place of a paid API key export WEB3_MANTLE="MANTLE-API-KEY-HERE" export WEB3_LINEA="LINEA-API-KEY-HERE" // +export WEB3_SEI="SEI-API-KEY-HERE" // #******** For Development - not required to run bot ********# export ETHERSCAN_TOKEN="ONLY_REQUIRED_IN_DEV" diff --git a/fastlane_bot/config/network.py b/fastlane_bot/config/network.py index ca18856fe..0a5593cf6 100644 --- a/fastlane_bot/config/network.py +++ b/fastlane_bot/config/network.py @@ -276,6 +276,7 @@ class ConfigNetwork(ConfigBase): NETWORK_FANTOM = S.NETWORK_FANTOM NETWORK_MANTLE = S.NETWORK_MANTLE NETWORK_LINEA = S.NETWORK_LINEA + NETWORK_SEI = S.NETWORK_SEI # FLAGS ####################################################################################### @@ -317,7 +318,9 @@ def new(cls, network=None): elif network == cls.NETWORK_MANTLE: return _ConfigNetworkMantle(_direct=False) elif network == cls.NETWORK_LINEA: - return _ConfigNetworkLinea(_direct=False) + return _ConfigNetworkLinea(_direct=False) + elif network == cls.NETWORK_SEI: + return _ConfigNetworkSei(_direct=False) elif network == cls.NETWORK_TENDERLY: return _ConfigNetworkTenderly(_direct=False) else: @@ -783,6 +786,42 @@ class _ConfigNetworkLinea(ConfigNetwork): # Add any exchanges unique to the chain here CHAIN_SPECIFIC_EXCHANGES = [] +class _ConfigNetworkSei(ConfigNetwork): + """ + Fastlane bot config -- network [Base Mainnet] + """ + + NETWORK = S.NETWORK_SEI + NETWORK_ID = "1" # TODO + NETWORK_NAME = "sei" + DEFAULT_PROVIDER = S.PROVIDER_ALCHEMY + RPC_ENDPOINT = "https://evm-rpc.arctic-1.seinetwork.io/" # TODO currently Sei devnet + WEB3_ALCHEMY_PROJECT_ID = os.environ.get("WEB3_SEI") + + network_df = get_multichain_addresses(network=NETWORK_NAME) + FASTLANE_CONTRACT_ADDRESS = "0xC7Dd38e64822108446872c5C2105308058c5C55C" #TODO - UPDATE WITH Mainnet + MULTICALL_CONTRACT_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11" + + CARBON_CONTROLLER_ADDRESS = "0x59f21012B2E9BA67ce6a7605E74F945D0D4C84EA" #TODO - UPDATE WITH Mainnet + CARBON_CONTROLLER_VOUCHER = "0xe4816658ad10bF215053C533cceAe3f59e1f1087" #TODO - UPDATE WITH Mainnet + + NATIVE_GAS_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" + WRAPPED_GAS_TOKEN_ADDRESS = "0x57eE725BEeB991c70c53f9642f36755EC6eb2139" # TODO confirm for Mainnet + NATIVE_GAS_TOKEN_SYMBOL = "SEI" + WRAPPED_GAS_TOKEN_SYMBOL = "WSEI" + STABLECOIN_ADDRESS = "0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C" #TODO USDC on devnet + + IS_INJECT_POA_MIDDLEWARE = False + # Balancer + BALANCER_VAULT_ADDRESS = "0x7ccBebeb88696f9c8b061f1112Bb970158e29cA5" # # TODO Jellyswap on devnet + + CHAIN_FLASHLOAN_TOKENS = { + "0x57eE725BEeB991c70c53f9642f36755EC6eb2139": "WSEI", #TODO confirm for Mainnet + "0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C": "USDC", #TODO confirm for Mainnet + } + # Add any exchanges unique to the chain here + CHAIN_SPECIFIC_EXCHANGES = [] + class _ConfigNetworkTenderly(ConfigNetwork): """ Fastlane bot config -- network [Ethereum Tenderly] diff --git a/fastlane_bot/config/selectors.py b/fastlane_bot/config/selectors.py index d910f52be..791810fea 100644 --- a/fastlane_bot/config/selectors.py +++ b/fastlane_bot/config/selectors.py @@ -18,6 +18,7 @@ NETWORK_CANTO = "canto" NETWORK_FANTOM = "fantom" NETWORK_LINEA = "linea" +NETWORK_SEI = "sei" NETWORK_MANTLE = "mantle" NETWORK_SCROLL = "scroll" NETWORK_BSC = "binance_smart_chain" diff --git a/fastlane_bot/data/blockchain_data/sei/solidly_v2_event_mappings.csv b/fastlane_bot/data/blockchain_data/sei/solidly_v2_event_mappings.csv new file mode 100644 index 000000000..2785f2805 --- /dev/null +++ b/fastlane_bot/data/blockchain_data/sei/solidly_v2_event_mappings.csv @@ -0,0 +1 @@ +exchange,address diff --git a/fastlane_bot/data/blockchain_data/sei/static_pool_data.csv b/fastlane_bot/data/blockchain_data/sei/static_pool_data.csv new file mode 100644 index 000000000..54e89f03e --- /dev/null +++ b/fastlane_bot/data/blockchain_data/sei/static_pool_data.csv @@ -0,0 +1,4 @@ +cid,strategy_id,last_updated,last_updated_block,descr,pair_name,exchange_name,fee,fee_float,address,anchor,tkn0_address,tkn1_address,tkn0_decimals,tkn1_decimals,exchange_id,tkn0_symbol,tkn1_symbol,timestamp,tkn0_balance,tkn1_balance,liquidity,sqrt_price_q96,tick,tick_spacing,exchange,pool_type,tkn0_weight,tkn1_weight,tkn2_address,tkn2_decimals,tkn2_symbol,tkn2_balance,tkn2_weight,tkn3_address,tkn3_decimals,tkn3_symbol,tkn3_balance,tkn3_weight,tkn4_address,tkn4_decimals,tkn4_symbol,tkn4_balance,tkn4_weight,tkn5_address,tkn5_decimals,tkn5_symbol,tkn5_balance,tkn5_weight,tkn6_address,tkn6_decimals,tkn6_symbol,tkn6_balance,tkn6_weight,tkn7_address,tkn7_decimals,tkn7_symbol,tkn7_balance,tkn7_weight +0x1422169ab760ea6994358267b7d3783e8e7fa55c6a74b365b3fd3d17cbf4c6f1,0,,2354,dragonswap 0x027D2E627209f1cebA52ADc8A5aFE9318459b44B/0x7b75109369ACb528d9fa989E227812a6589712b9,0x027D2E627209f1cebA52ADc8A5aFE9318459b44B/0x7b75109369ACb528d9fa989E227812a6589712b9,dragonswap,0.003,0.003,0x01A34Dfa104F020FEE739268679338169945D5B1,,0x027D2E627209f1cebA52ADc8A5aFE9318459b44B,0x7b75109369ACb528d9fa989E227812a6589712b9,18,18,3,WSEI,DSWAP,0,0,0,,,,,dragonswap,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xbfd9612b2cb8035908dff18c040f64de75999cefd1020b5ce8a2e533c2ecd5dc,0,,2354,dragonswap 0x027D2E627209f1cebA52ADc8A5aFE9318459b44B/0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C,0x027D2E627209f1cebA52ADc8A5aFE9318459b44B/0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C,dragonswap,0.003,0.003,0x85CB6BFd781e1f42f4E79Efb6bf1F1fEfE4E9732,,0x027D2E627209f1cebA52ADc8A5aFE9318459b44B,0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C,18,6,3,WSEI,USDC,0,0,0,,,,,dragonswap,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +0xe3aead757d877a15316e4896d5c5ab7639adbcba1ff76e3434b4e0af90f6225e,0,,2354,dragonswap 0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C/0xF983afa393199D6902a1Dd04f8E93465915ffD8B,0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C/0xF983afa393199D6902a1Dd04f8E93465915ffD8B,dragonswap,0.003,0.003,0x72A788B0A83e18ce1757171321E82c03e4351498,,0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C,0xF983afa393199D6902a1Dd04f8E93465915ffD8B,6,6,3,USDC,USDT,0,0,0,,,,,dragonswap,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, diff --git a/fastlane_bot/data/blockchain_data/sei/tokens.csv b/fastlane_bot/data/blockchain_data/sei/tokens.csv new file mode 100644 index 000000000..e79bf6c3b --- /dev/null +++ b/fastlane_bot/data/blockchain_data/sei/tokens.csv @@ -0,0 +1,9 @@ +address,decimals,symbol +0x26841a0A5D958B128209F4ea9a1DD7E61558c330,18,WSEI +0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C,6,USDC +0x027D2E627209f1cebA52ADc8A5aFE9318459b44B,18,WSEI +0x7b75109369ACb528d9fa989E227812a6589712b9,18,DSWAP +0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE,18,SEI +0x9e7A8e558Ce582511f4104465a886b7bEfBC146b,18,JLY +0x57eE725BEeB991c70c53f9642f36755EC6eb2139,18,WSEI +0xF983afa393199D6902a1Dd04f8E93465915ffD8B,6,USDT diff --git a/fastlane_bot/data/blockchain_data/sei/uniswap_v2_event_mappings.csv b/fastlane_bot/data/blockchain_data/sei/uniswap_v2_event_mappings.csv new file mode 100644 index 000000000..c23f7b0da --- /dev/null +++ b/fastlane_bot/data/blockchain_data/sei/uniswap_v2_event_mappings.csv @@ -0,0 +1,5 @@ +exchange,address +dragonswap,0x01A34Dfa104F020FEE739268679338169945D5B1 +dragonswap,0x85CB6BFd781e1f42f4E79Efb6bf1F1fEfE4E9732 +dragonswap,0x38BcEBb9A3fbF05B0Ab7ce9b485c9669578409fE +dragonswap,0x72A788B0A83e18ce1757171321E82c03e4351498 diff --git a/fastlane_bot/data/blockchain_data/sei/uniswap_v3_event_mappings.csv b/fastlane_bot/data/blockchain_data/sei/uniswap_v3_event_mappings.csv new file mode 100644 index 000000000..2785f2805 --- /dev/null +++ b/fastlane_bot/data/blockchain_data/sei/uniswap_v3_event_mappings.csv @@ -0,0 +1 @@ +exchange,address diff --git a/fastlane_bot/data/multichain_addresses.csv b/fastlane_bot/data/multichain_addresses.csv index c1ba30702..0650447ea 100644 --- a/fastlane_bot/data/multichain_addresses.csv +++ b/fastlane_bot/data/multichain_addresses.csv @@ -135,3 +135,7 @@ sushiswap_v3,thundercore,uniswap_v3,0xc35DADB65012eC5796536bD9864eD8773aBc74C4,0 pancakeswap_v3,zkevm,uniswap_v3,0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865,0x1b81D678ffb9C0263b24A97847620C99d213eB14,,, pancakeswap_v3,zksync,uniswap_v3,0x1BB72E0CbbEA93c08f535fc7856E0338D7F7a8aB,0xD70C70AD87aa8D45b8D59600342FB3AEe76E3c68,,, xfai_v0,linea,solidly_v2,0xa5136eAd459F0E61C99Cec70fe8F5C24cF3ecA26,0xD538be6e9026C13D130C9e17d509E69C8Bb0eF33,,222864, +carbon_v1,sei,carbon_v1,0x59f21012B2E9BA67ce6a7605E74F945D0D4C84EA,0x59f21012B2E9BA67ce6a7605E74F945D0D4C84EA,,17658678, +dragonswap,sei,uniswap_v2,0x5D370a6189F89603FaB67e9C68383e63F7B6A262,0x2346d3A6fb18Ff3ae590Ea31d9e41E6AB8c9f5EB,0.003,1008775, +jellyswap,sei,balancer,BALANCER_VAULT_ADDRESS,0x7ccBebeb88696f9c8b061f1112Bb970158e29cA5,0,222832, +uniswap_v3,sei,uniswap_v3,0x0000000000000000000000000000000000000000,0x0000000000000000000000000000000000000000,,1, diff --git a/fastlane_bot/helpers/poolandtokens.py b/fastlane_bot/helpers/poolandtokens.py index d4f10bc87..08f82506d 100644 --- a/fastlane_bot/helpers/poolandtokens.py +++ b/fastlane_bot/helpers/poolandtokens.py @@ -403,10 +403,25 @@ def _carbon_to_cpc(self) -> ConstantProductCurve: allow to omit yint (in which case it is set to y, but this does not make a difference for the result) """ + def calculate_parameters(y: Decimal, pa: Decimal, pb: Decimal, pm: Decimal, n: Decimal): + H = pa.sqrt() ** n + L = pb.sqrt() ** n + M = pm.sqrt() ** n + A = H - L + B = L + z = y * (H - L) / (M - L) if M > L else y + return z + + def check_overlap(pa0, pb0, pa1, pb1): + min0, max0 = sorted([pa0, pb0]) + min1, max1 = sorted([1 / pa1, 1 / pb1]) + prices_overlap = max(min0, min1) < min(max0, max1) + return prices_overlap # if idx == 0, use the first curve, otherwise use the second curve. change the numerical values to Decimal lst = [] errors = [] + strategy_typed_args = [] for i in [0, 1]: S = Decimal(self.A_1) if i == 0 else Decimal(self.A_0) @@ -450,6 +465,7 @@ def decimal_converter(idx): decimal_converter = decimal_converter(i) p_start = Decimal(encoded_order.p_start) * decimal_converter + p_marg = Decimal(encoded_order.p_marg) * decimal_converter p_end = Decimal(encoded_order.p_end) * decimal_converter yint = Decimal(yint) / ( Decimal("10") ** [self.tkn1_decimals, self.tkn0_decimals][i] @@ -457,6 +473,7 @@ def decimal_converter(idx): y = Decimal(y) / ( Decimal("10") ** [self.tkn1_decimals, self.tkn0_decimals][i] ) + is_limit_order = p_start==p_end tkny = 1 if i == 0 else 0 typed_args = { @@ -466,7 +483,9 @@ def decimal_converter(idx): "yint": yint, "y": y, "pb": p_end, + "p_marg": p_marg, # deleted later since not supported by from_carbon() "pa": p_start, + "is_limit_order": is_limit_order, # deleted later since not supported by from_carbon() "tkny": self.pair_name.split("/")[tkny].replace( self.ConfigObj.NATIVE_GAS_TOKEN_ADDRESS, self.ConfigObj.WRAPPED_GAS_TOKEN_ADDRESS ), @@ -476,6 +495,54 @@ def decimal_converter(idx): "descr": self.descr, "params": self._params, } + + strategy_typed_args += [typed_args] + + # Only overlapping strategies are selected for modification + if len(strategy_typed_args) == 2: + + is_overlapping = False + pmarg_threshold = Decimal("0.01") # 1% # WARNING using this condition alone can included stable/stable pairs incidently + + # evaluate that the marginal prices are within the pmarg_threshold + pmarg0, pmarg1 = [x['p_marg'] for x in strategy_typed_args] + pmarg0_inv = 1/pmarg0 # one of the orders must be flipped since prices are always dy/dx - but must flip same geomean_pmarg later + percent_component = pmarg_threshold * max(pmarg0_inv, pmarg1) + percent_component_met = abs(pmarg0_inv - pmarg1) <= percent_component + + # overlapping strategies by defintion cannot have A=0 i.e. there must be no limit orders + no_limit_orders = (strategy_typed_args[0]['is_limit_order'] == False) and (strategy_typed_args[1]['is_limit_order'] == False) + + # evaluate if the price boundaries pa/pb overlap at one end # TODO check logic and remove duplicate logic if necessary + prices_overlap = check_overlap(strategy_typed_args[0]['pa'], strategy_typed_args[0]['pb'], strategy_typed_args[1]['pa'], strategy_typed_args[1]['pb']) + + # if the threshold is met and neither is a limit order and prices overlap then likely to be overlapping + is_overlapping = percent_component_met and no_limit_orders and prices_overlap + + if is_overlapping: + # calculate the geometric mean + geomean_p_marg = Decimal.sqrt(pmarg0_inv * pmarg1) + + # modify the y_int based on the new geomean to the limit of y #TODO check that this math is correct + typed_args0 = strategy_typed_args[0] + new_yint0 = calculate_parameters(y=typed_args0['y'], pa=typed_args0['pa'], pb=typed_args0['pb'], pm=(1/geomean_p_marg), n=1) + if new_yint0 < typed_args0['y']: + new_yint0 = typed_args0['y'] + typed_args0['yint'] = new_yint0 + + typed_args1 = strategy_typed_args[1] + new_yint1 = calculate_parameters(y=typed_args1['y'], pa=typed_args1['pa'], pb=typed_args1['pb'], pm=(geomean_p_marg), n=1) + if new_yint1 < typed_args1['y']: + new_yint1 = typed_args1['y'] + typed_args1['yint'] = new_yint1 + + # repack the strateg_typed_args + strategy_typed_args = [typed_args0, typed_args1] + + for typed_args in strategy_typed_args: + # delete new args that arent supported by from_carbon() + del typed_args["p_marg"] + del typed_args["is_limit_order"] try: if typed_args["y"] > 0: lst.append( diff --git a/fastlane_bot/tests/test_039_TestMultiMode.py b/fastlane_bot/tests/test_039_TestMultiMode.py index dc47761d1..b3c875d70 100644 --- a/fastlane_bot/tests/test_039_TestMultiMode.py +++ b/fastlane_bot/tests/test_039_TestMultiMode.py @@ -140,6 +140,7 @@ def test_test_tax_tokens(): # ------------------------------------------------------------ assert any(token.address in cfg.TAX_TOKENS for token in tokens), f"[TestMultiMode], DB does not include any tax tokens" + assert len(CCm) == 516, f"[NBTest 039 TestMultiMode] Expected 516 curves, found {len(CCm)}" for curve in CCm: for token in cfg.TAX_TOKENS: @@ -178,6 +179,7 @@ def test_test_combos_and_tokens(): # ------------------------------------------------------------ # + + assert len(CCm) == 516, f"[NBTest 039 TestMultiMode] Expected 516 curves, found {len(CCm)}" arb_finder = bot._get_arb_finder("multi") finder = arb_finder( flashloan_tokens=flashloan_tokens, @@ -205,6 +207,7 @@ def test_test_expected_output(): # ------------------------------------------------------------ # + + assert len(CCm) == 516, f"[NBTest 039 TestMultiMode] Expected 516 curves, found {len(CCm)}" arb_finder = bot._get_arb_finder("multi") finder = arb_finder( flashloan_tokens=flashloan_tokens, diff --git a/fastlane_bot/utils.py b/fastlane_bot/utils.py index e449c6dd8..bfae0fe7b 100644 --- a/fastlane_bot/utils.py +++ b/fastlane_bot/utils.py @@ -68,6 +68,10 @@ def __getitem__(self, item): def decodeFloat(cls, value): """undoes the mantisse/exponent encoding in A,B""" return (value % cls.ONE) << (value // cls.ONE) + + @classmethod + def decodeRate(cls, value): + return (value / cls.ONE) ** 2 @classmethod def decode(cls, value): @@ -178,17 +182,12 @@ def p_start(self): @property def p_marg(self): + A = self.decodeFloat(int(self.A)) + B = self.decodeFloat(int(self.B)) if self.y == self.z: - return self.p_start - elif self.y == 0: - return self.p_end - raise NotImplementedError("p_marg not implemented for non-full / empty orders") - A = self.decodeFloat(self.A) - B = self.decodeFloat(self.B) - return self.decode(B + A * self.y / self.z) ** 2 - # https://github.com/bancorprotocol/carbon-simulator/blob/beta/benchmark/core/trade/impl.py - # 'marginalRate' : decodeRate(B + A if y == z else B + A * y / z), - + return self.decodeRate(B + A) + else: + return self.decodeRate(B + A * self.y/self.z) def find_latest_timestamped_folder(logging_path=None): """ diff --git a/main.py b/main.py index 69a64dd57..6ba36805d 100644 --- a/main.py +++ b/main.py @@ -671,7 +671,7 @@ def run(mgr, args, tenderly_uri=None) -> None: "--blockchain", default="ethereum", help="A blockchain from the list. Blockchains not in this list do not have a deployed Fast Lane contract and are not supported.", - choices=["ethereum", "coinbase_base", "fantom", "mantle", "linea"], + choices=["ethereum", "coinbase_base", "fantom", "mantle", "linea", "sei"], ) parser.add_argument( "--pool_data_update_frequency", diff --git a/resources/NBTest/NBTest_002_CPCandOptimizer.ipynb b/resources/NBTest/NBTest_002_CPCandOptimizer.ipynb index 099e10b48..0f16cffb0 100644 --- a/resources/NBTest/NBTest_002_CPCandOptimizer.ipynb +++ b/resources/NBTest/NBTest_002_CPCandOptimizer.ipynb @@ -2732,6 +2732,8 @@ "r = O.margp_optimizer(\"WETH\", result=O.MO_DEBUG)\n", "assert isinstance(r, dict)\n", "prices0 = r[\"price_estimates_t\"]\n", + "dtknfromp_f = r[\"dtknfromp_f\"]\n", + "assert np.linalg.norm(dtknfromp_f(np.log10(prices0))) < 1e-6\n", "assert not prices0 is None, f\"prices0 must not be None [{prices0}]\"\n", "r1 = O.arb(\"WETH\")\n", "r2 = O.SelfFinancingConstraints.arb(\"WETH\")\n", @@ -2792,6 +2794,16 @@ "prices0" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "30424c63", + "metadata": {}, + "outputs": [], + "source": [ + "dtknfromp_f(np.log10(prices0))" + ] + }, { "cell_type": "code", "execution_count": 115, diff --git a/resources/NBTest/NBTest_002_CPCandOptimizer.py b/resources/NBTest/NBTest_002_CPCandOptimizer.py index b985dacf7..4e34b9a1e 100644 --- a/resources/NBTest/NBTest_002_CPCandOptimizer.py +++ b/resources/NBTest/NBTest_002_CPCandOptimizer.py @@ -1278,6 +1278,8 @@ r = O.margp_optimizer("WETH", result=O.MO_DEBUG) assert isinstance(r, dict) prices0 = r["price_estimates_t"] +dtknfromp_f = r["dtknfromp_f"] +assert np.linalg.norm(dtknfromp_f(np.log10(prices0))) < 1e-6 assert not prices0 is None, f"prices0 must not be None [{prices0}]" r1 = O.arb("WETH") r2 = O.SelfFinancingConstraints.arb("WETH") @@ -1291,6 +1293,8 @@ prices0 +dtknfromp_f(np.log10(prices0)) + f = O.optimize("WETH", result=O.MO_DTKNFROMPF, params=dict(verbose=True, debug=False)) r3 = f(prices0, islog10=False) assert np.all(r3 == (0,0)) diff --git a/resources/NBTest/NBTest_003_Serialization.ipynb b/resources/NBTest/NBTest_003_Serialization.ipynb index d5b5680f6..fb042d8c0 100644 --- a/resources/NBTest/NBTest_003_Serialization.ipynb +++ b/resources/NBTest/NBTest_003_Serialization.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": 58, "id": "be65f3d2-769a-449f-90cd-2633a11478d0", "metadata": {}, "outputs": [ @@ -10,8 +10,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "imported m, np, pd, plt, os, sys, decimal; defined iseq, raises, require, Timer\n", - "ConstantProductCurve v3.4 (23/Jan/2024)\n", + "ConstantProductCurve v3.5 (22/Apr/2023)\n", "CPCArbOptimizer v5.1 (15/Sep/2023)\n" ] } @@ -21,7 +20,6 @@ " from fastlane_bot.tools.cpc import ConstantProductCurve as CPC, CPCContainer\n", " from fastlane_bot.tools.optimizer import CPCArbOptimizer, cp, time\n", " from fastlane_bot.testing import *\n", - "\n", "except:\n", " from tools.cpc import ConstantProductCurve as CPC, CPCContainer\n", " from tools.optimizer import CPCArbOptimizer, cp, time\n", @@ -55,7 +53,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 59, "id": "4030cea3-3e03-4e0f-8d80-7a2bcca05fcf", "metadata": {}, "outputs": [], @@ -65,7 +63,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 60, "id": "8cb4f9bc-2f31-4eae-b77f-533aa188e49b", "metadata": {}, "outputs": [], @@ -84,7 +82,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 61, "id": "a5ed0075-5ee5-4592-a192-e06d2b5af454", "metadata": {}, "outputs": [], @@ -95,7 +93,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 62, "id": "1bf13d91-2bc0-4819-96b9-2712ef89b6f1", "metadata": {}, "outputs": [], @@ -105,7 +103,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 63, "id": "ce05c578-5060-498e-b4eb-f55617d10cdd", "metadata": {}, "outputs": [], @@ -140,7 +138,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 64, "id": "41a5cdfe-fb7b-4c8b-a270-1a52f0765e94", "metadata": {}, "outputs": [ @@ -150,7 +148,7 @@ "ConstantProductCurve(k=10000, x=100, x_act=100, y_act=100, alpha=0.5, pair='TKNB/TKNQ', cid='1', fee=0, descr='UniV2', constr='uv2', params={})" ] }, - "execution_count": 7, + "execution_count": 64, "metadata": {}, "output_type": "execute_result" } @@ -174,7 +172,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 65, "id": "ea3cdfbc-8edd-41f1-9703-0ae0d72fdb9a", "metadata": {}, "outputs": [ @@ -194,7 +192,7 @@ " 'params': {}}" ] }, - "execution_count": 8, + "execution_count": 65, "metadata": {}, "output_type": "execute_result" } @@ -205,7 +203,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 66, "id": "595de023-5c66-40fc-928f-eca5fe6a50c9", "metadata": {}, "outputs": [], @@ -227,7 +225,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 67, "id": "215b5105-08d9-4077-a51a-7658cafcffa9", "metadata": {}, "outputs": [], @@ -261,7 +259,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 68, "id": "0963034a-b36c-4cfb-84da-ccb3c88c4389", "metadata": {}, "outputs": [], @@ -279,7 +277,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 69, "id": "eb5dd380-dd90-4a3b-b88a-5a697bdbc3a0", "metadata": {}, "outputs": [], @@ -310,7 +308,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 70, "id": "624b80f1-c811-483b-ba24-b76c72fe3e0c", "metadata": {}, "outputs": [], @@ -325,7 +323,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 71, "id": "34d52402-18d6-4485-8e5c-6cb4f8af2ab2", "metadata": {}, "outputs": [ @@ -349,7 +347,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 72, "id": "85175836-0fa9-4f64-a42f-b5b787e622f0", "metadata": {}, "outputs": [], @@ -364,7 +362,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 73, "id": "9753798a-b154-4865-a845-a1f5f1eb8e4b", "metadata": {}, "outputs": [ @@ -388,17 +386,17 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 74, "id": "5f683913-1799-4f3a-9473-a663d803448a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "ConstantProductCurve(k=0.01, x=0.0015438708879488485, x_act=0, y_act=1, alpha=0.5, pair='ETH/USDC', cid='4', fee=0, descr='Carbon', constr='carb', params={'y': 1, 'yint': 1, 'A': 10, 'B': 54.772255750516614, 'pa': 4195.445115010333, 'pb': 3000.0000000000005})" + "ConstantProductCurve(k=0.01, x=0.0015438708879488485, x_act=0, y_act=1, alpha=0.5, pair='ETH/USDC', cid='4', fee=0, descr='Carbon', constr='carb', params={'y': 1, 'yint': 1, 'A': 10, 'B': 54.772255750516614, 'pa': 4195.445115010333, 'pb': 3000.0000000000005, 'minrw': 1e-06})" ] }, - "execution_count": 17, + "execution_count": 74, "metadata": {}, "output_type": "execute_result" } @@ -412,7 +410,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 75, "id": "cffdcaa4-f221-4bd7-bf2d-5418a33e3592", "metadata": {}, "outputs": [], @@ -431,12 +429,35 @@ "assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, A=100, pair=\"ETH/USDC\", tkny=\"ETH\", fee=0, cid=\"1\", descr=\"Carbon\", isdydx=False)\n", "assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, B=100, pair=\"ETH/USDC\", tkny=\"ETH\", fee=0, cid=\"1\", descr=\"Carbon\", isdydx=False)\n", "assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, A=100, B=100, pair=\"ETH/USDC\", tkny=\"ETH\", fee=0, cid=\"1\", descr=\"Carbon\", isdydx=False)\n", - "assert raises(CPC.from_carbon, yint=1, y=1, pb=1800, pa=2200, pair=\"ETH/USDC\", tkny=\"ETH\", fee=0, cid=\"1\", descr=\"Carbon\", isdydx=False)" + "#assert raises(CPC.from_carbon, yint=1, y=1, pb=1800, pa=2200, pair=\"ETH/USDC\", tkny=\"ETH\", fee=0, cid=\"1\", descr=\"Carbon\", isdydx=False)" + ] + }, + { + "cell_type": "markdown", + "id": "6d4698a1-5df9-4c5d-a1c9-7e48fd9aa580", + "metadata": {}, + "source": [ + "TODO" ] }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 76, + "id": "c1b70bbc-2531-458a-a507-24d89559bf41", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "#assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, pair=\"ETH/USDC\", tkny=\"ETH\", cid=\"1\", descr=\"Carbon\", isdydx=False)\n", + "#assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, pair=\"ETH/USDC\", tkny=\"ETH\", fee=0, descr=\"Carbon\", isdydx=False)\n", + "#assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, pair=\"ETH/USDC\", tkny=\"ETH\", fee=0, cid=\"1\", isdydx=False)\n", + "#assert raises(CPC.from_carbon, yint=1, y=1, pb=1800, pa=2200, pair=\"ETH/USDC\", tkny=\"ETH\", fee=0, cid=\"1\", descr=\"Carbon\", isdydx=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 77, "id": "f66fc490-97e0-4c5e-958d-1e9014934d5c", "metadata": {}, "outputs": [], @@ -450,13 +471,31 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 78, "id": "465ff937-2382-4215-8e11-ec8096e1ea3d", "metadata": {}, "outputs": [], "source": [ "assert not raises(CPC.from_carbon, yint=1, y=1, pa=3100, pb=2900, pair=\"ETH/USDC\", tkny=\"USDC\", fee=0, cid=\"2\", descr=\"Carbon\", isdydx=True)\n", - "assert raises(CPC.from_carbon, yint=1, y=1, pb=3100, pa=2900, pair=\"ETH/USDC\", tkny=\"USDC\", fee=0, cid=\"2\", descr=\"Carbon\", isdydx=True)" + "#assert raises(CPC.from_carbon, yint=1, y=1, pb=3100, pa=2900, pair=\"ETH/USDC\", tkny=\"USDC\", fee=0, cid=\"2\", descr=\"Carbon\", isdydx=True)" + ] + }, + { + "cell_type": "markdown", + "id": "b0da3d2e-9b91-4c7a-89b8-8aa140901e32", + "metadata": {}, + "source": [ + "TODO" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "id": "d30a97ad-0188-4388-a3f8-3efa1151aa4a", + "metadata": {}, + "outputs": [], + "source": [ + "#assert raises(CPC.from_carbon, yint=1, y=1, pb=3100, pa=2900, pair=\"ETH/USDC\", tkny=\"USDC\", fee=0, cid=\"2\", descr=\"Carbon\", isdydx=True)" ] }, { @@ -469,7 +508,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 80, "id": "c5c8d6c3-0d15-4c3d-8852-b2870a7b4caa", "metadata": {}, "outputs": [], @@ -485,7 +524,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 81, "id": "8296d087-d5a5-4b77-825a-dd53ed60d4bd", "metadata": {}, "outputs": [], @@ -503,7 +542,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 82, "id": "e72d0162-dd59-489c-8efb-dbb8327ff553", "metadata": {}, "outputs": [ @@ -567,7 +606,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 83, "id": "c2d5dc97-05e8-4eca-abc7-66eee6e7d706", "metadata": {}, "outputs": [], @@ -581,7 +620,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 84, "id": "9f467a32-370b-4634-bec8-3c28be84a0a0", "metadata": {}, "outputs": [], @@ -593,7 +632,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 85, "id": "d7563934-5381-476d-b9cb-99b909691049", "metadata": {}, "outputs": [ @@ -603,7 +642,7 @@ "CPCContainer(curves=[ConstantProductCurve(k=2000, x=1, x_act=1, y_act=2000, alpha=0.5, pair='ETH/USDC', cid='1', fee=0.001, descr='UniV2', constr='uv2', params={'meh': 1}), ConstantProductCurve(k=8040, x=2, x_act=2, y_act=4020, alpha=0.5, pair='ETH/USDC', cid='2', fee=0.001, descr='UniV2', constr='uv2', params={}), ConstantProductCurve(k=1970, x=1, x_act=1, y_act=1970, alpha=0.5, pair='ETH/USDC', cid='3', fee=0.001, descr='UniV2', constr='uv2', params={})])" ] }, - "execution_count": 26, + "execution_count": 85, "metadata": {}, "output_type": "execute_result" } @@ -621,7 +660,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 86, "id": "131928b8-f927-4799-97c6-ec50631c7959", "metadata": {}, "outputs": [ @@ -723,7 +762,7 @@ "3 1970 1 1 1970 0.5 ETH/USDC 0.001 UniV2 uv2 {}" ] }, - "execution_count": 27, + "execution_count": 86, "metadata": {}, "output_type": "execute_result" } @@ -750,7 +789,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 87, "id": "6cd062ae-c465-4102-a57c-587874023de5", "metadata": {}, "outputs": [], @@ -779,7 +818,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 88, "id": "8c046e70-ef8a-4de8-bd17-726afb617ea1", "metadata": {}, "outputs": [ @@ -788,7 +827,7 @@ "output_type": "stream", "text": [ "len 2355000\n", - "elapsed time: 0.29s\n" + "elapsed time: 0.34s\n" ] } ], @@ -814,7 +853,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 89, "id": "e892dc06-329d-477f-adcb-40a87eb7a009", "metadata": {}, "outputs": [ @@ -822,7 +861,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "elapsed time: 0.21s\n" + "elapsed time: 0.22s\n" ] }, { @@ -913,7 +952,7 @@ "2 3 1970 1 1 1970 0.5 ETH/USDC 0.001 UniV2 uv2 {}" ] }, - "execution_count": 30, + "execution_count": 89, "metadata": {}, "output_type": "execute_result" } @@ -939,7 +978,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 90, "id": "a2976017-2a84-4fba-885d-7680d9f61c3a", "metadata": {}, "outputs": [ @@ -947,7 +986,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "elapsed time: 0.17s\n" + "elapsed time: 0.16s\n" ] } ], @@ -971,7 +1010,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 91, "id": "ed5aaa2c-2f5a-4863-87cf-a77240826a85", "metadata": { "lines_to_next_cell": 2 @@ -981,7 +1020,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "elapsed time: 0.21s\n" + "elapsed time: 0.16s\n" ] } ], @@ -1005,7 +1044,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 92, "id": "f1507cc7-96ba-4342-bf1e-955b248bd8b4", "metadata": {}, "outputs": [], @@ -1030,7 +1069,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 93, "id": "a1c75dfe-ce14-4840-9c62-39a8d5cfc3ad", "metadata": {}, "outputs": [ @@ -1139,7 +1178,7 @@ "3 1970 1 1 1970 0.5 ETH/USDC 0.001 UniV2 uv2 {}" ] }, - "execution_count": 34, + "execution_count": 93, "metadata": {}, "output_type": "execute_result" } @@ -1156,7 +1195,9 @@ { "cell_type": "markdown", "id": "3cfc2ff5-bf9d-4684-9b8c-2aff57937a46", - "metadata": {}, + "metadata": { + "tags": [] + }, "source": [ "### Benchmarking\n", "\n", @@ -1174,7 +1215,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 94, "id": "c43b9431-603d-49af-b5fd-1975e9f59e2f", "metadata": {}, "outputs": [ @@ -1183,10 +1224,10 @@ "output_type": "stream", "text": [ " 2355000 .curves.json\n", - "-rw-r--r-- 1 skl staff 720055 1 May 07:51 .curves.csv\n", - "-rw-r--r-- 1 skl staff 2965 1 May 07:51 .curves.csv.gz\n", - "-rw-r--r-- 1 skl staff 961219 1 May 07:51 .curves.pkl\n", - "-rw-r--r-- 1 skl staff 720055 1 May 07:51 .curves.tsv\n" + "-rw-r--r-- 1 skl staff 720055 1 May 15:40 .curves.csv\n", + "-rw-r--r-- 1 skl staff 2965 1 May 15:40 .curves.csv.gz\n", + "-rw-r--r-- 1 skl staff 961219 1 May 15:40 .curves.pkl\n", + "-rw-r--r-- 1 skl staff 720055 1 May 15:40 .curves.tsv\n" ] } ], @@ -1227,6 +1268,14 @@ "metadata": {}, "outputs": [], "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "73a341c5-36e5-47c2-9fb0-0a63b589b98b", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/resources/NBTest/NBTest_003_Serialization.py b/resources/NBTest/NBTest_003_Serialization.py index 95f7a43db..d1530d580 100644 --- a/resources/NBTest/NBTest_003_Serialization.py +++ b/resources/NBTest/NBTest_003_Serialization.py @@ -19,7 +19,6 @@ from fastlane_bot.tools.cpc import ConstantProductCurve as CPC, CPCContainer from fastlane_bot.tools.optimizer import CPCArbOptimizer, cp, time from fastlane_bot.testing import * - except: from tools.cpc import ConstantProductCurve as CPC, CPCContainer from tools.optimizer import CPCArbOptimizer, cp, time @@ -205,7 +204,16 @@ assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, A=100, pair="ETH/USDC", tkny="ETH", fee=0, cid="1", descr="Carbon", isdydx=False) assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, B=100, pair="ETH/USDC", tkny="ETH", fee=0, cid="1", descr="Carbon", isdydx=False) assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, A=100, B=100, pair="ETH/USDC", tkny="ETH", fee=0, cid="1", descr="Carbon", isdydx=False) -assert raises(CPC.from_carbon, yint=1, y=1, pb=1800, pa=2200, pair="ETH/USDC", tkny="ETH", fee=0, cid="1", descr="Carbon", isdydx=False) +#assert raises(CPC.from_carbon, yint=1, y=1, pb=1800, pa=2200, pair="ETH/USDC", tkny="ETH", fee=0, cid="1", descr="Carbon", isdydx=False) + +# TODO + +# + +#assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, pair="ETH/USDC", tkny="ETH", cid="1", descr="Carbon", isdydx=False) +#assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, pair="ETH/USDC", tkny="ETH", fee=0, descr="Carbon", isdydx=False) +#assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, pair="ETH/USDC", tkny="ETH", fee=0, cid="1", isdydx=False) +#assert raises(CPC.from_carbon, yint=1, y=1, pb=1800, pa=2200, pair="ETH/USDC", tkny="ETH", fee=0, cid="1", descr="Carbon", isdydx=False) +# - assert not raises(CPC.from_carbon, yint=1, y=1, A=1/10, B=m.sqrt(1/2000), pair="ETH/USDC", tkny="USDC", fee=0, cid="2", descr="Carbon", isdydx=True) assert raises(CPC.from_carbon, yint=1, y=1, A=1/10, B=m.sqrt(1/2000), pair="ETH/USDC", tkny="USDC", fee=0, cid="2", descr="Carbon", isdydx=False) @@ -214,7 +222,13 @@ assert raises(CPC.from_carbon, yint=1, y=1, A=-1/10, B=m.sqrt(1/2000), pair="ETH/USDC", tkny="USDC", fee=0, cid="2", descr="Carbon", isdydx=True) assert not raises(CPC.from_carbon, yint=1, y=1, pa=3100, pb=2900, pair="ETH/USDC", tkny="USDC", fee=0, cid="2", descr="Carbon", isdydx=True) -assert raises(CPC.from_carbon, yint=1, y=1, pb=3100, pa=2900, pair="ETH/USDC", tkny="USDC", fee=0, cid="2", descr="Carbon", isdydx=True) +#assert raises(CPC.from_carbon, yint=1, y=1, pb=3100, pa=2900, pair="ETH/USDC", tkny="USDC", fee=0, cid="2", descr="Carbon", isdydx=True) + +# TODO + +# + +#assert raises(CPC.from_carbon, yint=1, y=1, pb=3100, pa=2900, pair="ETH/USDC", tkny="USDC", fee=0, cid="2", descr="Carbon", isdydx=True) +# - # ## Charts [NOTEST] @@ -386,3 +400,5 @@ + + diff --git a/run_blockchain_terraformer.py b/run_blockchain_terraformer.py index 62d7f2840..96269107f 100644 --- a/run_blockchain_terraformer.py +++ b/run_blockchain_terraformer.py @@ -49,6 +49,7 @@ async def gather(): FANTOM = "fantom" MANTLE = "mantle" LINEA = "linea" +SEI = "sei" coingecko_network_map = { "ethereum": "ethereum", @@ -67,6 +68,7 @@ async def gather(): "cosmos": "cosmos", "kava": "kava", "mantle": "mantle", + "sei": "sei", } BLOCK_CHUNK_SIZE_MAP = { @@ -78,7 +80,8 @@ async def gather(): "coinbase_base": 0, "fantom": 5000, "mantle": 0, - "linea": 0 + "linea": 0, + "sei": 0, } ALCHEMY_KEY_DICT = { @@ -91,6 +94,7 @@ async def gather(): "fantom": "WEB3_FANTOM", "mantle": "WEB3_MANTLE", "linea": "WEB3_LINEA", + "sei": "WEB3_SEI", } ALCHEMY_RPC_LIST = { @@ -103,6 +107,7 @@ async def gather(): "fantom": "https://fantom.blockpi.network/v1/rpc/", "mantle": "https://rpc.mantle.xyz/", "linea": "https://rpc.linea.build/", + "sei": "https://evm-rpc.arctic-1.seinetwork.io/", # TODO update with mainnet } BALANCER_SUBGRAPH_CHAIN_URL = { @@ -114,6 +119,7 @@ async def gather(): "coinbase_base": "https://api.studio.thegraph.com/query/24660/balancer-base-v2/version/latest", "avalanche": "https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-avalanche-v2", "fantom": "https://api.thegraph.com/subgraphs/name/beethovenxfi/beethovenx", + "sei": "https://thegraph.dev.mvpworkshop.co/subgraphs/name/jelly" # TODO verify this for mainnet } @@ -1073,3 +1079,4 @@ def terraform_blockchain(network_name: str): #terraform_blockchain(network_name=FANTOM) #terraform_blockchain(network_name=MANTLE) #terraform_blockchain(network_name=LINEA) +#terraform_blockchain(network_name=SEI) From 3aabd33501e0ec8f1bf8035439b9e79b033933c9 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Thu, 9 May 2024 10:14:19 +0200 Subject: [PATCH 066/131] revert: optimizer tests --- .../NBTest/NBTest_002_CPCandOptimizer.ipynb | 12 -- .../NBTest/NBTest_002_CPCandOptimizer.py | 4 - .../NBTest/NBTest_003_Serialization.ipynb | 163 ++++++------------ resources/NBTest/NBTest_003_Serialization.py | 22 +-- 4 files changed, 60 insertions(+), 141 deletions(-) diff --git a/resources/NBTest/NBTest_002_CPCandOptimizer.ipynb b/resources/NBTest/NBTest_002_CPCandOptimizer.ipynb index 0f16cffb0..099e10b48 100644 --- a/resources/NBTest/NBTest_002_CPCandOptimizer.ipynb +++ b/resources/NBTest/NBTest_002_CPCandOptimizer.ipynb @@ -2732,8 +2732,6 @@ "r = O.margp_optimizer(\"WETH\", result=O.MO_DEBUG)\n", "assert isinstance(r, dict)\n", "prices0 = r[\"price_estimates_t\"]\n", - "dtknfromp_f = r[\"dtknfromp_f\"]\n", - "assert np.linalg.norm(dtknfromp_f(np.log10(prices0))) < 1e-6\n", "assert not prices0 is None, f\"prices0 must not be None [{prices0}]\"\n", "r1 = O.arb(\"WETH\")\n", "r2 = O.SelfFinancingConstraints.arb(\"WETH\")\n", @@ -2794,16 +2792,6 @@ "prices0" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "30424c63", - "metadata": {}, - "outputs": [], - "source": [ - "dtknfromp_f(np.log10(prices0))" - ] - }, { "cell_type": "code", "execution_count": 115, diff --git a/resources/NBTest/NBTest_002_CPCandOptimizer.py b/resources/NBTest/NBTest_002_CPCandOptimizer.py index 4e34b9a1e..b985dacf7 100644 --- a/resources/NBTest/NBTest_002_CPCandOptimizer.py +++ b/resources/NBTest/NBTest_002_CPCandOptimizer.py @@ -1278,8 +1278,6 @@ r = O.margp_optimizer("WETH", result=O.MO_DEBUG) assert isinstance(r, dict) prices0 = r["price_estimates_t"] -dtknfromp_f = r["dtknfromp_f"] -assert np.linalg.norm(dtknfromp_f(np.log10(prices0))) < 1e-6 assert not prices0 is None, f"prices0 must not be None [{prices0}]" r1 = O.arb("WETH") r2 = O.SelfFinancingConstraints.arb("WETH") @@ -1293,8 +1291,6 @@ prices0 -dtknfromp_f(np.log10(prices0)) - f = O.optimize("WETH", result=O.MO_DTKNFROMPF, params=dict(verbose=True, debug=False)) r3 = f(prices0, islog10=False) assert np.all(r3 == (0,0)) diff --git a/resources/NBTest/NBTest_003_Serialization.ipynb b/resources/NBTest/NBTest_003_Serialization.ipynb index fb042d8c0..d5b5680f6 100644 --- a/resources/NBTest/NBTest_003_Serialization.ipynb +++ b/resources/NBTest/NBTest_003_Serialization.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 58, + "execution_count": 1, "id": "be65f3d2-769a-449f-90cd-2633a11478d0", "metadata": {}, "outputs": [ @@ -10,7 +10,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "ConstantProductCurve v3.5 (22/Apr/2023)\n", + "imported m, np, pd, plt, os, sys, decimal; defined iseq, raises, require, Timer\n", + "ConstantProductCurve v3.4 (23/Jan/2024)\n", "CPCArbOptimizer v5.1 (15/Sep/2023)\n" ] } @@ -20,6 +21,7 @@ " from fastlane_bot.tools.cpc import ConstantProductCurve as CPC, CPCContainer\n", " from fastlane_bot.tools.optimizer import CPCArbOptimizer, cp, time\n", " from fastlane_bot.testing import *\n", + "\n", "except:\n", " from tools.cpc import ConstantProductCurve as CPC, CPCContainer\n", " from tools.optimizer import CPCArbOptimizer, cp, time\n", @@ -53,7 +55,7 @@ }, { "cell_type": "code", - "execution_count": 59, + "execution_count": 2, "id": "4030cea3-3e03-4e0f-8d80-7a2bcca05fcf", "metadata": {}, "outputs": [], @@ -63,7 +65,7 @@ }, { "cell_type": "code", - "execution_count": 60, + "execution_count": 3, "id": "8cb4f9bc-2f31-4eae-b77f-533aa188e49b", "metadata": {}, "outputs": [], @@ -82,7 +84,7 @@ }, { "cell_type": "code", - "execution_count": 61, + "execution_count": 4, "id": "a5ed0075-5ee5-4592-a192-e06d2b5af454", "metadata": {}, "outputs": [], @@ -93,7 +95,7 @@ }, { "cell_type": "code", - "execution_count": 62, + "execution_count": 5, "id": "1bf13d91-2bc0-4819-96b9-2712ef89b6f1", "metadata": {}, "outputs": [], @@ -103,7 +105,7 @@ }, { "cell_type": "code", - "execution_count": 63, + "execution_count": 6, "id": "ce05c578-5060-498e-b4eb-f55617d10cdd", "metadata": {}, "outputs": [], @@ -138,7 +140,7 @@ }, { "cell_type": "code", - "execution_count": 64, + "execution_count": 7, "id": "41a5cdfe-fb7b-4c8b-a270-1a52f0765e94", "metadata": {}, "outputs": [ @@ -148,7 +150,7 @@ "ConstantProductCurve(k=10000, x=100, x_act=100, y_act=100, alpha=0.5, pair='TKNB/TKNQ', cid='1', fee=0, descr='UniV2', constr='uv2', params={})" ] }, - "execution_count": 64, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -172,7 +174,7 @@ }, { "cell_type": "code", - "execution_count": 65, + "execution_count": 8, "id": "ea3cdfbc-8edd-41f1-9703-0ae0d72fdb9a", "metadata": {}, "outputs": [ @@ -192,7 +194,7 @@ " 'params': {}}" ] }, - "execution_count": 65, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -203,7 +205,7 @@ }, { "cell_type": "code", - "execution_count": 66, + "execution_count": 9, "id": "595de023-5c66-40fc-928f-eca5fe6a50c9", "metadata": {}, "outputs": [], @@ -225,7 +227,7 @@ }, { "cell_type": "code", - "execution_count": 67, + "execution_count": 10, "id": "215b5105-08d9-4077-a51a-7658cafcffa9", "metadata": {}, "outputs": [], @@ -259,7 +261,7 @@ }, { "cell_type": "code", - "execution_count": 68, + "execution_count": 11, "id": "0963034a-b36c-4cfb-84da-ccb3c88c4389", "metadata": {}, "outputs": [], @@ -277,7 +279,7 @@ }, { "cell_type": "code", - "execution_count": 69, + "execution_count": 12, "id": "eb5dd380-dd90-4a3b-b88a-5a697bdbc3a0", "metadata": {}, "outputs": [], @@ -308,7 +310,7 @@ }, { "cell_type": "code", - "execution_count": 70, + "execution_count": 13, "id": "624b80f1-c811-483b-ba24-b76c72fe3e0c", "metadata": {}, "outputs": [], @@ -323,7 +325,7 @@ }, { "cell_type": "code", - "execution_count": 71, + "execution_count": 14, "id": "34d52402-18d6-4485-8e5c-6cb4f8af2ab2", "metadata": {}, "outputs": [ @@ -347,7 +349,7 @@ }, { "cell_type": "code", - "execution_count": 72, + "execution_count": 15, "id": "85175836-0fa9-4f64-a42f-b5b787e622f0", "metadata": {}, "outputs": [], @@ -362,7 +364,7 @@ }, { "cell_type": "code", - "execution_count": 73, + "execution_count": 16, "id": "9753798a-b154-4865-a845-a1f5f1eb8e4b", "metadata": {}, "outputs": [ @@ -386,17 +388,17 @@ }, { "cell_type": "code", - "execution_count": 74, + "execution_count": 17, "id": "5f683913-1799-4f3a-9473-a663d803448a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "ConstantProductCurve(k=0.01, x=0.0015438708879488485, x_act=0, y_act=1, alpha=0.5, pair='ETH/USDC', cid='4', fee=0, descr='Carbon', constr='carb', params={'y': 1, 'yint': 1, 'A': 10, 'B': 54.772255750516614, 'pa': 4195.445115010333, 'pb': 3000.0000000000005, 'minrw': 1e-06})" + "ConstantProductCurve(k=0.01, x=0.0015438708879488485, x_act=0, y_act=1, alpha=0.5, pair='ETH/USDC', cid='4', fee=0, descr='Carbon', constr='carb', params={'y': 1, 'yint': 1, 'A': 10, 'B': 54.772255750516614, 'pa': 4195.445115010333, 'pb': 3000.0000000000005})" ] }, - "execution_count": 74, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -410,7 +412,7 @@ }, { "cell_type": "code", - "execution_count": 75, + "execution_count": 18, "id": "cffdcaa4-f221-4bd7-bf2d-5418a33e3592", "metadata": {}, "outputs": [], @@ -429,35 +431,12 @@ "assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, A=100, pair=\"ETH/USDC\", tkny=\"ETH\", fee=0, cid=\"1\", descr=\"Carbon\", isdydx=False)\n", "assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, B=100, pair=\"ETH/USDC\", tkny=\"ETH\", fee=0, cid=\"1\", descr=\"Carbon\", isdydx=False)\n", "assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, A=100, B=100, pair=\"ETH/USDC\", tkny=\"ETH\", fee=0, cid=\"1\", descr=\"Carbon\", isdydx=False)\n", - "#assert raises(CPC.from_carbon, yint=1, y=1, pb=1800, pa=2200, pair=\"ETH/USDC\", tkny=\"ETH\", fee=0, cid=\"1\", descr=\"Carbon\", isdydx=False)" - ] - }, - { - "cell_type": "markdown", - "id": "6d4698a1-5df9-4c5d-a1c9-7e48fd9aa580", - "metadata": {}, - "source": [ - "TODO" + "assert raises(CPC.from_carbon, yint=1, y=1, pb=1800, pa=2200, pair=\"ETH/USDC\", tkny=\"ETH\", fee=0, cid=\"1\", descr=\"Carbon\", isdydx=False)" ] }, { "cell_type": "code", - "execution_count": 76, - "id": "c1b70bbc-2531-458a-a507-24d89559bf41", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "#assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, pair=\"ETH/USDC\", tkny=\"ETH\", cid=\"1\", descr=\"Carbon\", isdydx=False)\n", - "#assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, pair=\"ETH/USDC\", tkny=\"ETH\", fee=0, descr=\"Carbon\", isdydx=False)\n", - "#assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, pair=\"ETH/USDC\", tkny=\"ETH\", fee=0, cid=\"1\", isdydx=False)\n", - "#assert raises(CPC.from_carbon, yint=1, y=1, pb=1800, pa=2200, pair=\"ETH/USDC\", tkny=\"ETH\", fee=0, cid=\"1\", descr=\"Carbon\", isdydx=False)" - ] - }, - { - "cell_type": "code", - "execution_count": 77, + "execution_count": 19, "id": "f66fc490-97e0-4c5e-958d-1e9014934d5c", "metadata": {}, "outputs": [], @@ -471,31 +450,13 @@ }, { "cell_type": "code", - "execution_count": 78, + "execution_count": 20, "id": "465ff937-2382-4215-8e11-ec8096e1ea3d", "metadata": {}, "outputs": [], "source": [ "assert not raises(CPC.from_carbon, yint=1, y=1, pa=3100, pb=2900, pair=\"ETH/USDC\", tkny=\"USDC\", fee=0, cid=\"2\", descr=\"Carbon\", isdydx=True)\n", - "#assert raises(CPC.from_carbon, yint=1, y=1, pb=3100, pa=2900, pair=\"ETH/USDC\", tkny=\"USDC\", fee=0, cid=\"2\", descr=\"Carbon\", isdydx=True)" - ] - }, - { - "cell_type": "markdown", - "id": "b0da3d2e-9b91-4c7a-89b8-8aa140901e32", - "metadata": {}, - "source": [ - "TODO" - ] - }, - { - "cell_type": "code", - "execution_count": 79, - "id": "d30a97ad-0188-4388-a3f8-3efa1151aa4a", - "metadata": {}, - "outputs": [], - "source": [ - "#assert raises(CPC.from_carbon, yint=1, y=1, pb=3100, pa=2900, pair=\"ETH/USDC\", tkny=\"USDC\", fee=0, cid=\"2\", descr=\"Carbon\", isdydx=True)" + "assert raises(CPC.from_carbon, yint=1, y=1, pb=3100, pa=2900, pair=\"ETH/USDC\", tkny=\"USDC\", fee=0, cid=\"2\", descr=\"Carbon\", isdydx=True)" ] }, { @@ -508,7 +469,7 @@ }, { "cell_type": "code", - "execution_count": 80, + "execution_count": 21, "id": "c5c8d6c3-0d15-4c3d-8852-b2870a7b4caa", "metadata": {}, "outputs": [], @@ -524,7 +485,7 @@ }, { "cell_type": "code", - "execution_count": 81, + "execution_count": 22, "id": "8296d087-d5a5-4b77-825a-dd53ed60d4bd", "metadata": {}, "outputs": [], @@ -542,7 +503,7 @@ }, { "cell_type": "code", - "execution_count": 82, + "execution_count": 23, "id": "e72d0162-dd59-489c-8efb-dbb8327ff553", "metadata": {}, "outputs": [ @@ -606,7 +567,7 @@ }, { "cell_type": "code", - "execution_count": 83, + "execution_count": 24, "id": "c2d5dc97-05e8-4eca-abc7-66eee6e7d706", "metadata": {}, "outputs": [], @@ -620,7 +581,7 @@ }, { "cell_type": "code", - "execution_count": 84, + "execution_count": 25, "id": "9f467a32-370b-4634-bec8-3c28be84a0a0", "metadata": {}, "outputs": [], @@ -632,7 +593,7 @@ }, { "cell_type": "code", - "execution_count": 85, + "execution_count": 26, "id": "d7563934-5381-476d-b9cb-99b909691049", "metadata": {}, "outputs": [ @@ -642,7 +603,7 @@ "CPCContainer(curves=[ConstantProductCurve(k=2000, x=1, x_act=1, y_act=2000, alpha=0.5, pair='ETH/USDC', cid='1', fee=0.001, descr='UniV2', constr='uv2', params={'meh': 1}), ConstantProductCurve(k=8040, x=2, x_act=2, y_act=4020, alpha=0.5, pair='ETH/USDC', cid='2', fee=0.001, descr='UniV2', constr='uv2', params={}), ConstantProductCurve(k=1970, x=1, x_act=1, y_act=1970, alpha=0.5, pair='ETH/USDC', cid='3', fee=0.001, descr='UniV2', constr='uv2', params={})])" ] }, - "execution_count": 85, + "execution_count": 26, "metadata": {}, "output_type": "execute_result" } @@ -660,7 +621,7 @@ }, { "cell_type": "code", - "execution_count": 86, + "execution_count": 27, "id": "131928b8-f927-4799-97c6-ec50631c7959", "metadata": {}, "outputs": [ @@ -762,7 +723,7 @@ "3 1970 1 1 1970 0.5 ETH/USDC 0.001 UniV2 uv2 {}" ] }, - "execution_count": 86, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" } @@ -789,7 +750,7 @@ }, { "cell_type": "code", - "execution_count": 87, + "execution_count": 28, "id": "6cd062ae-c465-4102-a57c-587874023de5", "metadata": {}, "outputs": [], @@ -818,7 +779,7 @@ }, { "cell_type": "code", - "execution_count": 88, + "execution_count": 29, "id": "8c046e70-ef8a-4de8-bd17-726afb617ea1", "metadata": {}, "outputs": [ @@ -827,7 +788,7 @@ "output_type": "stream", "text": [ "len 2355000\n", - "elapsed time: 0.34s\n" + "elapsed time: 0.29s\n" ] } ], @@ -853,7 +814,7 @@ }, { "cell_type": "code", - "execution_count": 89, + "execution_count": 30, "id": "e892dc06-329d-477f-adcb-40a87eb7a009", "metadata": {}, "outputs": [ @@ -861,7 +822,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "elapsed time: 0.22s\n" + "elapsed time: 0.21s\n" ] }, { @@ -952,7 +913,7 @@ "2 3 1970 1 1 1970 0.5 ETH/USDC 0.001 UniV2 uv2 {}" ] }, - "execution_count": 89, + "execution_count": 30, "metadata": {}, "output_type": "execute_result" } @@ -978,7 +939,7 @@ }, { "cell_type": "code", - "execution_count": 90, + "execution_count": 31, "id": "a2976017-2a84-4fba-885d-7680d9f61c3a", "metadata": {}, "outputs": [ @@ -986,7 +947,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "elapsed time: 0.16s\n" + "elapsed time: 0.17s\n" ] } ], @@ -1010,7 +971,7 @@ }, { "cell_type": "code", - "execution_count": 91, + "execution_count": 32, "id": "ed5aaa2c-2f5a-4863-87cf-a77240826a85", "metadata": { "lines_to_next_cell": 2 @@ -1020,7 +981,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "elapsed time: 0.16s\n" + "elapsed time: 0.21s\n" ] } ], @@ -1044,7 +1005,7 @@ }, { "cell_type": "code", - "execution_count": 92, + "execution_count": 33, "id": "f1507cc7-96ba-4342-bf1e-955b248bd8b4", "metadata": {}, "outputs": [], @@ -1069,7 +1030,7 @@ }, { "cell_type": "code", - "execution_count": 93, + "execution_count": 34, "id": "a1c75dfe-ce14-4840-9c62-39a8d5cfc3ad", "metadata": {}, "outputs": [ @@ -1178,7 +1139,7 @@ "3 1970 1 1 1970 0.5 ETH/USDC 0.001 UniV2 uv2 {}" ] }, - "execution_count": 93, + "execution_count": 34, "metadata": {}, "output_type": "execute_result" } @@ -1195,9 +1156,7 @@ { "cell_type": "markdown", "id": "3cfc2ff5-bf9d-4684-9b8c-2aff57937a46", - "metadata": { - "tags": [] - }, + "metadata": {}, "source": [ "### Benchmarking\n", "\n", @@ -1215,7 +1174,7 @@ }, { "cell_type": "code", - "execution_count": 94, + "execution_count": 35, "id": "c43b9431-603d-49af-b5fd-1975e9f59e2f", "metadata": {}, "outputs": [ @@ -1224,10 +1183,10 @@ "output_type": "stream", "text": [ " 2355000 .curves.json\n", - "-rw-r--r-- 1 skl staff 720055 1 May 15:40 .curves.csv\n", - "-rw-r--r-- 1 skl staff 2965 1 May 15:40 .curves.csv.gz\n", - "-rw-r--r-- 1 skl staff 961219 1 May 15:40 .curves.pkl\n", - "-rw-r--r-- 1 skl staff 720055 1 May 15:40 .curves.tsv\n" + "-rw-r--r-- 1 skl staff 720055 1 May 07:51 .curves.csv\n", + "-rw-r--r-- 1 skl staff 2965 1 May 07:51 .curves.csv.gz\n", + "-rw-r--r-- 1 skl staff 961219 1 May 07:51 .curves.pkl\n", + "-rw-r--r-- 1 skl staff 720055 1 May 07:51 .curves.tsv\n" ] } ], @@ -1268,14 +1227,6 @@ "metadata": {}, "outputs": [], "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "73a341c5-36e5-47c2-9fb0-0a63b589b98b", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/resources/NBTest/NBTest_003_Serialization.py b/resources/NBTest/NBTest_003_Serialization.py index d1530d580..95f7a43db 100644 --- a/resources/NBTest/NBTest_003_Serialization.py +++ b/resources/NBTest/NBTest_003_Serialization.py @@ -19,6 +19,7 @@ from fastlane_bot.tools.cpc import ConstantProductCurve as CPC, CPCContainer from fastlane_bot.tools.optimizer import CPCArbOptimizer, cp, time from fastlane_bot.testing import * + except: from tools.cpc import ConstantProductCurve as CPC, CPCContainer from tools.optimizer import CPCArbOptimizer, cp, time @@ -204,16 +205,7 @@ assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, A=100, pair="ETH/USDC", tkny="ETH", fee=0, cid="1", descr="Carbon", isdydx=False) assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, B=100, pair="ETH/USDC", tkny="ETH", fee=0, cid="1", descr="Carbon", isdydx=False) assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, A=100, B=100, pair="ETH/USDC", tkny="ETH", fee=0, cid="1", descr="Carbon", isdydx=False) -#assert raises(CPC.from_carbon, yint=1, y=1, pb=1800, pa=2200, pair="ETH/USDC", tkny="ETH", fee=0, cid="1", descr="Carbon", isdydx=False) - -# TODO - -# + -#assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, pair="ETH/USDC", tkny="ETH", cid="1", descr="Carbon", isdydx=False) -#assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, pair="ETH/USDC", tkny="ETH", fee=0, descr="Carbon", isdydx=False) -#assert raises(CPC.from_carbon, yint=1, y=1, pa=1800, pb=2200, pair="ETH/USDC", tkny="ETH", fee=0, cid="1", isdydx=False) -#assert raises(CPC.from_carbon, yint=1, y=1, pb=1800, pa=2200, pair="ETH/USDC", tkny="ETH", fee=0, cid="1", descr="Carbon", isdydx=False) -# - +assert raises(CPC.from_carbon, yint=1, y=1, pb=1800, pa=2200, pair="ETH/USDC", tkny="ETH", fee=0, cid="1", descr="Carbon", isdydx=False) assert not raises(CPC.from_carbon, yint=1, y=1, A=1/10, B=m.sqrt(1/2000), pair="ETH/USDC", tkny="USDC", fee=0, cid="2", descr="Carbon", isdydx=True) assert raises(CPC.from_carbon, yint=1, y=1, A=1/10, B=m.sqrt(1/2000), pair="ETH/USDC", tkny="USDC", fee=0, cid="2", descr="Carbon", isdydx=False) @@ -222,13 +214,7 @@ assert raises(CPC.from_carbon, yint=1, y=1, A=-1/10, B=m.sqrt(1/2000), pair="ETH/USDC", tkny="USDC", fee=0, cid="2", descr="Carbon", isdydx=True) assert not raises(CPC.from_carbon, yint=1, y=1, pa=3100, pb=2900, pair="ETH/USDC", tkny="USDC", fee=0, cid="2", descr="Carbon", isdydx=True) -#assert raises(CPC.from_carbon, yint=1, y=1, pb=3100, pa=2900, pair="ETH/USDC", tkny="USDC", fee=0, cid="2", descr="Carbon", isdydx=True) - -# TODO - -# + -#assert raises(CPC.from_carbon, yint=1, y=1, pb=3100, pa=2900, pair="ETH/USDC", tkny="USDC", fee=0, cid="2", descr="Carbon", isdydx=True) -# - +assert raises(CPC.from_carbon, yint=1, y=1, pb=3100, pa=2900, pair="ETH/USDC", tkny="USDC", fee=0, cid="2", descr="Carbon", isdydx=True) # ## Charts [NOTEST] @@ -400,5 +386,3 @@ - - From 268b6aca6b004e8bc4369f73e9026a8b1e53a66f Mon Sep 17 00:00:00 2001 From: Nicholas Welch Date: Wed, 8 May 2024 10:41:08 +1000 Subject: [PATCH 067/131] remove handle_target_token_addresses --- fastlane_bot/events/utils.py | 38 ------------------------------------ main.py | 7 +------ 2 files changed, 1 insertion(+), 44 deletions(-) diff --git a/fastlane_bot/events/utils.py b/fastlane_bot/events/utils.py index 8f2e66618..154683b69 100644 --- a/fastlane_bot/events/utils.py +++ b/fastlane_bot/events/utils.py @@ -1678,44 +1678,6 @@ def delete_tenderly_forks(forks_to_cleanup: List[str], mgr: Any) -> List[str]: return forks_to_keep - -def handle_target_token_addresses(static_pool_data: pd.DataFrame, target_tokens: List): - """ - Get the addresses of the target tokens. - - Parameters - ---------- - static_pool_data : pd.DataFrame - The static pool data. - target_tokens : List - The target tokens. - - Returns - ------- - List - The addresses of the target tokens. - - """ - # Get the addresses of the target tokens - target_token_addresses = [] - if target_tokens: - for token in target_tokens: - target_token_addresses = ( - target_token_addresses - + static_pool_data[static_pool_data["tkn0_address"] == token][ - "tkn0_address" - ].tolist() - ) - target_token_addresses = ( - target_token_addresses - + static_pool_data[static_pool_data["tkn1_address"] == token][ - "tkn1_address" - ].tolist() - ) - target_token_addresses = list(set(target_token_addresses)) - return target_token_addresses - - def get_current_block( last_block: int, mgr: Any, diff --git a/main.py b/main.py index 6ba36805d..8a4e42e5d 100644 --- a/main.py +++ b/main.py @@ -47,7 +47,6 @@ get_start_block, set_network_to_mainnet_if_replay, set_network_to_tenderly_if_replay, - handle_target_token_addresses, get_current_block, handle_tenderly_event_exchanges, handle_static_pools_update, @@ -255,10 +254,6 @@ def main(args: argparse.Namespace) -> None: cfg, exchanges, args.blockchain, args.static_pool_data_filename, args.read_only ) - target_token_addresses = handle_target_token_addresses( - static_pool_data, args.target_tokens - ) - # Break if timeout is hit to test the bot flags if args.timeout == 1: cfg.logger.info("Timeout to test the bot flags") @@ -284,7 +279,7 @@ def main(args: argparse.Namespace) -> None: solidly_v2_event_mappings=solidly_v2_event_mappings, tokens=tokens.to_dict(orient="records"), replay_from_block=args.replay_from_block, - target_tokens=target_token_addresses, + target_tokens=args.target_tokens, tenderly_fork_id=args.tenderly_fork_id, tenderly_event_exchanges=tenderly_event_exchanges, w3_tenderly=w3_tenderly, From d2d8779a69b03884bdfa8507c601393cf53d695e Mon Sep 17 00:00:00 2001 From: Nicholas Welch Date: Wed, 8 May 2024 10:41:38 +1000 Subject: [PATCH 068/131] bugfix always add native wrapped gas infor to the token objects --- fastlane_bot/events/interface.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fastlane_bot/events/interface.py b/fastlane_bot/events/interface.py index cc7ab2888..a0f200db3 100644 --- a/fastlane_bot/events/interface.py +++ b/fastlane_bot/events/interface.py @@ -509,11 +509,11 @@ def populate_tokens(self): self.token_list[token.address] = token except AttributeError: pass - if self.ConfigObj.GAS_TKN_IN_FLASHLOAN_TOKENS: - native_gas_tkn = Token(symbol=self.ConfigObj.NATIVE_GAS_TOKEN_SYMBOL, address=self.ConfigObj.NATIVE_GAS_TOKEN_ADDRESS, decimals=18) - wrapped_gas_tkn = Token(symbol=self.ConfigObj.WRAPPED_GAS_TOKEN_SYMBOL, address=self.ConfigObj.WRAPPED_GAS_TOKEN_ADDRESS, decimals=18) - self.token_list[native_gas_tkn.address] = native_gas_tkn - self.token_list[wrapped_gas_tkn.address] = wrapped_gas_tkn + # native and wrapped gas token info populated everytime + native_gas_tkn = Token(symbol=self.ConfigObj.NATIVE_GAS_TOKEN_SYMBOL, address=self.ConfigObj.NATIVE_GAS_TOKEN_ADDRESS, decimals=18) + wrapped_gas_tkn = Token(symbol=self.ConfigObj.WRAPPED_GAS_TOKEN_SYMBOL, address=self.ConfigObj.WRAPPED_GAS_TOKEN_ADDRESS, decimals=18) + self.token_list[native_gas_tkn.address] = native_gas_tkn + self.token_list[wrapped_gas_tkn.address] = wrapped_gas_tkn def create_token(self, record: Dict[str, Any], prefix: str) -> Token: """ From 5ba114b5ee0b46feaf4bede66fe6aac62204eeee Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Thu, 9 May 2024 15:19:41 +0300 Subject: [PATCH 069/131] Remove the `GAS_TKN_IN_FLASHLOAN_TOKENS` flag --- fastlane_bot/config/network.py | 1 - fastlane_bot/events/interface.py | 5 ++--- fastlane_bot/events/utils.py | 4 ---- fastlane_bot/tests/test_034_Interface.py | 1 - 4 files changed, 2 insertions(+), 9 deletions(-) diff --git a/fastlane_bot/config/network.py b/fastlane_bot/config/network.py index 0a5593cf6..e144ffdac 100644 --- a/fastlane_bot/config/network.py +++ b/fastlane_bot/config/network.py @@ -280,7 +280,6 @@ class ConfigNetwork(ConfigBase): # FLAGS ####################################################################################### - GAS_TKN_IN_FLASHLOAN_TOKENS = None IS_NO_FLASHLOAN_AVAILABLE = False # HOOKS diff --git a/fastlane_bot/events/interface.py b/fastlane_bot/events/interface.py index a0f200db3..1672cfafc 100644 --- a/fastlane_bot/events/interface.py +++ b/fastlane_bot/events/interface.py @@ -492,9 +492,8 @@ def get_tokens(self) -> List[Token]: token_set.add(self.create_token(record, f"tkn{str(idx)}_")) except AttributeError: pass - if self.ConfigObj.GAS_TKN_IN_FLASHLOAN_TOKENS: - token_set.add(Token(symbol=self.ConfigObj.NATIVE_GAS_TOKEN_SYMBOL, address=self.ConfigObj.NATIVE_GAS_TOKEN_ADDRESS, decimals=18)) - token_set.add(Token(symbol=self.ConfigObj.WRAPPED_GAS_TOKEN_SYMBOL, address=self.ConfigObj.WRAPPED_GAS_TOKEN_ADDRESS, decimals=18)) + token_set.add(Token(symbol=self.ConfigObj.NATIVE_GAS_TOKEN_SYMBOL, address=self.ConfigObj.NATIVE_GAS_TOKEN_ADDRESS, decimals=18)) + token_set.add(Token(symbol=self.ConfigObj.WRAPPED_GAS_TOKEN_SYMBOL, address=self.ConfigObj.WRAPPED_GAS_TOKEN_ADDRESS, decimals=18)) return list(token_set) def populate_tokens(self): diff --git a/fastlane_bot/events/utils.py b/fastlane_bot/events/utils.py index 154683b69..719ebf09b 100644 --- a/fastlane_bot/events/utils.py +++ b/fastlane_bot/events/utils.py @@ -637,10 +637,6 @@ def get_config( cfg.LIMIT_BANCOR3_FLASHLOAN_TOKENS = limit_bancor3_flashloan_tokens cfg.DEFAULT_MIN_PROFIT_GAS_TOKEN = Decimal(default_min_profit_gas_token) - cfg.GAS_TKN_IN_FLASHLOAN_TOKENS = ( - cfg.NATIVE_GAS_TOKEN_ADDRESS in flashloan_tokens - or cfg.WRAPPED_GAS_TOKEN_ADDRESS in flashloan_tokens - ) return cfg diff --git a/fastlane_bot/tests/test_034_Interface.py b/fastlane_bot/tests/test_034_Interface.py index 8b7f3dea8..82a98ee87 100644 --- a/fastlane_bot/tests/test_034_Interface.py +++ b/fastlane_bot/tests/test_034_Interface.py @@ -35,7 +35,6 @@ cfg_mock = Mock() cfg_mock.logger = MagicMock() -cfg_mock.GAS_TKN_IN_FLASHLOAN_TOKENS = False qi = QueryInterface(mgr=None, ConfigObj=cfg_mock) qi.state = [{'exchange_name': 'uniswap_v2', 'address': '0x123', 'tkn0_key': 'TKN-0x123', 'tkn1_key': 'TKN-0x456', 'pair_name': 'Pair-0x789', 'liquidity': 10}, {'exchange_name': 'sushiswap_v2', 'address': '0xabc', 'tkn0_key': 'TKN-0xabc', 'tkn1_key': 'TKN-0xdef', 'pair_name': 'Pair-0xghi', 'liquidity': 0}] From 99b702aabfab76d0e6c9a06552f03f575eed9868 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Tue, 7 May 2024 23:32:47 +0200 Subject: [PATCH 070/131] refactor: events --- .gitignore | 2 + .../events/async_event_update_utils.py | 9 +-- fastlane_bot/events/exchanges/balancer.py | 8 ++- fastlane_bot/events/exchanges/bancor_pol.py | 20 ++++-- fastlane_bot/events/exchanges/bancor_v2.py | 22 +++--- fastlane_bot/events/exchanges/bancor_v3.py | 22 ++++-- fastlane_bot/events/exchanges/base.py | 7 +- fastlane_bot/events/exchanges/carbon_v1.py | 31 +++++++-- fastlane_bot/events/exchanges/solidly_v2.py | 9 ++- fastlane_bot/events/exchanges/uniswap_v2.py | 8 ++- fastlane_bot/events/exchanges/uniswap_v3.py | 8 ++- fastlane_bot/events/interfaces/event.py | 27 ++++++++ .../events/interfaces/subscription.py | 46 +++++++++++++ fastlane_bot/events/managers/base.py | 49 ++++++------- fastlane_bot/events/managers/contracts.py | 7 +- fastlane_bot/events/managers/manager.py | 46 +++++++++---- fastlane_bot/events/pools/balancer.py | 4 +- fastlane_bot/events/pools/bancor_pol.py | 15 ++-- fastlane_bot/events/pools/bancor_v2.py | 17 ++--- fastlane_bot/events/pools/bancor_v3.py | 16 ++--- fastlane_bot/events/pools/base.py | 14 ++-- fastlane_bot/events/pools/carbon_v1.py | 38 ++++------ fastlane_bot/events/pools/solidly_v2.py | 12 ++-- fastlane_bot/events/pools/uniswap_v2.py | 14 ++-- fastlane_bot/events/pools/uniswap_v3.py | 16 ++--- fastlane_bot/events/utils.py | 69 ++++++++----------- 26 files changed, 337 insertions(+), 199 deletions(-) create mode 100644 fastlane_bot/events/interfaces/event.py create mode 100644 fastlane_bot/events/interfaces/subscription.py diff --git a/.gitignore b/.gitignore index 5e3d05b03..a35a7e42a 100644 --- a/.gitignore +++ b/.gitignore @@ -73,3 +73,5 @@ logs/* missing_tokens_df.csv tokens_and_fee_df.csv fastlane_bot/tests/nbtest/* + +.python-version diff --git a/fastlane_bot/events/async_event_update_utils.py b/fastlane_bot/events/async_event_update_utils.py index bbfa99273..a847599d0 100644 --- a/fastlane_bot/events/async_event_update_utils.py +++ b/fastlane_bot/events/async_event_update_utils.py @@ -27,6 +27,7 @@ from fastlane_bot.events.async_utils import get_contract_chunks from fastlane_bot.events.utils import update_pools_from_events from fastlane_bot.events.pools.utils import get_pool_cid +from .interfaces.event import Event nest_asyncio.apply() @@ -89,7 +90,7 @@ async def _get_missing_tkns(mgr: Any, c: List[Dict[str, Any]]) -> pd.DataFrame: return pd.concat(vals) -async def _get_token_and_fee(mgr: Any, exchange_name: str, ex: Any, address: str, contract: AsyncContract, event: Any): +async def _get_token_and_fee(mgr: Any, exchange_name: str, ex: Any, address: str, contract: AsyncContract, event: Event): """ This function uses the exchange object to get the tokens and fee for a given pool. @@ -97,7 +98,7 @@ async def _get_token_and_fee(mgr: Any, exchange_name: str, ex: Any, address: str ex(Any): The exchange object address(str): The pool address contract(AsyncContract): The contract object - event(Any): The event object + event(Event): The event object Returns: The tokens and fee info for the pool @@ -119,7 +120,7 @@ async def _get_token_and_fee(mgr: Any, exchange_name: str, ex: Any, address: str elif tkn1 == mgr.cfg.BNT_ADDRESS: tkn0 = connector_token - strategy_id = 0 if not ex.is_carbon_v1_fork else str(event["args"]["id"]) + strategy_id = 0 if not ex.is_carbon_v1_fork else str(event.args["id"]) pool_info = { "exchange_name": exchange_name, "address": address, @@ -319,7 +320,7 @@ def _get_pool_contracts(mgr: Any) -> List[Dict[str, Any]]: exchange_name = mgr.exchange_name_from_event(event) ex = mgr.exchanges[exchange_name] abi = ex.get_abi() - address = event["address"] + address = event.address contracts.append( { "exchange_name": exchange_name, diff --git a/fastlane_bot/events/exchanges/balancer.py b/fastlane_bot/events/exchanges/balancer.py index 01383cc51..791180f0c 100644 --- a/fastlane_bot/events/exchanges/balancer.py +++ b/fastlane_bot/events/exchanges/balancer.py @@ -17,8 +17,9 @@ from web3.contract import Contract from fastlane_bot.data.abi import BALANCER_VAULT_ABI, BALANCER_POOL_ABI_V1 -from fastlane_bot.events.exchanges.base import Exchange -from fastlane_bot.events.pools.base import Pool +from ..exchanges.base import Exchange +from ..pools.base import Pool +from ..interfaces.subscription import Subscription @dataclass @@ -47,6 +48,9 @@ def get_pool_abi(self): def get_events(self, contract: Contract) -> List[Type[Contract]]: return [contract.events.AuthorizerChanged] + def get_subscriptions(self, contract: Contract) -> List[Subscription]: + return [] + async def get_fee(self, pool_id: str, contract: Contract) -> Tuple[str, float]: pool = self.get_pool(pool_id) if pool: diff --git a/fastlane_bot/events/exchanges/bancor_pol.py b/fastlane_bot/events/exchanges/bancor_pol.py index 1211cc5cc..4e40c7397 100644 --- a/fastlane_bot/events/exchanges/bancor_pol.py +++ b/fastlane_bot/events/exchanges/bancor_pol.py @@ -17,9 +17,11 @@ from web3.contract import Contract from fastlane_bot.data.abi import BANCOR_POL_ABI -from fastlane_bot.events.exchanges.base import Exchange -from fastlane_bot.events.pools.base import Pool from fastlane_bot import Config +from ..exchanges.base import Exchange +from ..pools.base import Pool +from ..interfaces.event import Event +from ..interfaces.subscription import Subscription @dataclass @@ -46,14 +48,20 @@ def get_factory_abi(self): def get_events(self, contract: Contract) -> List[Type[Contract]]: return [contract.events.TokenTraded, contract.events.TradingEnabled] + def get_subscriptions(self, contract: Contract) -> List[Subscription]: + return [ + Subscription(contract.events.TokenTraded), + Subscription(contract.events.TradingEnabled), + ] + async def get_fee(self, address: str, contract: Contract) -> Tuple[str, float]: return "0.000", 0.000 - async def get_tkn0(self, address: str, contract: Contract, event: Any) -> str: - return event["args"]["token"] + async def get_tkn0(self, address: str, contract: Contract, event: Event) -> str: + return event.args["token"] - async def get_tkn1(self, address: str, contract: Contract, event: Any) -> str: - return self.ETH_ADDRESS if event["args"]["token"] not in self.ETH_ADDRESS else self.BNT_ADDRESS + async def get_tkn1(self, address: str, contract: Contract, event: Event) -> str: + return self.ETH_ADDRESS if event.args["token"] not in self.ETH_ADDRESS else self.BNT_ADDRESS def save_strategy( self, diff --git a/fastlane_bot/events/exchanges/bancor_v2.py b/fastlane_bot/events/exchanges/bancor_v2.py index 217b1297a..d1b4b149e 100644 --- a/fastlane_bot/events/exchanges/bancor_v2.py +++ b/fastlane_bot/events/exchanges/bancor_v2.py @@ -14,11 +14,14 @@ from dataclasses import dataclass from typing import List, Type, Tuple, Any +from web3 import AsyncWeb3 from web3.contract import Contract, AsyncContract from fastlane_bot.data.abi import BANCOR_V2_CONVERTER_ABI -from fastlane_bot.events.exchanges.base import Exchange -from fastlane_bot.events.pools.base import Pool +from ..exchanges.base import Exchange +from ..pools.base import Pool +from ..interfaces.event import Event +from ..interfaces.subscription import Subscription @dataclass @@ -44,6 +47,9 @@ def get_factory_abi(self): def get_events(self, contract: Contract) -> List[Type[Contract]]: return [contract.events.TokenRateUpdate] + def get_subscriptions(self, contract: Contract) -> List[Subscription]: + return [Subscription(contract.events.TokenRateUpdate)] + # def async convert_address(self, address: str, contract: Contract) -> str: # return @@ -59,15 +65,15 @@ async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, flo fee_float = float(fee) / 1e6 return fee, fee_float - async def get_tkn0(self, address: str, contract: Contract, event: Any) -> str: + async def get_tkn0(self, address: str, contract: Contract, event: Event) -> str: if event: - return event["args"]["_token1"] - return await contract.caller.reserveTokens()[0] + return event.args["_token1"] + return await contract.functions.reserveTokens()[0] - async def get_tkn1(self, address: str, contract: Contract, event: Any) -> str: + async def get_tkn1(self, address: str, contract: Contract, event: Event) -> str: if event: - return event["args"]["_token2"] - return await contract.caller.reserveTokens()[1] + return event.args["_token2"] + return await contract.functions.reserveTokens()[1] async def get_anchor(self, contract: Contract) -> str: return await contract.caller.anchor() diff --git a/fastlane_bot/events/exchanges/bancor_v3.py b/fastlane_bot/events/exchanges/bancor_v3.py index 7e0e5b20d..da2c76733 100644 --- a/fastlane_bot/events/exchanges/bancor_v3.py +++ b/fastlane_bot/events/exchanges/bancor_v3.py @@ -17,8 +17,13 @@ from web3.contract import Contract from fastlane_bot.data.abi import BANCOR_V3_POOL_COLLECTION_ABI -from fastlane_bot.events.exchanges.base import Exchange -from fastlane_bot.events.pools.base import Pool +from ..exchanges.base import Exchange +from ..pools.base import Pool +from ..interfaces.event import Event +from ..interfaces.subscription import Subscription + + +LIQUIDITY_UPDATED_TOPIC = "0x6e96dc5343d067ec486a9920e0304c3610ed05c65e45cc029d9b9fe7ecfa7620" @dataclass @@ -44,15 +49,18 @@ def get_factory_abi(self): def get_events(self, contract: Contract) -> List[Type[Contract]]: return [contract.events.TradingLiquidityUpdated] + def get_subscriptions(self, contract: Contract) -> List[Subscription]: + return [Subscription(contract.events.TradingLiquidityUpdated, LIQUIDITY_UPDATED_TOPIC)] + async def get_fee(self, address: str, contract: Contract) -> Tuple[str, float]: return "0.000", 0.000 - async def get_tkn0(self, address: str, contract: Contract, event: Any) -> str: + async def get_tkn0(self, address: str, contract: Contract, event: Event) -> str: return self.BNT_ADDRESS - async def get_tkn1(self, address: str, contract: Contract, event: Any) -> str: + async def get_tkn1(self, address: str, contract: Contract, event: Event) -> str: return ( - event["args"]["pool"] - if event["args"]["pool"] != self.BNT_ADDRESS - else event["args"]["tkn_address"] + event.args["pool"] + if event.args["pool"] != self.BNT_ADDRESS + else event.args["tkn_address"] ) diff --git a/fastlane_bot/events/exchanges/base.py b/fastlane_bot/events/exchanges/base.py index a63c7ed29..ed641d974 100644 --- a/fastlane_bot/events/exchanges/base.py +++ b/fastlane_bot/events/exchanges/base.py @@ -17,7 +17,8 @@ from web3.contract import Contract, AsyncContract from fastlane_bot.config.constants import CARBON_V1_NAME -from fastlane_bot.events.pools.base import Pool +from ..pools.base import Pool +from ..interfaces.subscription import Subscription @dataclass @@ -96,6 +97,10 @@ def get_events(self, contract: Contract) -> List[Type[Contract]]: """ pass + @abstractmethod + def get_subscriptions(self, contract: Contract) -> List[Subscription]: + ... + @staticmethod @abstractmethod async def get_fee(address: str, contract: AsyncContract) -> float: diff --git a/fastlane_bot/events/exchanges/carbon_v1.py b/fastlane_bot/events/exchanges/carbon_v1.py index 3dcf93a98..2957e04cf 100644 --- a/fastlane_bot/events/exchanges/carbon_v1.py +++ b/fastlane_bot/events/exchanges/carbon_v1.py @@ -18,9 +18,16 @@ from web3.contract import Contract from fastlane_bot.data.abi import CARBON_CONTROLLER_ABI -from fastlane_bot.events.exchanges.base import Exchange -from fastlane_bot.events.pools.base import Pool -from fastlane_bot.events.pools.utils import get_pool_cid +from ..exchanges.base import Exchange +from ..pools.base import Pool +from ..interfaces.event import Event +from ..interfaces.subscription import Subscription +from ..pools.utils import get_pool_cid + + +STRATEGY_CREATED_TOPIC = "0xff24554f8ccfe540435cfc8854831f8dcf1cf2068708cfaf46e8b52a4ccc4c8d" +STRATEGY_UPDATED_TOPIC = "0x720da23a5c920b1d8827ec83c4d3c4d90d9419eadb0036b88cb4c2ffa91aef7d" +STRATEGY_DELETED_TOPIC = "0x4d5b6e0627ea711d8e9312b6ba56f50e0b51d41816fd6fd38643495ac81d38b6" @dataclass @@ -73,6 +80,16 @@ def get_events(self, contract: Contract) -> List[Type[Contract]]: contract.events.PairCreated, ] if self.exchange_initialized else [] + def get_subscriptions(self, contract: Contract) -> List[Subscription]: + return [ + Subscription(contract.events.StrategyCreated, STRATEGY_CREATED_TOPIC), + Subscription(contract.events.StrategyUpdated, STRATEGY_UPDATED_TOPIC), + Subscription(contract.events.StrategyDeleted, STRATEGY_DELETED_TOPIC), + Subscription(contract.events.PairTradingFeePPMUpdated), + Subscription(contract.events.TradingFeePPMUpdated), + Subscription(contract.events.PairCreated), + ] + async def get_fee( self, address: str, contract: Contract ) -> Tuple[str, float]: @@ -94,7 +111,7 @@ async def get_fee( fee = await contract.tradingFeePPM() return f"{fee}", fee / 1e6 - async def get_tkn0(self, address: str, contract: Contract, event: Any) -> str: + async def get_tkn0(self, address: str, contract: Contract, event: Event) -> str: """ Get the token0 address from the contract or event. @@ -116,9 +133,9 @@ async def get_tkn0(self, address: str, contract: Contract, event: Any) -> str: if event is None: return await contract.caller.token0() else: - return event["args"]["token0"] + return event.args["token0"] - async def get_tkn1(self, address: str, contract: Contract, event: Any) -> str: + async def get_tkn1(self, address: str, contract: Contract, event: Event) -> str: """ Get the token1 address from the contract or event. @@ -140,7 +157,7 @@ async def get_tkn1(self, address: str, contract: Contract, event: Any) -> str: if event is None: return await contract.caller.token1() else: - return event["args"]["token1"] + return event.args["token1"] def delete_strategy(self, id: str): """ diff --git a/fastlane_bot/events/exchanges/solidly_v2.py b/fastlane_bot/events/exchanges/solidly_v2.py index 0197f5315..d6f5aa02a 100644 --- a/fastlane_bot/events/exchanges/solidly_v2.py +++ b/fastlane_bot/events/exchanges/solidly_v2.py @@ -19,8 +19,10 @@ from fastlane_bot.data.abi import SOLIDLY_V2_POOL_ABI, VELOCIMETER_V2_FACTORY_ABI, SOLIDLY_V2_FACTORY_ABI, \ SCALE_V2_FACTORY_ABI, CLEOPATRA_V2_FACTORY_ABI, LYNEX_V2_FACTORY_ABI, NILE_V2_FACTORY_ABI, \ XFAI_V0_FACTORY_ABI, XFAI_V0_CORE_ABI, XFAI_V0_POOL_ABI -from fastlane_bot.events.exchanges.base import Exchange -from fastlane_bot.events.pools.base import Pool +from ..exchanges.base import Exchange +from ..pools.base import Pool +from ..interfaces.subscription import Subscription + async def _get_fee_1(address: str, contract: Contract, factory_contract: Contract) -> int: return await factory_contract.caller.getFee(address) @@ -104,6 +106,9 @@ def get_factory_abi(self): def get_events(self, contract: Contract) -> List[Type[Contract]]: return [contract.events.Sync] if self.exchange_initialized else [] + def get_subscriptions(self, contract: Contract) -> List[Subscription]: + return [Subscription(contract.events.Sync)] + async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, float]: exchange_info = EXCHANGE_INFO[self.exchange_name] fee = await exchange_info["get_fee"](address, contract, self.factory_contract) diff --git a/fastlane_bot/events/exchanges/uniswap_v2.py b/fastlane_bot/events/exchanges/uniswap_v2.py index 198ce4a2f..870b938bf 100644 --- a/fastlane_bot/events/exchanges/uniswap_v2.py +++ b/fastlane_bot/events/exchanges/uniswap_v2.py @@ -17,8 +17,9 @@ from web3.contract import Contract, AsyncContract from fastlane_bot.data.abi import UNISWAP_V2_POOL_ABI, UNISWAP_V2_FACTORY_ABI -from fastlane_bot.events.exchanges.base import Exchange -from fastlane_bot.events.pools.base import Pool +from ..exchanges.base import Exchange +from ..pools.base import Pool +from ..interfaces.subscription import Subscription @dataclass @@ -49,6 +50,9 @@ def get_abi(self): def get_events(self, contract: Contract) -> List[Type[Contract]]: return [contract.events.Sync] if self.exchange_initialized else [] + def get_subscriptions(self, contract: Contract) -> List[Subscription]: + return [Subscription(contract.events.Sync)] + async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, float]: return self.fee, self.fee_float diff --git a/fastlane_bot/events/exchanges/uniswap_v3.py b/fastlane_bot/events/exchanges/uniswap_v3.py index 97870bf68..2136a32a2 100644 --- a/fastlane_bot/events/exchanges/uniswap_v3.py +++ b/fastlane_bot/events/exchanges/uniswap_v3.py @@ -18,8 +18,9 @@ from fastlane_bot.config.constants import AGNI_V3_NAME, PANCAKESWAP_V3_NAME, FUSIONX_V3_NAME, ECHODEX_V3_NAME, SECTA_V3_NAME from fastlane_bot.data.abi import UNISWAP_V3_POOL_ABI, UNISWAP_V3_FACTORY_ABI, PANCAKESWAP_V3_POOL_ABI -from fastlane_bot.events.exchanges.base import Exchange -from fastlane_bot.events.pools.base import Pool +from ..exchanges.base import Exchange +from ..pools.base import Pool +from ..interfaces.subscription import Subscription @dataclass @@ -45,6 +46,9 @@ def get_factory_abi(self): def get_events(self, contract: Contract) -> List[Type[Contract]]: return [contract.events.Swap] if self.exchange_initialized else [] + def get_subscriptions(self, contract: Contract) -> List[Subscription]: + return [Subscription(contract.events.Swap)] + async def get_fee(self, address: str, contract: Contract) -> Tuple[str, float]: fee = await contract.caller.fee() fee_float = float(fee) / 1e6 diff --git a/fastlane_bot/events/interfaces/event.py b/fastlane_bot/events/interfaces/event.py new file mode 100644 index 000000000..98bb5c2fc --- /dev/null +++ b/fastlane_bot/events/interfaces/event.py @@ -0,0 +1,27 @@ +from dataclasses import dataclass +from typing import Any, Dict + + +@dataclass +class Event: + args: Dict[str, Any] + event: str + log_index: int + transaction_index: int + transaction_hash: str + address: str + block_hash: str + block_number: int + + @classmethod + def from_dict(cls, data): + return cls( + args=data["args"], + event=data["event"], + log_index=data["logIndex"], + transaction_index=data["transactionIndex"], + transaction_hash=data["transactionHash"], + address=data["address"], + block_hash=data["blockHash"], + block_number=data["blockNumber"], + ) diff --git a/fastlane_bot/events/interfaces/subscription.py b/fastlane_bot/events/interfaces/subscription.py new file mode 100644 index 000000000..5d78bf8ab --- /dev/null +++ b/fastlane_bot/events/interfaces/subscription.py @@ -0,0 +1,46 @@ +from typing import Optional + +from web3 import AsyncWeb3, Web3 +from web3.contract.contract import ContractEvent + +from ..utils import complex_handler +from .event import Event + + +def _get_event_topic(event): + abi = event().abi + topic = Web3.keccak(text=f'{abi["name"]}({",".join([arg["type"] for arg in abi["inputs"]])})') + return topic.hex() + + +class Subscription: + def __init__(self, event: ContractEvent, topic: Optional[str] = None): + self._event = event + self._topic = _get_event_topic(event) if topic is None else topic + self._subscription_id = None + self._latest_event_index = (-1, -1) # (block_number, block_index) + + async def subscribe(self, w3: AsyncWeb3): + self._subscription_id = await w3.eth.subscribe("logs", {"topics": [self._topic]}) + + @property + def subscription_id(self): + return self._subscription_id + + def process_log(self, log) -> Optional[Event]: + if self._is_event_latest(log): + self._latest_event_index = (log["blockNumber"], log["transactionIndex"]) + return self._parse_log(log) + else: + return None + + def _parse_log(self, log) -> Event: + try: + event_data = complex_handler(self._event().process_log(log)) + except: + print(log) + raise + return Event.from_dict(event_data) + + def _is_event_latest(self, event) -> bool: + return (event["blockNumber"], event["transactionIndex"]) > self._latest_event_index diff --git a/fastlane_bot/events/managers/base.py b/fastlane_bot/events/managers/base.py index becf27d89..cf85d906a 100644 --- a/fastlane_bot/events/managers/base.py +++ b/fastlane_bot/events/managers/base.py @@ -23,6 +23,7 @@ from fastlane_bot.events.exchanges.base import Exchange from fastlane_bot.events.pools.utils import get_pool_cid from fastlane_bot.events.pools import pool_factory +from ..interfaces.event import Event @dataclass @@ -241,13 +242,13 @@ def get_fee_pairs( ) return fee_pairs - def exchange_name_from_event(self, event: Dict[str, Any]) -> str: + def exchange_name_from_event(self, event: Event) -> str: """ Get the exchange name from the event. Parameters ---------- - event : Dict[str, Any] + event : Event The event. Returns @@ -255,8 +256,8 @@ def exchange_name_from_event(self, event: Dict[str, Any]) -> str: str The exchange name. """ - if 'id' in event['args']: - carbon_controller_address = event['address'] + if 'id' in event.args: + carbon_controller_address = event.address for ex in self.cfg.CARBON_CONTROLLER_MAPPING: if self.cfg.CARBON_CONTROLLER_MAPPING[ex] == carbon_controller_address: return ex @@ -270,7 +271,7 @@ def exchange_name_from_event(self, event: Dict[str, Any]) -> str: return None def check_forked_exchange_names( - self, exchange_name_default: str = None, address: str = None, event: Any = None + self, exchange_name_default: str = None, address: str = None, event: Event = None ) -> str: """ Check the forked exchange names. If the exchange name is forked (Sushiswap from UniswapV2, etc) return the @@ -282,7 +283,7 @@ def check_forked_exchange_names( The default exchange name. address : str, optional The address. - event : Any, optional + event : Event, optional The event. Returns @@ -778,11 +779,11 @@ def validate_pool_info( if key != "strategy_id" and (pool_info is None or not pool_info): # Uses method in ContractsManager.add_pool_info_from_contract class to get pool info from contract pool_info = self.add_pool_info_from_contract( - address=addr, event=event, block_number=event["blockNumber"] + address=addr, event=event, block_number=event.block_number ) # if addr in self.cfg.CARBON_CONTROLLER_MAPPING: - # cid = event["args"]["id"] if event is not None else pool_info["strategy_id"] + # cid = event.args["id"] if event is not None else pool_info["strategy_id"] # # for pool in self.pool_data: # if pool["cid"] == cid: @@ -795,14 +796,14 @@ def validate_pool_info( return pool_info def get_key_and_value( - self, event: Dict[str, Any], addr: str, ex_name: str + self, event: Event, addr: str, ex_name: str ) -> Tuple[str, Any]: """ Get the key and value. Parameters ---------- - event : Dict[str, Any] + event : Event The event. addr : str The address. @@ -816,38 +817,38 @@ def get_key_and_value( """ if ex_name == "bancor_pol": - return "token", event["args"]["token"] + return "token", event.args["token"] if ex_name in self.cfg.CARBON_V1_FORKS: - info = {'exchange_name': ex_name, 'strategy_id': event["args"]["id"]} + info = {'exchange_name': ex_name, 'strategy_id': event.args["id"]} return "cid", get_pool_cid(info, self.cfg.CARBON_V1_FORKS) if ex_name in self.cfg.ALL_FORK_NAMES_WITHOUT_CARBON: return "address", addr if ex_name == "bancor_v2": return ("tkn0_address", "tkn1_address"), ( - event["args"]["_token1"], - event["args"]["_token2"], + event.args["_token1"], + event.args["_token2"], ) if ex_name == "bancor_v3": value = ( - event["args"]["tkn_address"] - if event["args"]["tkn_address"] != self.cfg.BNT_ADDRESS - else event["args"]["pool"] + event.args["tkn_address"] + if event.args["tkn_address"] != self.cfg.BNT_ADDRESS + else event.args["pool"] ) return "tkn1_address", value raise ValueError( f"[managers.base.get_key_and_value] Exchange {ex_name} not supported" ) - def handle_strategy_deleted(self, event: Dict[str, Any]) -> None: + def handle_strategy_deleted(self, event: Event) -> None: """ Handle the strategy deleted event. Parameters ---------- - event : Dict[str, Any] + event : Event The event. """ - strategy_id = event["args"]["id"] + strategy_id = event.args["id"] exchange_name = self.exchange_name_from_event(event) cids = [p["cid"] for p in self.pool_data if p["strategy_id"] == strategy_id and p["exchange_name"] == exchange_name] @@ -886,13 +887,13 @@ def pool_key_value_from_event(key: str, event: Dict[str, Any]) -> Any: The pool key value. """ if key == "cid": - return event["args"]["id"] + return event.args["id"] elif key == "address": - return event["address"] + return event.address elif key == "tkn0_address": - return event["args"]["token0"] + return event.args["token0"] elif key == "tkn1_address": - return event["args"]["token1"] + return event.args["token1"] print_events = [] diff --git a/fastlane_bot/events/managers/contracts.py b/fastlane_bot/events/managers/contracts.py index 03a4cd0c1..1355d4ba9 100644 --- a/fastlane_bot/events/managers/contracts.py +++ b/fastlane_bot/events/managers/contracts.py @@ -28,6 +28,7 @@ ) from fastlane_bot.events.managers.base import BaseManager from fastlane_bot.events.pools.utils import get_pool_cid +from ..interfaces.event import Event class ContractsManager(BaseManager): @@ -203,7 +204,7 @@ def add_pool_info_from_contract( self, exchange_name: str = None, address: str = None, - event: Any = None, + event: Event = None, tenderly_exchanges: List[str] = None, ) -> Dict[str, Any]: """ @@ -244,8 +245,8 @@ def add_pool_info_from_contract( t0_addr = self.exchanges[exchange_name].get_tkn0(address, pool_contract, event) t1_addr = self.exchanges[exchange_name].get_tkn1(address, pool_contract, event) - block_number = event["blockNumber"] - strategy_id = event["args"]["id"] if exchange_name in self.cfg.CARBON_V1_FORKS else None + block_number = event.block_number + strategy_id = event.args["id"] if exchange_name in self.cfg.CARBON_V1_FORKS else None temp_pool_info = { "exchange_name": exchange_name, "fee": f"{fee}", diff --git a/fastlane_bot/events/managers/manager.py b/fastlane_bot/events/managers/manager.py index 998356c53..7b80e66f6 100644 --- a/fastlane_bot/events/managers/manager.py +++ b/fastlane_bot/events/managers/manager.py @@ -18,33 +18,33 @@ from fastlane_bot.events.managers.contracts import ContractsManager from fastlane_bot.events.managers.events import EventManager from fastlane_bot.events.managers.pools import PoolManager -from fastlane_bot.events.pools.utils import get_pool_cid +from ..interfaces.event import Event class Manager(PoolManager, EventManager, ContractsManager): - def update_from_event(self, event: Dict[str, Any]): + def update_from_event(self, event: Event): """ Updates the state of the pool data from an event. StrategyCreated and StrategyUpdated events are handled as the "default" event types to process. Args: - event (Dict[str, Any]): The event to process. + event (Event): The event to process. """ ex_name = self.exchange_name_from_event(event) - if event["event"] in ["TradingFeePPMUpdated", "PairTradingFeePPMUpdated"]: + if event.event in ["TradingFeePPMUpdated", "PairTradingFeePPMUpdated"]: self.handle_trading_fee_updated() return - if event["event"] == "PairCreated": + if event.event == "PairCreated": self.set_carbon_v1_fee_pairs() return - if event["event"] == "StrategyDeleted": + if event.event == "StrategyDeleted": self.handle_strategy_deleted(event) return - addr = self.web3.to_checksum_address(event["address"]) + addr = self.web3.to_checksum_address(event.address) if not ex_name: return @@ -63,9 +63,7 @@ def update_from_event(self, event: Dict[str, Any]): pool_info["descr"] = self.pool_descr_from_info(pool_info) pool = self.get_or_init_pool(pool_info) - data = pool.update_from_event( - event or {}, pool.get_common_data(event, pool_info) - ) + data = pool.update_from_event(event, pool.get_common_data(event, pool_info)) self.update_pool_data(pool_info, data) def update_from_pool_info( @@ -166,18 +164,18 @@ def update( def handle_pair_trading_fee_updated( self, - event: Dict[str, Any] = None, + event: Event = None, ): """ Handle the pair trading fee updated event by updating the fee pairs and pool info for the given pair. Parameters ---------- - event : Dict[str, Any], optional + event : Event, optional The event, by default None. """ - tkn0_address = event["args"]["token0"] - tkn1_address = event["args"]["token1"] + tkn0_address = event.args["token0"] + tkn1_address = event.args["token1"] for exchange_name in self.cfg.CARBON_V1_FORKS: if exchange_name in self.exchanges: @@ -244,3 +242,23 @@ def handle_trading_fee_updated(self): pool["fee_float"] = pool["fee"] / 1e6 pool["descr"] = self.pool_descr_from_info(pool) self.pool_data[idx] = pool + + + def update_remaining_pools(self): + remaining_pools = [] + all_events = [pool[2] for pool in self.pools_to_add_from_contracts] + for event in all_events: + addr = self.web3.to_checksum_address(event.address) + ex_name = self.exchange_name_from_event(event) + if not ex_name: + self.cfg.logger.warning("[update_remaining_pools] ex_name not found from event") + continue + + key, key_value = self.get_key_and_value(event, addr, ex_name) + pool_info = self.get_pool_info(key, key_value, ex_name) + + if not pool_info: + remaining_pools.append((addr, ex_name, event, key, key_value)) + + random.shuffle(remaining_pools) + self.pools_to_add_from_contracts = remaining_pools diff --git a/fastlane_bot/events/pools/balancer.py b/fastlane_bot/events/pools/balancer.py index 80f894aea..6f8cd4b2b 100644 --- a/fastlane_bot/events/pools/balancer.py +++ b/fastlane_bot/events/pools/balancer.py @@ -15,7 +15,7 @@ from web3.contract import Contract from .base import Pool -from fastlane_bot import Config +from ..interfaces.event import Event @dataclass @@ -46,7 +46,7 @@ def event_matches_format( return False def update_from_event( - self, event_args: Dict[str, Any], data: Dict[str, Any] + self, event: Event, data: Dict[str, Any] ) -> Dict[str, Any]: """ See base class. diff --git a/fastlane_bot/events/pools/bancor_pol.py b/fastlane_bot/events/pools/bancor_pol.py index 58e58bc83..d0f1a6065 100644 --- a/fastlane_bot/events/pools/bancor_pol.py +++ b/fastlane_bot/events/pools/bancor_pol.py @@ -18,6 +18,7 @@ from fastlane_bot.data.abi import ERC20_ABI, BANCOR_POL_ABI from fastlane_bot.events.pools.base import Pool +from ..interfaces.event import Event from _decimal import Decimal @@ -41,14 +42,14 @@ def unique_key() -> str: @classmethod def event_matches_format( - cls, event: Dict[str, Any], static_pools: Dict[str, Any], exchange_name: str = None + cls, event: Event, static_pools: Dict[str, Any], exchange_name: str = None ) -> bool: """ Check if an event matches the format of a Bancor pol event. Parameters ---------- - event : Dict[str, Any] + event : Event The event arguments. Returns @@ -61,7 +62,7 @@ def event_matches_format( return ("token" in event_args) and ("token0" not in event_args) and (event_args['token'] == "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE") def update_from_event( - self, event_args: Dict[str, Any], data: Dict[str, Any] + self, event: Event, data: Dict[str, Any] ) -> Dict[str, Any]: """ This updates the pool balance from TokenTraded events. @@ -69,12 +70,12 @@ def update_from_event( See base class. """ - event_type = event_args["event"] + event_type = event.event if event_type in "TradingEnabled": - data["tkn0_address"] = event_args["args"]["token"] - data["tkn1_address"] = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" if event_args["args"]["token"] not in "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" else "0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C" + data["tkn0_address"] = event.args["token"] + data["tkn1_address"] = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" if event.args["token"] not in "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" else "0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C" - if event_args["args"]["token"] == self.state["tkn0_address"] and event_type in [ + if event.args["token"] == self.state["tkn0_address"] and event_type in [ "TokenTraded" ]: # *** Balance now updated from multicall *** diff --git a/fastlane_bot/events/pools/bancor_v2.py b/fastlane_bot/events/pools/bancor_v2.py index 68068bea7..b0f993418 100644 --- a/fastlane_bot/events/pools/bancor_v2.py +++ b/fastlane_bot/events/pools/bancor_v2.py @@ -15,6 +15,7 @@ from web3.contract import Contract from fastlane_bot.events.pools.base import Pool +from ..interfaces.event import Event @dataclass @@ -34,14 +35,14 @@ def unique_key() -> str: @classmethod def event_matches_format( - cls, event: Dict[str, Any], static_pools: Dict[str, Any], exchange_name: str = None + cls, event: Event, static_pools: Dict[str, Any], exchange_name: str = None ) -> bool: """ Check if an event matches the format of a Bancor v2 event. Parameters ---------- - event : Dict[str, Any] + event : Event The event arguments. Returns @@ -50,21 +51,21 @@ def event_matches_format( True if the event matches the format of a Bancor v3 event, False otherwise. """ - event_args = event["args"] + event_args = event.args return "_rateN" in event_args def update_from_event( - self, event_args: Dict[str, Any], data: Dict[str, Any] + self, event: Event, data: Dict[str, Any] ) -> Dict[str, Any]: """ **** IMPORTANT **** Bancor V2 pools emit 3 events per trade. Only one of them contains the new token balances we want. The one we want is the one where _token1 and _token2 match the token addresses of the pool. """ - data["tkn0_address"] = event_args["args"]["_token1"] - data["tkn1_address"] = event_args["args"]["_token2"] - data["tkn0_balance"] = event_args["args"]["_rateD"] - data["tkn1_balance"] = event_args["args"]["_rateN"] + data["tkn0_address"] = event.args["_token1"] + data["tkn1_address"] = event.args["_token2"] + data["tkn0_balance"] = event.args["_rateD"] + data["tkn1_balance"] = event.args["_rateN"] for key, value in data.items(): self.state[key] = value diff --git a/fastlane_bot/events/pools/bancor_v3.py b/fastlane_bot/events/pools/bancor_v3.py index 1b2281662..b266a819d 100644 --- a/fastlane_bot/events/pools/bancor_v3.py +++ b/fastlane_bot/events/pools/bancor_v3.py @@ -15,6 +15,7 @@ from web3.contract import Contract from .base import Pool +from ..interfaces.event import Event @dataclass @@ -34,14 +35,14 @@ def unique_key() -> str: @classmethod def event_matches_format( - cls, event: Dict[str, Any], static_pools: Dict[str, Any], exchange_name: str = None + cls, event: Event, static_pools: Dict[str, Any], exchange_name: str = None ) -> bool: """ Check if an event matches the format of a Bancor v3 event. Parameters ---------- - event : Dict[str, Any] + event : Event The event arguments. Returns @@ -50,20 +51,19 @@ def event_matches_format( True if the event matches the format of a Bancor v3 event, False otherwise. """ - event_args = event["args"] + event_args = event.args return "pool" in event_args def update_from_event( - self, event_args: Dict[str, Any], data: Dict[str, Any] + self, event: Event, data: Dict[str, Any] ) -> Dict[str, Any]: """ See base class. """ - event_args = event_args["args"] - if event_args["tkn_address"] == "0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C": - data["tkn0_balance"] = event_args["newLiquidity"] + if event.args["tkn_address"] == "0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C": + data["tkn0_balance"] = event.args["newLiquidity"] else: - data["tkn1_balance"] = event_args["newLiquidity"] + data["tkn1_balance"] = event.args["newLiquidity"] for key, value in data.items(): self.state[key] = value diff --git a/fastlane_bot/events/pools/base.py b/fastlane_bot/events/pools/base.py index e7f5870bb..4aa92999a 100644 --- a/fastlane_bot/events/pools/base.py +++ b/fastlane_bot/events/pools/base.py @@ -18,6 +18,8 @@ from web3 import Web3 from web3.contract import Contract +from ..interfaces.event import Event + @dataclass class Pool(ABC): @@ -61,37 +63,37 @@ def event_matches_format( @staticmethod def get_common_data( - event: Dict[str, Any], pool_info: Dict[str, Any] + event: Event, pool_info: Dict[str, Any] ) -> Dict[str, Any]: """ Get common (common to all Pool child classes) data from an event and pool info. Args: - event (Dict[str, Any]): The event data. + event (Event): The event data. pool_info (Dict[str, Any]): The pool information. Returns: Dict[str, Any]: A dictionary containing common data extracted from the event and pool info. """ return { - "last_updated_block": event["blockNumber"], + "last_updated_block": event.block_number, "timestamp": datetime.now().strftime("%H:%M:%S"), "pair_name": pool_info["pair_name"], "descr": pool_info["descr"], - "address": event["address"], + "address": event.address, } @staticmethod @abstractmethod def update_from_event( - event_args: Dict[str, Any], data: Dict[str, Any] + event: Event, data: Dict[str, Any] ) -> Dict[str, Any]: """ Update the pool state from an event. Parameters ---------- - event_args : Dict[str, Any] + event : Event The event arguments. data : Dict[str, Any] The pool data. diff --git a/fastlane_bot/events/pools/carbon_v1.py b/fastlane_bot/events/pools/carbon_v1.py index 4d62da546..184b13e83 100644 --- a/fastlane_bot/events/pools/carbon_v1.py +++ b/fastlane_bot/events/pools/carbon_v1.py @@ -15,6 +15,7 @@ from web3.contract import Contract from .base import Pool +from ..interfaces.event import Event from fastlane_bot.events.pools.utils import get_pool_cid @@ -36,34 +37,31 @@ def unique_key() -> str: @classmethod def event_matches_format( - cls, event: Dict[str, Any], static_pools: Dict[str, Any], exchange_name: str = None + cls, event: Event, static_pools: Dict[str, Any], exchange_name: str = None ) -> bool: """ see base class. """ - event_args = event["args"] + event_args = event.args return "order0" in event_args def update_from_event( - self, event_args: Dict[str, Any], data: Dict[str, Any] + self, event: Event, data: Dict[str, Any] ) -> Dict[str, Any]: """ See base class. """ - event_type = event_args["event"] - assert event_type not in ["TradingFeePPMUpdated", "PairTradingFeePPMUpdated"], ( + assert event.event not in ["TradingFeePPMUpdated", "PairTradingFeePPMUpdated"], ( "This event should not be " "handled by this class." ) - data = CarbonV1Pool.parse_event(data, event_args, event_type) + data = CarbonV1Pool.parse_event(data, event) data["router"] = self.router_address for key, value in data.items(): self.state[key] = value return data @staticmethod - def parse_event( - data: Dict[str, Any], event_args: Dict[str, Any], event_type: str - ) -> Dict[str, Any]: + def parse_event(data: Dict[str, Any], event: Event) -> Dict[str, Any]: """ Parse the event args into a dict. @@ -71,18 +69,16 @@ def parse_event( ---------- data : Dict[str, Any] The data to update. - event_args : Dict[str, Any] - The event arguments. - event_type : str - The event type. + event_args : Event + The event object. Returns ------- Dict[str, Any] The updated data. """ - order0, order1 = CarbonV1Pool.parse_orders(event_args, event_type) - data["strategy_id"] = event_args["args"].get("id") + order0, order1 = CarbonV1Pool.parse_orders(event) + data["strategy_id"] = event.args.get("id") if isinstance(order0, list) and isinstance(order1, list): data["y_0"] = order0[0] data["z_0"] = order0[1] @@ -105,9 +101,7 @@ def parse_event( return data @staticmethod - def parse_orders( - event_args: Dict[str, Any], event_type: str - ) -> Tuple[List[int], List[int]]: + def parse_orders(event: Event) -> Tuple[List[int], List[int]]: """ Parse the orders from the event args. If the event type is StrategyDeleted, then the orders are set to 0. @@ -115,17 +109,15 @@ def parse_orders( ---------- event_args : Dict[str, Any] The event arguments. - event_type : str - The event type. Returns ------- Tuple[List[int], List[int]] The parsed orders. """ - if event_type not in ["StrategyDeleted"]: - order0 = event_args["args"].get("order0") - order1 = event_args["args"].get("order1") + if event.event not in ["StrategyDeleted"]: + order0 = event.args.get("order0") + order1 = event.args.get("order1") else: order0 = [0, 0, 0, 0] order1 = [0, 0, 0, 0] diff --git a/fastlane_bot/events/pools/solidly_v2.py b/fastlane_bot/events/pools/solidly_v2.py index 61a1acf03..8ca967a7f 100644 --- a/fastlane_bot/events/pools/solidly_v2.py +++ b/fastlane_bot/events/pools/solidly_v2.py @@ -15,6 +15,7 @@ from web3.contract import Contract from fastlane_bot.events.pools.base import Pool +from ..interfaces.event import Event def _balances_A(contract: Contract) -> List[int]: return contract.caller.getReserves() @@ -88,21 +89,20 @@ def event_matches_format( """ Check if an event matches the format of a Uniswap v2 event. """ - event_args = event["args"] + event_args = event.args return ( "reserve0" in event_args - and event["address"] in static_pools[f"{exchange_name}_pools"] + and event.address in static_pools[f"{exchange_name}_pools"] ) def update_from_event( - self, event_args: Dict[str, Any], data: Dict[str, Any] + self, event: Event, data: Dict[str, Any] ) -> Dict[str, Any]: """ See base class. """ - event_args = event_args["args"] - data["tkn0_balance"] = event_args["reserve0"] - data["tkn1_balance"] = event_args["reserve1"] + data["tkn0_balance"] = event.args["reserve0"] + data["tkn1_balance"] = event.args["reserve1"] for key, value in data.items(): self.state[key] = value diff --git a/fastlane_bot/events/pools/uniswap_v2.py b/fastlane_bot/events/pools/uniswap_v2.py index 55549e89a..c48639f59 100644 --- a/fastlane_bot/events/pools/uniswap_v2.py +++ b/fastlane_bot/events/pools/uniswap_v2.py @@ -15,6 +15,7 @@ from web3.contract import Contract from fastlane_bot.events.pools.base import Pool +from ..interfaces.event import Event @dataclass @@ -41,26 +42,25 @@ def unique_key() -> str: @classmethod def event_matches_format( - cls, event: Dict[str, Any], static_pools: Dict[str, Any], exchange_name: str = None + cls, event: Event, static_pools: Dict[str, Any], exchange_name: str = None ) -> bool: """ Check if an event matches the format of a Uniswap v2 event. """ - event_args = event["args"] + event_args = event.args return ( "reserve0" in event_args - and event["address"] in static_pools[f"{exchange_name}_pools"] + and event.address in static_pools[f"{exchange_name}_pools"] ) def update_from_event( - self, event_args: Dict[str, Any], data: Dict[str, Any] + self, event: Event, data: Dict[str, Any] ) -> Dict[str, Any]: """ See base class. """ - event_args = event_args["args"] - data["tkn0_balance"] = event_args["reserve0"] - data["tkn1_balance"] = event_args["reserve1"] + data["tkn0_balance"] = event.args["reserve0"] + data["tkn1_balance"] = event.args["reserve1"] for key, value in data.items(): self.state[key] = value diff --git a/fastlane_bot/events/pools/uniswap_v3.py b/fastlane_bot/events/pools/uniswap_v3.py index 265c72296..06e67f65f 100644 --- a/fastlane_bot/events/pools/uniswap_v3.py +++ b/fastlane_bot/events/pools/uniswap_v3.py @@ -14,6 +14,7 @@ from web3.contract import Contract from fastlane_bot.events.pools.base import Pool +from ..interfaces.event import Event @dataclass @@ -34,27 +35,26 @@ def unique_key() -> str: @classmethod def event_matches_format( - cls, event: Dict[str, Any], static_pools: Dict[str, Any], exchange_name: str = None + cls, event: Event, static_pools: Dict[str, Any], exchange_name: str = None ) -> bool: """ Check if an event matches the format of a Uniswap v3 event. """ - event_args = event["args"] + event_args = event.args return ( "sqrtPriceX96" in event_args - and event["address"] in static_pools[f"{exchange_name}_pools"] + and event.address in static_pools[f"{exchange_name}_pools"] ) def update_from_event( - self, event_args: Dict[str, Any], data: Dict[str, Any] + self, event: Event, data: Dict[str, Any] ) -> Dict[str, Any]: """ See base class. """ - event_args = event_args["args"] - data["liquidity"] = event_args["liquidity"] - data["sqrt_price_q96"] = event_args["sqrtPriceX96"] - data["tick"] = event_args["tick"] + data["liquidity"] = event.args["liquidity"] + data["sqrt_price_q96"] = event.args["sqrtPriceX96"] + data["tick"] = event.args["tick"] for key, value in data.items(): self.state[key] = value diff --git a/fastlane_bot/events/utils.py b/fastlane_bot/events/utils.py index 719ebf09b..4f4f7aa92 100644 --- a/fastlane_bot/events/utils.py +++ b/fastlane_bot/events/utils.py @@ -31,15 +31,15 @@ from fastlane_bot.data.abi import FAST_LANE_CONTRACT_ABI from fastlane_bot.exceptions import ReadOnlyException from fastlane_bot.events.interface import QueryInterface -from fastlane_bot.events.managers.manager import Manager from fastlane_bot.helpers import TxHelpers from fastlane_bot.utils import safe_int +from .interfaces.event import Event def filter_latest_events( - mgr: Manager, events: List[List[AttributeDict]] -) -> List[AttributeDict]: + mgr: Any, events: List[Event] +) -> List[Event]: """ This function filters out the latest events for each pool. Given a nested list of events, it iterates through all events and keeps track of the latest event (i.e., with the highest block number) for each pool. The key used to identify each pool @@ -54,19 +54,16 @@ def filter_latest_events( List[AttributeDict]: A list of events, each representing the latest event for its corresponding pool. """ latest_entry_per_pool = {} - all_events = [event for event_list in events for event in event_list] # Handles the case where multiple pools are created in the same block - all_events.reverse() + events.reverse() bancor_v2_anchor_addresses = { pool["anchor"] for pool in mgr.pool_data if pool["exchange_name"] == "bancor_v2" } - for event in all_events: - pool_type = mgr.pool_type_from_exchange_name( - mgr.exchange_name_from_event(event) - ) + for event in events: + pool_type = mgr.pool_type_from_exchange_name(mgr.exchange_name_from_event(event)) if pool_type: key = pool_type.unique_key() else: @@ -74,43 +71,33 @@ def filter_latest_events( if key == "cid": key = "id" elif key == "tkn1_address": - if event["args"]["pool"] != mgr.cfg.BNT_ADDRESS: + if event.args["pool"] != mgr.cfg.BNT_ADDRESS: key = "pool" else: key = "tkn_address" - unique_key = event[key] if key in event else event["args"][key] + unique_key = event.address if key == "address" else event.args[key] + # unique_key = event.args[key] # Skip events for Bancor v2 anchors if ( key == "address" - and "_token1" in event["args"] + and "_token1" in event.args and ( - event["args"]["_token1"] in bancor_v2_anchor_addresses - or event["args"]["_token2"] in bancor_v2_anchor_addresses + event.args["_token1"] in bancor_v2_anchor_addresses + or event.args["_token2"] in bancor_v2_anchor_addresses ) ): continue if unique_key in latest_entry_per_pool: - if event["blockNumber"] > latest_entry_per_pool[unique_key]["blockNumber"]: + if event.block_number > latest_entry_per_pool[unique_key].block_number: latest_entry_per_pool[unique_key] = event - elif ( - event["blockNumber"] == latest_entry_per_pool[unique_key]["blockNumber"] - ): - if ( - event["transactionIndex"] - == latest_entry_per_pool[unique_key]["transactionIndex"] - ): - if ( - event["logIndex"] - > latest_entry_per_pool[unique_key]["logIndex"] - ): + elif event.block_number == latest_entry_per_pool[unique_key].block_number: + if event.transaction_index == latest_entry_per_pool[unique_key].transaction_index: + if event.log_index > latest_entry_per_pool[unique_key].log_index: latest_entry_per_pool[unique_key] = event - elif ( - event["transactionIndex"] - > latest_entry_per_pool[unique_key]["transactionIndex"] - ): + elif event.transaction_index > latest_entry_per_pool[unique_key].transaction_index: latest_entry_per_pool[unique_key] = event else: continue @@ -138,7 +125,7 @@ def complex_handler(obj: Any) -> Union[Dict, str, List, Set, Any]: If the input object does not match any of the specified types, it is returned as is. """ if isinstance(obj, AttributeDict): - return dict(obj) + return complex_handler(dict(obj)) elif isinstance(obj, HexBytes): return obj.hex() elif isinstance(obj, bytes): @@ -148,7 +135,7 @@ def complex_handler(obj: Any) -> Union[Dict, str, List, Set, Any]: elif isinstance(obj, (list, tuple)): return [complex_handler(i) for i in obj] elif isinstance(obj, set): - return list(obj) + return complex_handler(list(obj)) else: return obj @@ -806,7 +793,7 @@ def save_events_to_json( mgr.cfg.logger.debug(f"[events.utils.save_events_to_json] Saved events to {path}") -def update_pools_from_events(n_jobs: int, mgr: Any, latest_events: List[Any]): +def update_pools_from_events(n_jobs: int, mgr: Any, latest_events: List[Event]): """ Updates the pools with the given events. @@ -1216,14 +1203,12 @@ def get_latest_events( # Get all event filters, events, and flatten them events = [ - complex_handler(event) - for event in [ - complex_handler(event) - for event in get_all_events( - n_jobs, - get_event_filters(n_jobs, mgr, start_block, current_block), - ) - ] + Event.from_dict(complex_handler(event)) + for events in get_all_events( + n_jobs, + get_event_filters(n_jobs, mgr, start_block, current_block), + ) + for event in events ] # Filter out the latest events per pool, save them to disk, and update the pools @@ -1242,7 +1227,7 @@ def get_latest_events( if not pool_type.event_matches_format(event) ] - carbon_pol_events = [event for event in latest_events if "token" in event["args"]] + carbon_pol_events = [event for event in latest_events if "token" in event.args] mgr.cfg.logger.info( f"[events.utils.get_latest_events] Found {len(latest_events)} new events, {len(carbon_pol_events)} carbon_pol_events" ) From aff59023c9ff9c290a27ae78e9d553e0e22a8d3e Mon Sep 17 00:00:00 2001 From: Lesigh-3100 Date: Wed, 8 May 2024 16:09:33 +0300 Subject: [PATCH 071/131] Change event gathering from filters to get_logs --- fastlane_bot/events/event_gatherer.py | 50 +++++++++++++++++++ .../events/interfaces/subscription.py | 16 +++--- fastlane_bot/events/utils.py | 13 ++--- main.py | 6 ++- 4 files changed, 65 insertions(+), 20 deletions(-) create mode 100644 fastlane_bot/events/event_gatherer.py diff --git a/fastlane_bot/events/event_gatherer.py b/fastlane_bot/events/event_gatherer.py new file mode 100644 index 000000000..257482c59 --- /dev/null +++ b/fastlane_bot/events/event_gatherer.py @@ -0,0 +1,50 @@ +import time +from itertools import chain + +import asyncio +import nest_asyncio + +from typing import List, Any +from web3 import AsyncWeb3 + + +nest_asyncio.apply() + +class EventGatherer: + """ + The EventGatherer manages event gathering using eth.get_logs. + """ + + def __init__( + self, + w3: AsyncWeb3, + exchanges: Any, + event_contracts: Any, + ): + """ Initializes the EventManager. + Args: + manager: The Manager object + w3: The connected AsyncWeb3 object. + """ + self._w3 = w3 + self._subscriptions = [] + unique_topics = [] + + for exchange_name, exchange in exchanges.items(): + subscriptions = exchange.get_subscriptions(event_contracts[exchange_name]) + _unique_subscriptions = [] + for sub in subscriptions: + if sub.get_topic not in unique_topics: + unique_topics.append(sub.get_topic) + _unique_subscriptions.append(sub) + self._subscriptions += _unique_subscriptions + + def get_all_events(self, from_block: int, to_block: int): + results = asyncio.get_event_loop().run_until_complete(asyncio.gather(*[self._get_events_for_topic(from_block, to_block, sub) for sub in self._subscriptions])) + return list(chain.from_iterable(results)) + + async def _get_events_for_topic(self, from_block: int, to_block: int or str, subscription: Any): + events = await self._w3.eth.get_logs(filter_params={"fromBlock": from_block, "toBlock": to_block, "topics": [subscription.get_topic]}) + return [subscription.parse_log(event) for event in events] + + diff --git a/fastlane_bot/events/interfaces/subscription.py b/fastlane_bot/events/interfaces/subscription.py index 5d78bf8ab..be60aed02 100644 --- a/fastlane_bot/events/interfaces/subscription.py +++ b/fastlane_bot/events/interfaces/subscription.py @@ -27,14 +27,11 @@ async def subscribe(self, w3: AsyncWeb3): def subscription_id(self): return self._subscription_id - def process_log(self, log) -> Optional[Event]: - if self._is_event_latest(log): - self._latest_event_index = (log["blockNumber"], log["transactionIndex"]) - return self._parse_log(log) - else: - return None - - def _parse_log(self, log) -> Event: + @property + def get_topic(self): + return self._topic + + def parse_log(self, log) -> Event: try: event_data = complex_handler(self._event().process_log(log)) except: @@ -42,5 +39,4 @@ def _parse_log(self, log) -> Event: raise return Event.from_dict(event_data) - def _is_event_latest(self, event) -> bool: - return (event["blockNumber"], event["transactionIndex"]) > self._latest_event_index + diff --git a/fastlane_bot/events/utils.py b/fastlane_bot/events/utils.py index 4f4f7aa92..68f4c7921 100644 --- a/fastlane_bot/events/utils.py +++ b/fastlane_bot/events/utils.py @@ -34,6 +34,7 @@ from fastlane_bot.helpers import TxHelpers from fastlane_bot.utils import safe_int +from .event_gatherer import EventGatherer from .interfaces.event import Event @@ -1164,6 +1165,7 @@ def get_latest_events( start_block: int, cache_latest_only: bool, logging_path: str, + event_gatherer: EventGatherer ) -> List[Any]: """ Gets the latest events. @@ -1201,15 +1203,8 @@ def get_latest_events( f"[events.utils.get_latest_events] tenderly_events: {len(tenderly_events)}" ) - # Get all event filters, events, and flatten them - events = [ - Event.from_dict(complex_handler(event)) - for events in get_all_events( - n_jobs, - get_event_filters(n_jobs, mgr, start_block, current_block), - ) - for event in events - ] + # Get all events + events = event_gatherer.get_all_events(from_block=start_block, to_block=current_block) # Filter out the latest events per pool, save them to disk, and update the pools latest_events = filter_latest_events(mgr, events) diff --git a/main.py b/main.py index 8a4e42e5d..f2dce7d9c 100644 --- a/main.py +++ b/main.py @@ -5,7 +5,7 @@ (c) Copyright Bprotocol foundation 2023. Licensed under MIT """ - +from fastlane_bot.events.event_gatherer import EventGatherer from fastlane_bot.exceptions import ReadOnlyException, FlashloanUnavailableException from fastlane_bot.events.version_utils import check_version_requirements from fastlane_bot.tools.cpc import T @@ -301,6 +301,9 @@ def run(mgr, args, tenderly_uri=None) -> None: start_timeout = time.time() mainnet_uri = mgr.cfg.w3.provider.endpoint_uri handle_static_pools_update(mgr) + + event_gatherer = EventGatherer(w3=mgr.w3_async, exchanges=mgr.exchanges, event_contracts=mgr.event_contracts) + while True: try: # ensure 'last_updated_block' is in pool_data for all pools @@ -352,6 +355,7 @@ def run(mgr, args, tenderly_uri=None) -> None: start_block, args.cache_latest_only, args.logging_path, + event_gatherer ) ) iteration_start_time = time.time() From 87fc3d99057b05123964eb9d215f8944c0140b5a Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Thu, 9 May 2024 19:51:18 +0200 Subject: [PATCH 072/131] refactor --- fastlane_bot/events/event_gatherer.py | 27 +++++++++++-------- .../events/interfaces/subscription.py | 2 +- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/fastlane_bot/events/event_gatherer.py b/fastlane_bot/events/event_gatherer.py index 257482c59..989793716 100644 --- a/fastlane_bot/events/event_gatherer.py +++ b/fastlane_bot/events/event_gatherer.py @@ -1,15 +1,18 @@ -import time from itertools import chain import asyncio import nest_asyncio -from typing import List, Any from web3 import AsyncWeb3 +from web3.contract import Contract + +from .interfaces.subscription import Subscription +from .exchanges.base import Exchange nest_asyncio.apply() + class EventGatherer: """ The EventGatherer manages event gathering using eth.get_logs. @@ -18,8 +21,8 @@ class EventGatherer: def __init__( self, w3: AsyncWeb3, - exchanges: Any, - event_contracts: Any, + exchanges: dict[str, Exchange], + event_contracts: dict[str, Contract], ): """ Initializes the EventManager. Args: @@ -28,23 +31,25 @@ def __init__( """ self._w3 = w3 self._subscriptions = [] - unique_topics = [] + unique_topics = set() for exchange_name, exchange in exchanges.items(): subscriptions = exchange.get_subscriptions(event_contracts[exchange_name]) - _unique_subscriptions = [] for sub in subscriptions: if sub.get_topic not in unique_topics: - unique_topics.append(sub.get_topic) - _unique_subscriptions.append(sub) - self._subscriptions += _unique_subscriptions + unique_topics.add(sub.topic) + self._subscriptions.append(sub) def get_all_events(self, from_block: int, to_block: int): results = asyncio.get_event_loop().run_until_complete(asyncio.gather(*[self._get_events_for_topic(from_block, to_block, sub) for sub in self._subscriptions])) return list(chain.from_iterable(results)) - async def _get_events_for_topic(self, from_block: int, to_block: int or str, subscription: Any): - events = await self._w3.eth.get_logs(filter_params={"fromBlock": from_block, "toBlock": to_block, "topics": [subscription.get_topic]}) + async def _get_events_for_topic(self, from_block: int, to_block: int, subscription: Subscription): + events = await self._w3.eth.get_logs(filter_params={ + "fromBlock": from_block, + "toBlock": to_block, + "topics": [subscription.topic] + }) return [subscription.parse_log(event) for event in events] diff --git a/fastlane_bot/events/interfaces/subscription.py b/fastlane_bot/events/interfaces/subscription.py index be60aed02..660f45e0c 100644 --- a/fastlane_bot/events/interfaces/subscription.py +++ b/fastlane_bot/events/interfaces/subscription.py @@ -28,7 +28,7 @@ def subscription_id(self): return self._subscription_id @property - def get_topic(self): + def topic(self): return self._topic def parse_log(self, log) -> Event: From 18c1e701c410d37ee861bfb1502ccd5644e07b82 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Fri, 10 May 2024 11:32:33 +0300 Subject: [PATCH 073/131] fix: circular import --- fastlane_bot/events/interfaces/subscription.py | 2 -- fastlane_bot/events/utils.py | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/fastlane_bot/events/interfaces/subscription.py b/fastlane_bot/events/interfaces/subscription.py index 660f45e0c..b1165f757 100644 --- a/fastlane_bot/events/interfaces/subscription.py +++ b/fastlane_bot/events/interfaces/subscription.py @@ -38,5 +38,3 @@ def parse_log(self, log) -> Event: print(log) raise return Event.from_dict(event_data) - - diff --git a/fastlane_bot/events/utils.py b/fastlane_bot/events/utils.py index 68f4c7921..2577ba460 100644 --- a/fastlane_bot/events/utils.py +++ b/fastlane_bot/events/utils.py @@ -34,7 +34,6 @@ from fastlane_bot.helpers import TxHelpers from fastlane_bot.utils import safe_int -from .event_gatherer import EventGatherer from .interfaces.event import Event @@ -1165,7 +1164,7 @@ def get_latest_events( start_block: int, cache_latest_only: bool, logging_path: str, - event_gatherer: EventGatherer + event_gatherer: "EventGatherer" ) -> List[Any]: """ Gets the latest events. From 2b9dd4a8cd677b51cc67d68cc38b38e51e04f6d5 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Fri, 10 May 2024 12:39:07 +0300 Subject: [PATCH 074/131] fix: tests --- fastlane_bot/tests/test_033_Pools.py | 27 ++++++++++++------------ fastlane_bot/tests/test_035_Utils.py | 15 +++++++------ fastlane_bot/tests/test_036_Manager.py | 15 +++++++------ fastlane_bot/tests/test_037_Exchanges.py | 9 ++++---- 4 files changed, 35 insertions(+), 31 deletions(-) diff --git a/fastlane_bot/tests/test_033_Pools.py b/fastlane_bot/tests/test_033_Pools.py index d40a20074..26959204e 100644 --- a/fastlane_bot/tests/test_033_Pools.py +++ b/fastlane_bot/tests/test_033_Pools.py @@ -11,6 +11,7 @@ import json from fastlane_bot import Bot +from fastlane_bot.events.interfaces.event import Event from fastlane_bot.events.pools import BancorPolPool, BancorV2Pool, BancorV3Pool, CarbonV1Pool, SolidlyV2Pool, \ UniswapV2Pool, UniswapV3Pool from fastlane_bot.tools.cpc import ConstantProductCurve as CPC @@ -46,7 +47,7 @@ def test_test_uniswap_v2_pool(): # ------------------------------------------------------------ uniswap_v2_pool = UniswapV2Pool() - uniswap_v2_pool.update_from_event(setup_data['uniswap_v2_event'], {'cid': '0x', 'fee': '0.000', 'fee_float': 0.0, 'exchange_name': 'sushiswap_v2', 'reserve0': setup_data['uniswap_v2_event']['args']['reserve0'], 'reserve1': setup_data['uniswap_v2_event']['args']['reserve1'], 'tkn0_symbol': 'tkn0', 'tkn1_symbol': 'tkn1'}) + uniswap_v2_pool.update_from_event(Event.from_dict(setup_data['uniswap_v2_event']), {'cid': '0x', 'fee': '0.000', 'fee_float': 0.0, 'exchange_name': 'sushiswap_v2', 'reserve0': setup_data['uniswap_v2_event']['args']['reserve0'], 'reserve1': setup_data['uniswap_v2_event']['args']['reserve1'], 'tkn0_symbol': 'tkn0', 'tkn1_symbol': 'tkn1'}) assert (uniswap_v2_pool.state['tkn0_balance'] == setup_data['uniswap_v2_event']['args']['reserve0']) @@ -59,7 +60,7 @@ def test_test_solidly_v2_pool(): # ------------------------------------------------------------ solidly_v2_pool = SolidlyV2Pool() - solidly_v2_pool.update_from_event(setup_data['solidly_v2_event'], {'cid': '0x', 'fee': '0.000', 'fee_float': 0.0, 'exchange_name': 'velocimeter_v2', 'reserve0': setup_data['solidly_v2_event']['args']['reserve0'], 'reserve1': setup_data['solidly_v2_event']['args']['reserve1'], 'tkn0_symbol': 'tkn0', 'tkn1_symbol': 'tkn1'}) + solidly_v2_pool.update_from_event(Event.from_dict(setup_data['solidly_v2_event']), {'cid': '0x', 'fee': '0.000', 'fee_float': 0.0, 'exchange_name': 'velocimeter_v2', 'reserve0': setup_data['solidly_v2_event']['args']['reserve0'], 'reserve1': setup_data['solidly_v2_event']['args']['reserve1'], 'tkn0_symbol': 'tkn0', 'tkn1_symbol': 'tkn1'}) assert (solidly_v2_pool.state['tkn0_balance'] == setup_data['solidly_v2_event']['args']['reserve0']) @@ -75,7 +76,7 @@ def test_test_bancor_v2_pool(): bancor_v2_pool.state['tkn0_address'] = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' bancor_v2_pool.state['tkn1_address'] = '0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C' bancor_v2_pool.state['anchor']= '0xb1CD6e4153B2a390Cf00A6556b0fC1458C4A5533' - bancor_v2_pool.update_from_event(setup_data['bancor_v2_event'], {'cid': '0x', 'fee': '0.000', 'fee_float': 0.0, 'exchange_name': 'bancor_v2'}) + bancor_v2_pool.update_from_event(Event.from_dict(setup_data['bancor_v2_event']), {'cid': '0x', 'fee': '0.000', 'fee_float': 0.0, 'exchange_name': 'bancor_v2'}) assert (5698079648237338312679700 == setup_data['bancor_v2_event']['args']['_rateN']), f"expected {bancor_v2_pool.state['tkn0_balance']}, found {setup_data['bancor_v2_event']['args']['_rateN']}" assert (1404376232459809237924 == setup_data['bancor_v2_event']['args']['_rateD']), f"expected {bancor_v2_pool.state['tkn1_balance']}, found {setup_data['bancor_v2_event']['args']['_rateD']}" @@ -89,7 +90,7 @@ def test_test_pancakeswap_v2_pool(): # ------------------------------------------------------------ pancakeswap_v2_pool = UniswapV2Pool() - pancakeswap_v2_pool.update_from_event(setup_data['pancakeswap_v2_event'], {'cid': '0x', 'fee': '0.000', 'fee_float': 0.0, 'exchange_name': 'pancakeswap_v2', 'reserve0': setup_data['pancakeswap_v2_event']['args']['reserve0'], 'reserve1': setup_data['pancakeswap_v2_event']['args']['reserve1'], 'tkn0_symbol': 'tkn0', 'tkn1_symbol': 'tkn1'}) + pancakeswap_v2_pool.update_from_event(Event.from_dict(setup_data['pancakeswap_v2_event']), {'cid': '0x', 'fee': '0.000', 'fee_float': 0.0, 'exchange_name': 'pancakeswap_v2', 'reserve0': setup_data['pancakeswap_v2_event']['args']['reserve0'], 'reserve1': setup_data['pancakeswap_v2_event']['args']['reserve1'], 'tkn0_symbol': 'tkn0', 'tkn1_symbol': 'tkn1'}) assert (pancakeswap_v2_pool.state['tkn0_balance'] == setup_data['pancakeswap_v2_event']['args']['reserve0']) @@ -102,7 +103,7 @@ def test_test_uniswap_v3_pool(): # ------------------------------------------------------------ uniswap_v3_pool = UniswapV3Pool() - uniswap_v3_pool.update_from_event(setup_data['uniswap_v3_event'], {'cid': '0x', 'fee': '0.000', 'fee_float': 0.0, 'exchange_name': 'uniswap_v3', 'liquidity': setup_data['uniswap_v3_event']['args']['liquidity'], 'sqrtPriceX96': setup_data['uniswap_v3_event']['args']['sqrtPriceX96'], 'tick': setup_data['uniswap_v3_event']['args']['tick'], 'tkn0_symbol': 'tkn0', 'tkn1_symbol': 'tkn1'}) + uniswap_v3_pool.update_from_event(Event.from_dict(setup_data['uniswap_v3_event']), {'cid': '0x', 'fee': '0.000', 'fee_float': 0.0, 'exchange_name': 'uniswap_v3', 'liquidity': setup_data['uniswap_v3_event']['args']['liquidity'], 'sqrtPriceX96': setup_data['uniswap_v3_event']['args']['sqrtPriceX96'], 'tick': setup_data['uniswap_v3_event']['args']['tick'], 'tkn0_symbol': 'tkn0', 'tkn1_symbol': 'tkn1'}) assert (uniswap_v3_pool.state['liquidity'] == setup_data['uniswap_v3_event']['args']['liquidity']) assert (uniswap_v3_pool.state['sqrt_price_q96'] == setup_data['uniswap_v3_event']['args']['sqrtPriceX96']) @@ -116,7 +117,7 @@ def test_test_pancakeswap_v3_pool(): # ------------------------------------------------------------ pancakeswap_v3_pool = UniswapV3Pool() - pancakeswap_v3_pool.update_from_event(setup_data['pancakeswap_v3_event'], {'cid': '0x', 'fee': '0.000', 'fee_float': 0.0, 'exchange_name': 'pancakeswap_v3', 'liquidity': setup_data['pancakeswap_v3_event']['args']['liquidity'], 'sqrtPriceX96': setup_data['pancakeswap_v3_event']['args']['sqrtPriceX96'], 'tick': setup_data['pancakeswap_v3_event']['args']['tick'], 'tkn0_symbol': 'tkn0', 'tkn1_symbol': 'tkn1'}) + pancakeswap_v3_pool.update_from_event(Event.from_dict(setup_data['pancakeswap_v3_event']), {'cid': '0x', 'fee': '0.000', 'fee_float': 0.0, 'exchange_name': 'pancakeswap_v3', 'liquidity': setup_data['pancakeswap_v3_event']['args']['liquidity'], 'sqrtPriceX96': setup_data['pancakeswap_v3_event']['args']['sqrtPriceX96'], 'tick': setup_data['pancakeswap_v3_event']['args']['tick'], 'tkn0_symbol': 'tkn0', 'tkn1_symbol': 'tkn1'}) assert (pancakeswap_v3_pool.state['liquidity'] == setup_data['pancakeswap_v3_event']['args']['liquidity']) assert (pancakeswap_v3_pool.state['sqrt_price_q96'] == setup_data['pancakeswap_v3_event']['args']['sqrtPriceX96']) @@ -130,7 +131,7 @@ def test_test_bancor_v3_pool(): # ------------------------------------------------------------ bancor_v3_pool = BancorV3Pool() - bancor_v3_pool.update_from_event(setup_data['bancor_v3_event'], {'cid': '0x', 'fee': '0.000', 'fee_float': 0.0, 'exchange_name': 'bancor_v3', 'tkn0_balance': setup_data['bancor_v3_event']['args']['newLiquidity'], 'tkn1_balance': 0, 'tkn0_symbol': 'tkn0', 'tkn1_symbol': 'tkn1'}) + bancor_v3_pool.update_from_event(Event.from_dict(setup_data['bancor_v3_event']), {'cid': '0x', 'fee': '0.000', 'fee_float': 0.0, 'exchange_name': 'bancor_v3', 'tkn0_balance': setup_data['bancor_v3_event']['args']['newLiquidity'], 'tkn1_balance': 0, 'tkn0_symbol': 'tkn0', 'tkn1_symbol': 'tkn1'}) # ------------------------------------------------------------ @@ -142,7 +143,7 @@ def test_test_carbon_v1_pool_update(): # ------------------------------------------------------------ carbon_v1_pool = CarbonV1Pool() - carbon_v1_pool.update_from_event(setup_data['carbon_v1_event_create_for_update'], {}) + carbon_v1_pool.update_from_event(Event.from_dict(setup_data['carbon_v1_event_create_for_update']), {}) strat_id = setup_data['carbon_v1_event_update']['args']['id'] assert (strat_id == carbon_v1_pool.state['strategy_id']) assert (carbon_v1_pool.state['y_0'] == 0) @@ -153,7 +154,7 @@ def test_test_carbon_v1_pool_update(): assert (carbon_v1_pool.state['z_1'] == 0) assert (carbon_v1_pool.state['A_1'] == 0) assert (carbon_v1_pool.state['B_1'] == 0) - carbon_v1_pool.update_from_event(setup_data['carbon_v1_event_update'], {}) + carbon_v1_pool.update_from_event(Event.from_dict(setup_data['carbon_v1_event_update']), {}) assert (carbon_v1_pool.state['y_0'] == setup_data['carbon_v1_event_update']['args']['order0'][0]) assert (carbon_v1_pool.state['z_0'] == setup_data['carbon_v1_event_update']['args']['order0'][1]) assert (carbon_v1_pool.state['A_0'] == setup_data['carbon_v1_event_update']['args']['order0'][2]) @@ -172,7 +173,7 @@ def test_test_carbon_v1_pool_delete(): # ------------------------------------------------------------ carbon_v1_pool = CarbonV1Pool() - carbon_v1_pool.update_from_event(setup_data['carbon_v1_event_create_for_delete'], {}) + carbon_v1_pool.update_from_event(Event.from_dict(setup_data['carbon_v1_event_create_for_delete']), {}) strat_id = setup_data['carbon_v1_event_update']['args']['id'] assert (strat_id == carbon_v1_pool.state['strategy_id']) assert (carbon_v1_pool.state['y_0'] == setup_data['carbon_v1_event_delete']['args']['order0'][0]) @@ -183,7 +184,7 @@ def test_test_carbon_v1_pool_delete(): assert (carbon_v1_pool.state['z_1'] == setup_data['carbon_v1_event_delete']['args']['order1'][1]) assert (carbon_v1_pool.state['A_1'] == setup_data['carbon_v1_event_delete']['args']['order1'][2]) assert (carbon_v1_pool.state['B_1'] == setup_data['carbon_v1_event_delete']['args']['order1'][3]) - carbon_v1_pool.update_from_event(setup_data['carbon_v1_event_delete'], {}) + carbon_v1_pool.update_from_event(Event.from_dict(setup_data['carbon_v1_event_delete']), {}) assert (carbon_v1_pool.state['y_0'] == 0) assert (carbon_v1_pool.state['z_0'] == 0) assert (carbon_v1_pool.state['A_0'] == 0) @@ -206,7 +207,7 @@ def test_test_bancor_pol_token_traded_event(): bancor_pol_pool = BancorPolPool() bancor_pol_pool.state['tkn0_address'] = setup_data['bancor_pol_token_traded_event']['args']['token'] bancor_pol_pool.state['tkn0_balance'] = 10 + setup_data['bancor_pol_token_traded_event']['args']['amount'] - bancor_pol_pool.update_from_event(setup_data['bancor_pol_token_traded_event'], + bancor_pol_pool.update_from_event(Event.from_dict(setup_data['bancor_pol_token_traded_event']), {'cid': '0x', 'fee': '0.000', 'fee_float': 0.0, @@ -230,7 +231,7 @@ def test_test_bancor_pol_trading_enabled_event(): bancor_pol_pool = BancorPolPool() bancor_pol_pool.state['tkn0_address'] = None - bancor_pol_pool.update_from_event(setup_data['bancor_pol_trading_enabled_event'], + bancor_pol_pool.update_from_event(Event.from_dict(setup_data['bancor_pol_trading_enabled_event']), {'cid': '0x', 'fee': '0.000', 'fee_float': 0.0, diff --git a/fastlane_bot/tests/test_035_Utils.py b/fastlane_bot/tests/test_035_Utils.py index 712c0e53b..6f7ab23a1 100644 --- a/fastlane_bot/tests/test_035_Utils.py +++ b/fastlane_bot/tests/test_035_Utils.py @@ -12,6 +12,7 @@ from web3.types import HexBytes from fastlane_bot import Bot +from fastlane_bot.events.interfaces.event import Event from fastlane_bot.events.pools import UniswapV2Pool, UniswapV3Pool, BancorV3Pool, CarbonV1Pool from fastlane_bot.events.utils import filter_latest_events, complex_handler from fastlane_bot.tools.cpc import ConstantProductCurve as CPC @@ -47,10 +48,10 @@ def exchange_name_from_event(self, event): return 'uniswap_v2' mocked_mgr = MockManager() -event1 = AttributeDict({'args': {'reserve0': 100, 'reserve1': 100}, 'event': 'Sync', 'address': '0xabc', 'blockNumber': 5, 'transactionIndex': 0, 'logIndex': 0}) -event2 = AttributeDict({'args': {'reserve0': 200, 'reserve1': 200}, 'event': 'Sync', 'address': '0xabc', 'blockNumber': 10, 'transactionIndex': 1, 'logIndex': 1}) -event3 = AttributeDict({'args': {'reserve0': 300, 'reserve1': 300}, 'event': 'Sync', 'address': '0xdef', 'blockNumber': 7, 'transactionIndex': 1, 'logIndex': 1}) -mock_events = [[event1, event2, event3]] +event1 = Event.from_dict({'args': {'reserve0': 100, 'reserve1': 100}, 'event': 'Sync', 'address': '0xabc', 'blockNumber': 5, 'transactionIndex': 0, 'logIndex': 0, 'transactionHash': '', 'blockHash': ''}) +event2 = Event.from_dict({'args': {'reserve0': 200, 'reserve1': 200}, 'event': 'Sync', 'address': '0xabc', 'blockNumber': 10, 'transactionIndex': 1, 'logIndex': 1, 'transactionHash': '', 'blockHash': ''}) +event3 = Event.from_dict({'args': {'reserve0': 300, 'reserve1': 300}, 'event': 'Sync', 'address': '0xdef', 'blockNumber': 7, 'transactionIndex': 1, 'logIndex': 1, 'transactionHash': '', 'blockHash': ''}) +mock_events = [event1, event2, event3] # ------------------------------------------------------------ @@ -62,9 +63,9 @@ def test_test_filter_latest_events(): # ------------------------------------------------------------ result = filter_latest_events(mocked_mgr, mock_events) - assert (len(result) == len({event['address'] for event in result})) - pool_address = result[0]['address'] - pool_events = [event for event in mock_events[0] if (event['address'] == pool_address)] + assert (len(result) == len({event.address for event in result})) + pool_address = result[0].address + pool_events = [event for event in mock_events if (event.address == pool_address)] # ------------------------------------------------------------ diff --git a/fastlane_bot/tests/test_036_Manager.py b/fastlane_bot/tests/test_036_Manager.py index 8d5ae2772..511c76ff9 100644 --- a/fastlane_bot/tests/test_036_Manager.py +++ b/fastlane_bot/tests/test_036_Manager.py @@ -14,6 +14,7 @@ from unittest.mock import MagicMock from fastlane_bot import Bot, Config +from fastlane_bot.events.interfaces.event import Event from fastlane_bot.events.exchanges import UniswapV2, UniswapV3, CarbonV1, BancorV3 from fastlane_bot.events.managers.manager import Manager from fastlane_bot.events.pools.utils import get_pool_cid @@ -85,7 +86,7 @@ def test_test_update_from_event_uniswap_v2(): assert event['args']['reserve0'] != [pool['tkn0_balance'] for pool in manager.pool_data if pool['address'] == event['address']][0] - manager.update_from_event(event) + manager.update_from_event(Event.from_dict(event)) assert event['address'] in [pool['address'] for pool in manager.pool_data] assert event['args']['reserve0'] == [pool['tkn0_balance'] for pool in manager.pool_data if pool['address'] == event['address']][0] @@ -105,7 +106,7 @@ def test_test_update_from_event_uniswap_v3(): assert event['args']['liquidity'] != [pool['liquidity'] for pool in manager.pool_data if pool['address'] == event['address']][0] - manager.update_from_event(event) + manager.update_from_event(Event.from_dict(event)) assert event['address'] in [pool['address'] for pool in manager.pool_data] assert event['args']['liquidity'] == [pool['liquidity'] for pool in manager.pool_data if pool['address'] == event['address']][0] @@ -126,8 +127,8 @@ def test_test_update_from_event_carbon_v1_update(): event_create_for_update = event_data['carbon_v1_event_create_for_update'] event = event_data['carbon_v1_event_update'] - manager.update_from_event(event_create_for_update) - pools_to_add_from_contracts = [event[2]['args']['id'] for event in manager.pools_to_add_from_contracts] + manager.update_from_event(Event.from_dict(event_create_for_update)) + pools_to_add_from_contracts = [event[2].args['id'] for event in manager.pools_to_add_from_contracts] assert event['args']['id'] in pools_to_add_from_contracts @@ -148,7 +149,7 @@ def test_test_update_from_event_carbon_v1_create(): manager.pool_data = [pool for pool in manager.pool_data if pool['cid'] != event['args']['id']] assert event['args']['id'] not in [pool['cid'] for pool in manager.pool_data] - manager.update_from_event(event) + manager.update_from_event(Event.from_dict(event)) assert event['args']['id'] not in [pool['cid'] for pool in manager.pool_data] # - @@ -171,7 +172,7 @@ def test_test_update_from_event_carbon_v1_delete(): manager.pool_data = [pool for pool in manager.pool_data if pool['cid'] != cid] assert cid not in [pool['cid'] for pool in manager.pool_data] - manager.update_from_event(event) + manager.update_from_event(Event.from_dict(event)) assert cid in [p[-1] for p in manager.pools_to_add_from_contracts] fake_pool_data = { "address": event['address'], @@ -183,5 +184,5 @@ def test_test_update_from_event_carbon_v1_delete(): manager.pool_data.append(fake_pool_data) event['event'] = 'StrategyDeleted' - manager.update_from_event(event) + manager.update_from_event(Event.from_dict(event)) assert cid not in [pool['cid'] for pool in manager.pool_data] \ No newline at end of file diff --git a/fastlane_bot/tests/test_037_Exchanges.py b/fastlane_bot/tests/test_037_Exchanges.py index 81a51b5ea..27f1ad82e 100644 --- a/fastlane_bot/tests/test_037_Exchanges.py +++ b/fastlane_bot/tests/test_037_Exchanges.py @@ -11,6 +11,7 @@ import json from fastlane_bot import Bot +from fastlane_bot.events.interfaces.event import Event from fastlane_bot.events.exchanges.balancer import Balancer from fastlane_bot.tools.cpc import ConstantProductCurve as CPC from fastlane_bot.events.exchanges import UniswapV2, UniswapV3, CarbonV1, BancorV3, BancorV2, BancorPol, SolidlyV2 @@ -261,7 +262,7 @@ def test_test_bancor_v2_exchange(): async def test_bancor_v2_exchange(): assert (bancor_v2_exchange.get_abi() == BANCOR_V2_CONVERTER_ABI) assert (await bancor_v2_exchange.get_fee('', mocked_contract) == (3000, 0.003)) - assert (await bancor_v2_exchange.get_tkn0('', mocked_contract, setup_data['bancor_v2_event']) == '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE') + assert (await bancor_v2_exchange.get_tkn0('', mocked_contract, Event.from_dict(setup_data['bancor_v2_event'])) == '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE') # Run the test in an event loop asyncio.run(test_bancor_v2_exchange()) @@ -283,7 +284,7 @@ def test_test_carbon_v1_exchange_update(): async def test_carbon_v1_exchange_update(): assert (carbon_v1_exchange.get_abi() == CARBON_CONTROLLER_ABI) assert (await carbon_v1_exchange.get_fee('', mocked_contract) == ('2000', 0.002)) - assert (await carbon_v1_exchange.get_tkn0('', mocked_contract, setup_data['carbon_v1_event_update']) == setup_data['carbon_v1_event_update']['args']['token0']) + assert (await carbon_v1_exchange.get_tkn0('', mocked_contract, Event.from_dict(setup_data['carbon_v1_event_update'])) == setup_data['carbon_v1_event_update']['args']['token0']) # Run the test in an event loop asyncio.run(test_carbon_v1_exchange_update()) @@ -305,7 +306,7 @@ def test_test_carbon_v1_exchange_create(): async def test_carbon_v1_exchange_create(): assert (carbon_v1_exchange.get_abi() == CARBON_CONTROLLER_ABI) assert (await carbon_v1_exchange.get_fee('', mocked_contract) == ('2000', 0.002)) - assert (await carbon_v1_exchange.get_tkn0('', mocked_contract, setup_data['carbon_v1_event_create']) == setup_data['carbon_v1_event_create']['args']['token0']) + assert (await carbon_v1_exchange.get_tkn0('', mocked_contract, Event.from_dict(setup_data['carbon_v1_event_create'])) == setup_data['carbon_v1_event_create']['args']['token0']) # Run the test in an event loop asyncio.run(test_carbon_v1_exchange_create()) @@ -333,7 +334,7 @@ def test_test_carbon_v1_exchange_delete(): async def test_bancor_pol_exchange(): assert (bancor_pol_exchange.get_abi() == BANCOR_POL_ABI) assert (await bancor_pol_exchange.get_fee('', mocked_contract) == ('0.000', 0.0)) - assert (await bancor_pol_exchange.get_tkn0('', mocked_contract, setup_data['bancor_pol_trading_enabled_event']) == "0x86772b1409b61c639EaAc9Ba0AcfBb6E238e5F83") + assert (await bancor_pol_exchange.get_tkn0('', mocked_contract, Event.from_dict(setup_data['bancor_pol_trading_enabled_event'])) == "0x86772b1409b61c639EaAc9Ba0AcfBb6E238e5F83") # Run the test in an event loop asyncio.run(test_bancor_pol_exchange()) \ No newline at end of file From 6b20b6a06e02afb85bfade3c65e817a0ba44a1a7 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Fri, 10 May 2024 14:33:03 +0300 Subject: [PATCH 075/131] fix: tests --- fastlane_bot/events/interfaces/event.py | 26 +++++++++---------- .../tests/test_049_CustomTradingFees.py | 5 ++-- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/fastlane_bot/events/interfaces/event.py b/fastlane_bot/events/interfaces/event.py index 98bb5c2fc..5687f3079 100644 --- a/fastlane_bot/events/interfaces/event.py +++ b/fastlane_bot/events/interfaces/event.py @@ -1,27 +1,27 @@ from dataclasses import dataclass -from typing import Any, Dict +from typing import Any, Dict, Optional @dataclass class Event: args: Dict[str, Any] event: str - log_index: int - transaction_index: int - transaction_hash: str - address: str - block_hash: str - block_number: int + log_index: Optional[int] + transaction_index: Optional[int] + transaction_hash: Optional[str] + address: Optional[str] + block_hash: Optional[str] + block_number: Optional[int] @classmethod def from_dict(cls, data): return cls( args=data["args"], event=data["event"], - log_index=data["logIndex"], - transaction_index=data["transactionIndex"], - transaction_hash=data["transactionHash"], - address=data["address"], - block_hash=data["blockHash"], - block_number=data["blockNumber"], + log_index=data.get("logIndex", None), + transaction_index=data.get("transactionIndex", None), + transaction_hash=data.get("transactionHash", None), + address=data.get("address", None), + block_hash=data.get("blockHash", None), + block_number=data.get("blockNumber", None), ) diff --git a/fastlane_bot/tests/test_049_CustomTradingFees.py b/fastlane_bot/tests/test_049_CustomTradingFees.py index e6b2be248..c759db5df 100644 --- a/fastlane_bot/tests/test_049_CustomTradingFees.py +++ b/fastlane_bot/tests/test_049_CustomTradingFees.py @@ -14,6 +14,7 @@ from unittest.mock import MagicMock from fastlane_bot import Bot, Config +from fastlane_bot.events.interfaces.event import Event from fastlane_bot.events.exchanges import UniswapV2, UniswapV3, CarbonV1, BancorV3 from fastlane_bot.events.managers.manager import Manager Base = None @@ -77,7 +78,7 @@ def test_test_update_from_event_carbon_v1_pair_create(): assert (event['args']['token0'], event['args']['token1']) not in manager.fee_pairs[exchange_name] - manager.update_from_event(event) + manager.update_from_event(Event.from_dict(event)) assert (event['args']['token0'], event['args']['token1']) in manager.fee_pairs[exchange_name] @@ -112,7 +113,7 @@ async def test_update_from_event_carbon_v1_trading_fee_updated(): # find all pools with fee==prevFeePPM prev_default_pools = [idx for idx, pool in enumerate(manager.pool_data) if pool['fee'] == prevFeePPM] - manager.update_from_event(event) + manager.update_from_event(Event.from_dict(event)) for idx in prev_default_pools: assert manager.pool_data[idx]['fee'] == newFeePPM From 66654319bb83b3ba950cb068dc91fe8d061859d7 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Fri, 10 May 2024 14:57:22 +0300 Subject: [PATCH 076/131] fix: tests --- fastlane_bot/events/event_gatherer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane_bot/events/event_gatherer.py b/fastlane_bot/events/event_gatherer.py index 989793716..29eb78cc6 100644 --- a/fastlane_bot/events/event_gatherer.py +++ b/fastlane_bot/events/event_gatherer.py @@ -36,7 +36,7 @@ def __init__( for exchange_name, exchange in exchanges.items(): subscriptions = exchange.get_subscriptions(event_contracts[exchange_name]) for sub in subscriptions: - if sub.get_topic not in unique_topics: + if sub.topic not in unique_topics: unique_topics.add(sub.topic) self._subscriptions.append(sub) From 13aa6a1535c1a44e3f3bb7acef6fb7d92d9acdc0 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Fri, 10 May 2024 15:09:38 +0300 Subject: [PATCH 077/131] fix: tests --- fastlane_bot/events/pools/bancor_pol.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane_bot/events/pools/bancor_pol.py b/fastlane_bot/events/pools/bancor_pol.py index d0f1a6065..15091e159 100644 --- a/fastlane_bot/events/pools/bancor_pol.py +++ b/fastlane_bot/events/pools/bancor_pol.py @@ -58,7 +58,7 @@ def event_matches_format( True if the event matches the format of a Bancor v3 event, False otherwise. """ - event_args = event["args"] + event_args = event.args return ("token" in event_args) and ("token0" not in event_args) and (event_args['token'] == "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE") def update_from_event( From 5364213a3d2d9502e0ec73cc8932e40250b838c2 Mon Sep 17 00:00:00 2001 From: Lesigh-3100 Date: Sun, 5 May 2024 20:16:20 +0300 Subject: [PATCH 078/131] Pairfinder Automatically searches for Carbon pairs or triangles (depending on mode) and finds pools to create viable routes for them. --- fastlane_bot/config/constants.py | 3 + fastlane_bot/data/abi.py | 67 +++++ fastlane_bot/events/exchanges/balancer.py | 8 +- fastlane_bot/events/exchanges/bancor_pol.py | 6 + fastlane_bot/events/exchanges/bancor_v2.py | 6 + fastlane_bot/events/exchanges/bancor_v3.py | 5 + fastlane_bot/events/exchanges/base.py | 9 + fastlane_bot/events/exchanges/carbon_v1.py | 5 + fastlane_bot/events/exchanges/solidly_v2.py | 79 +++++- fastlane_bot/events/exchanges/uniswap_v2.py | 14 +- fastlane_bot/events/exchanges/uniswap_v3.py | 15 +- fastlane_bot/events/managers/base.py | 19 +- fastlane_bot/events/pools/base.py | 2 +- fastlane_bot/helpers/poolandtokens.py | 38 +-- fastlane_bot/pool_finder.py | 233 ++++++++++++++++++ fastlane_bot/tests/test_073_TestPoolFinder.py | 96 ++++++++ main.py | 19 +- 17 files changed, 589 insertions(+), 35 deletions(-) create mode 100644 fastlane_bot/pool_finder.py create mode 100644 fastlane_bot/tests/test_073_TestPoolFinder.py diff --git a/fastlane_bot/config/constants.py b/fastlane_bot/config/constants.py index 0c6357ce0..ad6641ac0 100644 --- a/fastlane_bot/config/constants.py +++ b/fastlane_bot/config/constants.py @@ -19,6 +19,8 @@ } ETHEREUM = "ethereum" +UNISWAP_V2_NAME = "uniswap_v2" +UNISWAP_V3_NAME = "uniswap_v3" PANCAKESWAP_V2_NAME = "pancakeswap_v2" PANCAKESWAP_V3_NAME = "pancakeswap_v3" BUTTER_V3_NAME = "butter_v3" @@ -31,3 +33,4 @@ ECHODEX_V3_NAME = "echodex_v3" SECTA_V3_NAME = "secta_v3" METAVAULT_V3_NAME = "metavault_v3" +ZERO_ADDRESS = "0x0000000000000000000000000000000000000000" diff --git a/fastlane_bot/data/abi.py b/fastlane_bot/data/abi.py index ec6f102f4..daaa04a03 100644 --- a/fastlane_bot/data/abi.py +++ b/fastlane_bot/data/abi.py @@ -164,6 +164,15 @@ "name": "PairCreated", "anonymous": False, "inputs": [{"indexed": True, "internalType": "address", "name": "token0", "type": "address"}, {"indexed": True, "internalType": "address", "name": "token1", "type": "address"}, {"indexed": False, "internalType": "address", "name": "pair", "type": "address"}, {"indexed": False, "internalType": "uint256", "name": "", "type": "uint256"}] + }, + { + "type": "function", + "name": "getPair", + "stateMutability": "view", + "constant": True, + "inputs": [{"internalType": "address", "name": "", "type": "address"}, {"internalType": "address", "name": "", "type": "address"}], + "outputs": [{"internalType": "address", "name": "", "type": "address"}], + "payable": False, } ] @@ -173,6 +182,13 @@ "name": "PoolCreated", "anonymous": False, "inputs": [{"indexed": True, "internalType": "address", "name": "token0", "type": "address"}, {"indexed": True, "internalType": "address", "name": "token1", "type": "address"}, {"indexed": True, "internalType": "uint24", "name": "fee", "type": "uint24"}, {"indexed": False, "internalType": "int24", "name": "tickSpacing", "type": "int24"}, {"indexed": False, "internalType": "address", "name": "pool", "type": "address"}] + }, + { + "type": "function", + "name": "getPool", + "stateMutability": "view", + "inputs": [{"internalType": "address", "name": "", "type": "address"}, {"internalType": "address", "name": "", "type": "address"}, {"internalType": "uint24", "name": "", "type": "uint24"}], + "outputs": [{"internalType": "address", "name": "", "type": "address"}], } ] @@ -189,6 +205,13 @@ "stateMutability": "view", "inputs": [{"internalType": "address", "name": "pool", "type": "address"}, {"internalType": "bool", "name": "_stable", "type": "bool"}], "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}] + }, + { + "name": "getPool", + "stateMutability": "view", + "type": "function", + "inputs": [{"internalType": "address", "name": "tokenA", "type": "address"}, {"internalType": "address", "name": "tokenB", "type": "address"}, {"internalType": "bool", "name": "stable", "type": "bool"}], + "outputs": [{"internalType": "address", "name": "", "type": "address"}], } ] @@ -205,6 +228,13 @@ "stateMutability": "view", "inputs": [{"internalType": "address", "name": "_pair", "type": "address"}], "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}] + }, + { + "type": "function", + "name": "getPair", + "stateMutability": "view", + "inputs": [{"internalType": "address", "name": "", "type": "address"}, {"internalType": "address", "name": "", "type": "address"}, {"internalType": "bool", "name": "", "type": "bool"}], + "outputs": [{"internalType": "address", "name": "", "type": "address"}] } ] @@ -221,6 +251,15 @@ "stateMutability": "view", "inputs": [{"internalType": "address", "name": "_pair", "type": "address"}], "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}] + }, + { + "type": "function", + "name": "getPair", + "stateMutability": "view", + "inputs": [{"internalType": "address", "name": "", "type": "address"}, + {"internalType": "address", "name": "", "type": "address"}, + {"internalType": "bool", "name": "", "type": "bool"}], + "outputs": [{"internalType": "address", "name": "", "type": "address"}] } ] @@ -237,6 +276,13 @@ "stateMutability": "view", "inputs": [{"type": "address", "name": "_pair", "internalType": "address"}, {"type": "bool", "name": "_stable", "internalType": "bool"}], "outputs": [{"type": "uint256", "name": "", "internalType": "uint256"}] + }, + { + "type": "function", + "name": "getPair", + "stateMutability": "view", + "inputs": [{"internalType": "address", "name": "", "type": "address"}, {"internalType": "address", "name": "", "type": "address"}, {"internalType": "bool", "name": "", "type": "bool"}], + "outputs": [{"internalType": "address", "name": "", "type": "address"}] } ] @@ -253,6 +299,13 @@ "stateMutability": "view", "inputs": [{"internalType": "bool", "name": "_stable", "type": "bool"}], "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}] + }, + { + "type": "function", + "name": "getPair", + "stateMutability": "view", + "inputs": [{"internalType": "address", "name": "", "type": "address"}, {"internalType": "address", "name": "", "type": "address"}, {"internalType": "bool", "name": "", "type": "bool"}], + "outputs": [{"internalType": "address", "name": "", "type": "address"}] } ] @@ -269,6 +322,13 @@ "stateMutability": "view", "inputs": [{"internalType": "address", "name": "_pool", "type": "address"}], "outputs": [{"internalType": "uint256", "name": "fee", "type": "uint256"}] + }, + { + "type": "function", + "name": "getPair", + "stateMutability": "view", + "inputs": [{"internalType": "address", "name": "", "type": "address"}, {"internalType": "address", "name": "", "type": "address"}, {"internalType": "bool", "name": "", "type": "bool"}], + "outputs": [{"internalType": "address", "name": "", "type": "address"}] } ] @@ -285,6 +345,13 @@ "stateMutability": "view", "inputs": [], "outputs": [{"internalType": "address", "name": "", "type": "address"}] + }, + { + "type": "function", + "name": "getPool", + "stateMutability": "view", + "inputs": [{"internalType": "address", "name": "_token", "type": "address"}], + "outputs": [{"internalType": "address", "name": "pool", "type": "address"}], } ] diff --git a/fastlane_bot/events/exchanges/balancer.py b/fastlane_bot/events/exchanges/balancer.py index 791180f0c..3481d5fe1 100644 --- a/fastlane_bot/events/exchanges/balancer.py +++ b/fastlane_bot/events/exchanges/balancer.py @@ -87,4 +87,10 @@ async def get_tkn_n(self, address: str, contract: Contract, event: Any, index: i pool_balances = await contract.caller.getPoolTokens(address) tokens = pool_balances[0] token_balances = pool_balances[1] - return token_balances[index] \ No newline at end of file + return token_balances[index] + + def get_pool_function(self, factory_contract: Contract): + """ + This function is unused for Carbon. + """ + pass \ No newline at end of file diff --git a/fastlane_bot/events/exchanges/bancor_pol.py b/fastlane_bot/events/exchanges/bancor_pol.py index 4e40c7397..7d0075f80 100644 --- a/fastlane_bot/events/exchanges/bancor_pol.py +++ b/fastlane_bot/events/exchanges/bancor_pol.py @@ -63,6 +63,12 @@ async def get_tkn0(self, address: str, contract: Contract, event: Event) -> str: async def get_tkn1(self, address: str, contract: Contract, event: Event) -> str: return self.ETH_ADDRESS if event.args["token"] not in self.ETH_ADDRESS else self.BNT_ADDRESS + def get_pool_function(self, factory_contract: Contract): + """ + This function is unused for Bancor POL. + """ + pass + def save_strategy( self, token: str, diff --git a/fastlane_bot/events/exchanges/bancor_v2.py b/fastlane_bot/events/exchanges/bancor_v2.py index d1b4b149e..ab23a3b86 100644 --- a/fastlane_bot/events/exchanges/bancor_v2.py +++ b/fastlane_bot/events/exchanges/bancor_v2.py @@ -77,3 +77,9 @@ async def get_tkn1(self, address: str, contract: Contract, event: Event) -> str: async def get_anchor(self, contract: Contract) -> str: return await contract.caller.anchor() + + def get_pool_function(self, factory_contract: Contract): + """ + This function is unused for Bancor V2. + """ + pass \ No newline at end of file diff --git a/fastlane_bot/events/exchanges/bancor_v3.py b/fastlane_bot/events/exchanges/bancor_v3.py index da2c76733..53c584ef3 100644 --- a/fastlane_bot/events/exchanges/bancor_v3.py +++ b/fastlane_bot/events/exchanges/bancor_v3.py @@ -64,3 +64,8 @@ async def get_tkn1(self, address: str, contract: Contract, event: Event) -> str: if event.args["pool"] != self.BNT_ADDRESS else event.args["tkn_address"] ) + def get_pool_function(self, factory_contract: Contract): + """ + This function is unused for Bancor V3. + """ + pass \ No newline at end of file diff --git a/fastlane_bot/events/exchanges/base.py b/fastlane_bot/events/exchanges/base.py index ed641d974..fd13105d2 100644 --- a/fastlane_bot/events/exchanges/base.py +++ b/fastlane_bot/events/exchanges/base.py @@ -30,6 +30,7 @@ class Exchange(ABC): exchange_name: str base_exchange_name: str = '' pools: Dict[str, Pool] = field(default_factory=dict) + sync_factory_contract: Contract = None __VERSION__ = "0.0.3" __DATE__ = "2024-03-20" @@ -122,6 +123,14 @@ async def get_fee(address: str, contract: AsyncContract) -> float: """ pass + @staticmethod + @abstractmethod + def get_pool_function(contract: Contract, *args): + """ + Returns the Factory contract function used to fetch liquidity pools. + """ + pass + @staticmethod @abstractmethod async def get_tkn0(address: str, contract: AsyncContract, event: Any) -> str: diff --git a/fastlane_bot/events/exchanges/carbon_v1.py b/fastlane_bot/events/exchanges/carbon_v1.py index 2957e04cf..e95416c6e 100644 --- a/fastlane_bot/events/exchanges/carbon_v1.py +++ b/fastlane_bot/events/exchanges/carbon_v1.py @@ -245,3 +245,8 @@ def save_strategy( block_number=block_number, ) + def get_pool_function(self, factory_contract: Contract): + """ + This function is unused for Carbon. + """ + pass \ No newline at end of file diff --git a/fastlane_bot/events/exchanges/solidly_v2.py b/fastlane_bot/events/exchanges/solidly_v2.py index d6f5aa02a..5d3951c11 100644 --- a/fastlane_bot/events/exchanges/solidly_v2.py +++ b/fastlane_bot/events/exchanges/solidly_v2.py @@ -59,17 +59,70 @@ async def _get_tkn0_B(contract: Contract) -> str: async def _get_tkn1_B(contract: Contract) -> str: return "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f" # TODO Use the constant WRAPPED_GAS_TOKEN_ADDRESS for this network + +def _get_pool_function_1(factory_contract): + """ Function to get pools from Factory. + This function is intended to be used with a Multicall. It fetches pools from a Solidly fork Factory contract. + + Args: + factory_contract: The factory contract. + + Returns: + The function. + + """ + return factory_contract.functions.getPair +def _get_pool_function_2(factory_contract): + """ Function to get pools from Factory. + This function is intended to be used with a Multicall. It fetches pools from a Solidly fork Factory contract. + + Args: + factory_contract: The factory contract. + + Returns: + The function. + + """ + return factory_contract.functions.getPool + + +def _get_pool_args_1(tkn0, tkn1, stable): + """ Function to manage args input to get pools from Factory. + + Args: + tkn0: The first token address. + tkn1: The second token address. + stable: (bool) If True, indicates a stable pool. If False, indicates a Volatile pool. + Returns: + The function returns the arguments necessary to get pool addresses from the factory contract. + + """ + return tkn0, tkn1, stable + +def _get_pool_args_2(tkn0, tkn1, stable): + """ Function to manage args input to get pools from Factory. + + Args: + tkn0: The first token address. + tkn1: The second token address. + stable: (bool) If True, indicates a stable pool. If False, indicates a Volatile pool. + Returns: + The function returns the arguments necessary to get pool addresses from the factory contract. + + """ + return tkn0 + EXCHANGE_INFO = { - "velocimeter_v2": {"decimals": 4, "factory_abi": VELOCIMETER_V2_FACTORY_ABI, "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_1, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A}, - "equalizer_v2" : {"decimals": 4, "factory_abi": SCALE_V2_FACTORY_ABI , "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_2, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A}, - "aerodrome_v2" : {"decimals": 4, "factory_abi": SOLIDLY_V2_FACTORY_ABI , "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_3, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A}, - "velodrome_v2" : {"decimals": 4, "factory_abi": SOLIDLY_V2_FACTORY_ABI , "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_3, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A}, - "scale_v2" : {"decimals": 18, "factory_abi": SCALE_V2_FACTORY_ABI , "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_2, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A}, - "cleopatra_v2" : {"decimals": 4, "factory_abi": CLEOPATRA_V2_FACTORY_ABI , "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_4, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A}, - "stratum_v2" : {"decimals": 4, "factory_abi": VELOCIMETER_V2_FACTORY_ABI, "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_1, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A}, - "lynex_v2" : {"decimals": 4, "factory_abi": LYNEX_V2_FACTORY_ABI , "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_5, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A}, - "nile_v2" : {"decimals": 4, "factory_abi": NILE_V2_FACTORY_ABI , "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_6, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A}, - "xfai_v0" : {"decimals": 4, "factory_abi": XFAI_V0_FACTORY_ABI , "pool_abi": XFAI_V0_POOL_ABI , "get_fee": _get_fee_7, "get_tkn0": _get_tkn0_B, "get_tkn1": _get_tkn1_B}, + "velocimeter_v2": {"decimals": 4, "factory_abi": VELOCIMETER_V2_FACTORY_ABI, "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_1, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A, "get_pool_function": _get_pool_function_1, "get_pool_args": _get_pool_args_1}, + "equalizer_v2" : {"decimals": 4, "factory_abi": SCALE_V2_FACTORY_ABI , "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_2, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A, "get_pool_function": _get_pool_function_1, "get_pool_args": _get_pool_args_1}, + "aerodrome_v2" : {"decimals": 4, "factory_abi": SOLIDLY_V2_FACTORY_ABI , "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_3, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A, "get_pool_function": _get_pool_function_2, "get_pool_args": _get_pool_args_1}, + "velodrome_v2" : {"decimals": 4, "factory_abi": SOLIDLY_V2_FACTORY_ABI , "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_3, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A, "get_pool_function": _get_pool_function_2, "get_pool_args": _get_pool_args_1}, + "scale_v2" : {"decimals": 18, "factory_abi": SCALE_V2_FACTORY_ABI , "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_2, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A, "get_pool_function": _get_pool_function_1, "get_pool_args": _get_pool_args_1}, + "cleopatra_v2" : {"decimals": 4, "factory_abi": CLEOPATRA_V2_FACTORY_ABI , "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_4, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A, "get_pool_function": _get_pool_function_1, "get_pool_args": _get_pool_args_1}, + "stratum_v2" : {"decimals": 4, "factory_abi": VELOCIMETER_V2_FACTORY_ABI, "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_1, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A, "get_pool_function": _get_pool_function_1, "get_pool_args": _get_pool_args_1}, + "lynex_v2" : {"decimals": 4, "factory_abi": LYNEX_V2_FACTORY_ABI , "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_5, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A, "get_pool_function": _get_pool_function_1, "get_pool_args": _get_pool_args_1}, + "nile_v2" : {"decimals": 4, "factory_abi": NILE_V2_FACTORY_ABI , "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_6, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A, "get_pool_function": _get_pool_function_1, "get_pool_args": _get_pool_args_1}, + "xfai_v0" : {"decimals": 4, "factory_abi": XFAI_V0_FACTORY_ABI , "pool_abi": XFAI_V0_POOL_ABI , "get_fee": _get_fee_7, "get_tkn0": _get_tkn0_B, "get_tkn1": _get_tkn1_B, "get_pool_function": _get_pool_function_2, "get_pool_args": _get_pool_args_2}, } @dataclass @@ -120,3 +173,9 @@ async def get_tkn0(self, address: str, contract: Contract, event: Any) -> str: async def get_tkn1(self, address: str, contract: Contract, event: Any) -> str: return await EXCHANGE_INFO[self.exchange_name]["get_tkn1"](contract) + + def get_pool_function(self, factory_contract): + return EXCHANGE_INFO[self.exchange_name]["get_pool_function"](factory_contract) + + def get_pool_args(self, tkn0, tkn1, stable): + return EXCHANGE_INFO[self.exchange_name]["get_pool_args"](tkn0, tkn1, stable) diff --git a/fastlane_bot/events/exchanges/uniswap_v2.py b/fastlane_bot/events/exchanges/uniswap_v2.py index 870b938bf..b08e0ef27 100644 --- a/fastlane_bot/events/exchanges/uniswap_v2.py +++ b/fastlane_bot/events/exchanges/uniswap_v2.py @@ -32,7 +32,6 @@ class UniswapV2(Exchange): fee: str = None router_address: str = None exchange_initialized: bool = False - @property def fee_float(self): return float(self.fee) @@ -63,3 +62,16 @@ async def get_tkn0(address: str, contract: AsyncContract, event: Any) -> str: @staticmethod async def get_tkn1(address: str, contract: AsyncContract, event: Any) -> str: return await contract.caller.token1() + + def get_pool_function(self, factory_contract: Contract): + """ Function to get pools from Factory. + This function is intended to be used with a Multicall. It fetches pools from a Uniswap V2 fork Factory contract. + + Args: + factory_contract: The factory contract. + + Returns: + The function. + + """ + return factory_contract.functions.getPair diff --git a/fastlane_bot/events/exchanges/uniswap_v3.py b/fastlane_bot/events/exchanges/uniswap_v3.py index 2136a32a2..0eb8fb6c4 100644 --- a/fastlane_bot/events/exchanges/uniswap_v3.py +++ b/fastlane_bot/events/exchanges/uniswap_v3.py @@ -14,7 +14,7 @@ from dataclasses import dataclass from typing import List, Type, Tuple, Any -from web3.contract import Contract +from web3.contract import Contract, AsyncContract from fastlane_bot.config.constants import AGNI_V3_NAME, PANCAKESWAP_V3_NAME, FUSIONX_V3_NAME, ECHODEX_V3_NAME, SECTA_V3_NAME from fastlane_bot.data.abi import UNISWAP_V3_POOL_ABI, UNISWAP_V3_FACTORY_ABI, PANCAKESWAP_V3_POOL_ABI @@ -59,3 +59,16 @@ async def get_tkn0(self, address: str, contract: Contract, event: Any) -> str: async def get_tkn1(self, address: str, contract: Contract, event: Any) -> str: return await contract.caller.token1() + + def get_pool_function(self, factory_contract: Contract): + """ Function to get pools from Factory. + This function is intended to be used with a Multicall. It fetches pools from a Uniswap V3 fork Factory contract. + + Args: + factory_contract: The factory contract. + + Returns: + The function. + + """ + return factory_contract.functions.getPool diff --git a/fastlane_bot/events/managers/base.py b/fastlane_bot/events/managers/base.py index cf85d906a..6600c9304 100644 --- a/fastlane_bot/events/managers/base.py +++ b/fastlane_bot/events/managers/base.py @@ -17,7 +17,7 @@ from fastlane_bot import Config from fastlane_bot.config.constants import PANCAKESWAP_V2_NAME, PANCAKESWAP_V3_NAME, VELOCIMETER_V2_NAME, AGNI_V3_NAME, \ - SOLIDLY_V2_NAME, FUSIONX_V3_NAME + SOLIDLY_V2_NAME, FUSIONX_V3_NAME, UNISWAP_V2_NAME, UNISWAP_V3_NAME from fastlane_bot.config.multicaller import MultiCaller from fastlane_bot.events.exchanges import exchange_factory from fastlane_bot.events.exchanges.base import Exchange @@ -78,6 +78,7 @@ class BaseManager: token_contracts: Dict[str, Contract or Type[Contract]] = field(default_factory=dict) erc20_contracts: Dict[str, Contract or Type[Contract]] = field(default_factory=dict) exchanges: Dict[str, Exchange] = field(default_factory=dict) + sync_factory_contracts: Dict[str, Contract or Type[Contract]] = field(default_factory=dict) factory_contracts: Dict[str, Contract or Type[Contract]] = field(default_factory=dict) uniswap_v2_event_mappings: Dict[str, str] = field(default_factory=dict) uniswap_v3_event_mappings: Dict[str, str] = field(default_factory=dict) @@ -129,8 +130,10 @@ def __post_init__(self): self.SUPPORTED_BASE_EXCHANGES.append(base_exchange_name) self.exchanges[exchange_name] = exchange_factory.get_exchange(key=exchange_name, cfg=self.cfg, exchange_initialized=initialize_events) - if base_exchange_name in SOLIDLY_V2_NAME: + if base_exchange_name == SOLIDLY_V2_NAME: self.exchanges[exchange_name] = self.handle_solidly_exchanges(exchange=self.exchanges[exchange_name]) + if base_exchange_name in [SOLIDLY_V2_NAME, UNISWAP_V2_NAME, UNISWAP_V3_NAME]: + self.exchanges[exchange_name] = self.initialize_factory_contract(exchange=self.exchanges[exchange_name]) self.init_exchange_contracts() self.set_carbon_v1_fee_pairs() @@ -149,6 +152,18 @@ def handle_solidly_exchanges(self, exchange): return exchange + def initialize_factory_contract(self, exchange): + """ + Initialize factory contract for exchange. + """ + exchange_name = exchange.exchange_name + self.sync_factory_contracts[exchange_name] = self.web3.eth.contract( + address=self.cfg.FACTORY_MAPPING[exchange_name], + abi=exchange.get_factory_abi, + ) + exchange.sync_factory_contract = self.sync_factory_contracts[exchange.exchange_name] + + return exchange @property def fee_pairs(self) -> Dict: """ diff --git a/fastlane_bot/events/pools/base.py b/fastlane_bot/events/pools/base.py index 4aa92999a..a220ce3fd 100644 --- a/fastlane_bot/events/pools/base.py +++ b/fastlane_bot/events/pools/base.py @@ -36,7 +36,7 @@ class Pool(ABC): __DATE__ = "2023-07-03" state: Dict[str, Any] = field(default_factory=dict) - + factory_contract = None @classmethod @abstractmethod def event_matches_format( diff --git a/fastlane_bot/helpers/poolandtokens.py b/fastlane_bot/helpers/poolandtokens.py index 08f82506d..120eaa549 100644 --- a/fastlane_bot/helpers/poolandtokens.py +++ b/fastlane_bot/helpers/poolandtokens.py @@ -26,6 +26,23 @@ class SolidlyV2StablePoolsNotSupported(Exception): pass +FEE_LOOKUP = { + 0.000001: Univ3Calculator.FEE1, + 0.000008: Univ3Calculator.FEE8, + 0.00001: Univ3Calculator.FEE10, + 0.00004: Univ3Calculator.FEE40, + 0.00008: Univ3Calculator.FEE80, + 0.0001: Univ3Calculator.FEE100, + 0.00025: Univ3Calculator.FEE250, + 0.0003: Univ3Calculator.FEE300, + 0.00045: Univ3Calculator.FEE450, + 0.0005: Univ3Calculator.FEE500, + 0.0010: Univ3Calculator.FEE1000, + 0.0025: Univ3Calculator.FEE2500, + 0.0030: Univ3Calculator.FEE3000, + 0.01: Univ3Calculator.FEE10000, + } + @dataclass class PoolAndTokens: """ @@ -559,22 +576,7 @@ def decimal_converter(idx): return lst - FEE_LOOKUP = { - 0.000001: Univ3Calculator.FEE1, - 0.000008: Univ3Calculator.FEE8, - 0.00001: Univ3Calculator.FEE10, - 0.00004: Univ3Calculator.FEE40, - 0.00008: Univ3Calculator.FEE80, - 0.0001: Univ3Calculator.FEE100, - 0.00025: Univ3Calculator.FEE250, - 0.0003: Univ3Calculator.FEE300, - 0.00045: Univ3Calculator.FEE450, - 0.0005: Univ3Calculator.FEE500, - 0.0010: Univ3Calculator.FEE1000, - 0.0025: Univ3Calculator.FEE2500, - 0.0030: Univ3Calculator.FEE3000, - 0.01: Univ3Calculator.FEE10000, - } + def _univ3_to_cpc(self) -> List[Any]: """ @@ -599,10 +601,10 @@ def _univ3_to_cpc(self) -> List[Any]: "tick": self.tick, "liquidity": self.liquidity, } - feeconst = self.FEE_LOOKUP.get(float(self.fee_float)) + feeconst = FEE_LOOKUP.get(float(self.fee_float)) if feeconst is None: raise ValueError( - f"Illegal fee for Uniswap v3 pool: {self.fee_float} [{self.FEE_LOOKUP}]]" + f"Illegal fee for Uniswap v3 pool: {self.fee_float} [{FEE_LOOKUP}]]" ) uni3 = Univ3Calculator.from_dict(args, feeconst, addrdec=self.ADDRDEC) params = uni3.cpc_params() diff --git a/fastlane_bot/pool_finder.py b/fastlane_bot/pool_finder.py new file mode 100644 index 000000000..ae7a901d5 --- /dev/null +++ b/fastlane_bot/pool_finder.py @@ -0,0 +1,233 @@ +""" +Finds liquidity pools. + +--- +(c) Copyright Bprotocol foundation 2023-24. +All rights reserved. +Licensed under MIT. +""" +from collections import defaultdict + +from typing import List, Tuple, Dict, Any + +from fastlane_bot.config.constants import ZERO_ADDRESS, UNISWAP_V2_NAME, UNISWAP_V3_NAME, SOLIDLY_V2_NAME +from fastlane_bot.config.multicaller import MultiCaller +from fastlane_bot.events.exchanges.base import Exchange + +class PoolFinder: + """A class that provides methods to find unsupported carbon pairs and triangles + within a given set of flashloan tokens and external pairs. + """ + + multicallers = [] + + def __init__(self, uni_v2_forks: List[str], uni_v3_forks: List[str], solidly_v2_forks: List[str], carbon_forks: List[str], flashloan_tokens: List[str]): + self.uni_v2_forks = uni_v2_forks + self.uni_v3_forks = uni_v3_forks + self.solidly_v2_forks = solidly_v2_forks + self.carbon_forks = carbon_forks + self.flashloan_tokens = flashloan_tokens + self.uni_v3_fee_tiers = defaultdict(set) + self.carbon_pairs_seen = set() + + def init_exchanges(self, exchanges: List[Exchange], web3: Any, multicall_address: str): + """ This function initializes multicallers that will be used for each exchange. + + The function is separated from the main __init__ function to enable easier testing. + + Args: + exchanges (List[Exchange]): List of exchange objects for which to make multicalls. + web3 (Web3): Web3 object + multicall_address (str): The address of the multicall contract. + + + """ + self.multicallers = {ex_name: {"multicaller": MultiCaller(contract=exchange.sync_factory_contract, web3=web3, multicall_address=multicall_address), "exchange": exchange} for ex_name, exchange in exchanges.items() if ex_name in self.uni_v2_forks + self.uni_v3_forks + self.solidly_v2_forks} + + def extract_univ3_fee_tiers(self, pools: List[Dict[str, Any]]): + """ + Extracts unique fee tiers for each exchange listed under Uniswap V3 forks from the provided pool data. + + Args: + pools (List[Dict[str, Any]]): List of pool dictionaries containing 'exchange_name' and 'fee'. + + This function updates the 'uni_v3_fee_tiers' dictionary where each exchange name is mapped to a set of unique fees. + """ + for pool in pools: + if pool["exchange_name"] in self.uni_v3_forks: + self.uni_v3_fee_tiers[pool["exchange_name"]].add(int(pool["fee"])) + + + def get_pools_for_unsupported_pairs(self, pools: List[Dict[str, Any]], arb_mode: str): + """ + Main flow for Poolfinder. + + Args: + pools (List[Dict[str, Any]]): A list of pool data where each pool is a dictionary. The expected keys in + each dictionary should align with the requirements of the _extract_pairs, + _find_unsupported_pairs, and _find_unsupported_triangles methods. + + Returns: + Dict: Returns a dictionary with pools sorted into different exchange types (Uni V2 forks, Uni V3 forks, + and Solidly V2 forks), each associated with their specific supporting pools based on the unsupported + configurations identified. + """ + carbon_pairs, other_pairs = self._extract_pairs(pools=pools, carbon_forks=self.carbon_forks) + if not carbon_pairs: + return [], [], [] + self.extract_univ3_fee_tiers(pools) + func = PoolFinder._find_unsupported_triangles if arb_mode in ["triangle", "multi_triangle"] else PoolFinder._find_unsupported_pairs + unsupported = func(self.flashloan_tokens, carbon_pairs=carbon_pairs, external_pairs=other_pairs) + supporting_pools = self._find_pools(unsupported) + return self._sort_exchange_pools(supporting_pools, self.uni_v2_forks, self.uni_v3_forks, self.solidly_v2_forks) + + + def _find_pools(self, unsupported_pairs: List[Tuple]) -> Dict[str, List[str]]: + """ + Collects pool addresses for each exchange, based on a set of unsupported token pairs + and flashloan tokens. The function constructs pairs of tokens from unsupported_pairs with each + flashloan token and retrieves pool data via multicall. It filters out invalid addresses. + + Args: + unsupported_pairs (List[Tuple]): A list of tuples, where each tuple contains two token addresses. + flashloan_tokens (List[str]): A list of token addresses available for flashloans. + + Returns: + Dict[str, List[str]]: A list of dictionaries, where each dictionary maps an exchange's name + to a list of valid pool addresses (i.e., non-zero addresses) obtained + from the multicall across all generated pairs. + + Raises: + Exception: An exception could be raised from the multicall operation depending on the + implementation specifics of the multicall context manager or the exchange's + get_pool_function method if it encounters a problem. + """ + pairs = [(tkn, token) for pair in unsupported_pairs for tkn in pair for token in self.flashloan_tokens] + + result_list = {} + for ex_name, ex_data in self.multicallers.items(): + mc = ex_data["multicaller"] + ex = ex_data["exchange"] + with mc: + for pair in pairs: + if ex.base_exchange_name == UNISWAP_V2_NAME: + mc.add_call(ex.get_pool_function(ex.sync_factory_contract), pair[0], pair[1]) + elif ex.base_exchange_name == UNISWAP_V3_NAME: + for fee in self.uni_v3_fee_tiers[ex.exchange_name]: + mc.add_call(ex.get_pool_function(ex.sync_factory_contract), pair[0], pair[1], fee) + elif ex.base_exchange_name == SOLIDLY_V2_NAME: + mc.add_call(ex.get_pool_function(ex.sync_factory_contract), *ex.get_pool_args(pair[0], pair[1], False)) + results = mc.multicall() + result_list[ex.exchange_name] = [mc.web3.to_checksum_address(addr) for addr in results if addr != ZERO_ADDRESS] + return result_list + + @staticmethod + def _sort_exchange_pools(ex_pools: Dict, uni_v2_forks: List[str], uni_v3_forks: List[str], solidly_v2_forks: List[str]): + """ + Categorizes pools based on the type of exchange they belong to into separate dictionaries. + + Args: + ex_pools (List[Dict]): A list of dictionary where keys are exchange names and values are lists of pool addresses. + + Returns: + Tuple[Dict, Dict, Dict]: Three dictionaries categorizing pool addresses into Uniswap V2 forks, + Uniswap V3 forks, and Solidly V2 forks. + """ + # Initialize separate dictionaries for each type of exchange fork + uni_v2_pools = {} + uni_v3_pools = {} + solidly_v2_pools = {} + + # Assign pools to the appropriate category based on the exchange type + for ex_name, pools in ex_pools.items(): + if ex_name in uni_v2_forks: + target_pools = uni_v2_pools + elif ex_name in uni_v3_forks: + target_pools = uni_v3_pools + elif ex_name in solidly_v2_forks: + target_pools = solidly_v2_pools + else: + continue # Skip exchanges that do not match any known category + + for addr in pools: + target_pools[addr] = ex_name # Map pool address to exchange name + + return uni_v2_pools, uni_v3_pools, solidly_v2_pools + + + def _extract_pairs(self, pools: List[Dict[str, Any]], carbon_forks: List[str]) -> (List, set): + """ + Extracts unique, order-insensitive pairs of tokens from pools, categorizing them + into carbon pairs and other pairs based on the exchange's presence in carbon_forks. + + Args: + pools (List[Dict[str, Any]]): List of pool dictionaries containing token addresses and exchange names. + carbon_forks (List[str]): List of exchange names categorized under carbon forks. + + Returns: + tuple: Two sets of unique token pairs, one for carbon forks and one for other exchanges. + """ + carbon_pairs = set() + other_pairs = set() + + for pool in pools: + # Create a frozenset for each pair to ensure the pair is treated as order-insensitive + pair = (pool["tkn0_address"], pool["tkn1_address"]) + frozen_pair = frozenset(pair) + + if pool["exchange_name"] in carbon_forks and frozen_pair not in self.carbon_pairs_seen: + carbon_pairs.add(pair) + self.carbon_pairs_seen.add(frozen_pair) + else: + other_pairs.add(pair) + + return list(carbon_pairs), other_pairs + + @staticmethod + def _find_unsupported_triangles(flashloan_tokens: List[str], carbon_pairs: List[Tuple], external_pairs: set) -> List[Tuple]: + """ + Identifies carbon pairs that cannot form a valid triangle with any of the flashloan tokens, + even though each side of the pair is supported externally. + + Args: + flashloan_tokens (List[str]): Tokens available for forming triangles. + carbon_pairs (List[Tuple]): Carbon pairs to check for triangle support. + external_pairs (List[Tuple[str, str]]): Pairs that are supported externally. + + Returns: + List[Tuple]: List of carbon pairs that cannot form a valid triangle. + """ + unsupported_triangles = [] + + for pair in carbon_pairs: + tkn0, tkn1 = pair[0], pair[1] + if not any((frozenset((tkn0, tkn)) in external_pairs and frozenset((tkn1, tkn)) in external_pairs) for tkn in flashloan_tokens): + unsupported_triangles.append(pair) + return unsupported_triangles + + @staticmethod + def _find_unsupported_pairs(flashloan_tokens: List[str], carbon_pairs: set, external_pairs: set): + """ + Determines which carbon pairs are unsupported based on the lack of token support and non-existence in external pairs. + + Args: + flashloan_tokens (List[str]): List of tokens supported for flashloans. + carbon_pairs (List[Tuple]): Carbon pairs to evaluate for support. + external_pairs (List[Tuple]): Pairs externally supported. + + Returns: + List[Tuple]: List of unsupported carbon pairs. + """ + unsupported_pairs = [] + for pair in carbon_pairs: + tkn0, tkn1 = pair[0], pair[1] + if (tkn0 not in flashloan_tokens and tkn1 not in flashloan_tokens): + unsupported_pairs.append(pair) + continue + if pair not in external_pairs: + unsupported_pairs.append(pair) + + return unsupported_pairs + + + diff --git a/fastlane_bot/tests/test_073_TestPoolFinder.py b/fastlane_bot/tests/test_073_TestPoolFinder.py new file mode 100644 index 000000000..4b893b36b --- /dev/null +++ b/fastlane_bot/tests/test_073_TestPoolFinder.py @@ -0,0 +1,96 @@ +from fastlane_bot.pool_finder import PoolFinder + + +def test_find_unsupported_pairs(): + flashloan_tokens = ['TokenA', 'TokenB'] + carbon_pairs = [('TokenA', 'TokenC'), ('TokenC', 'TokenD'), ('TokenB', 'TokenE')] + external_pairs = [('TokenA', 'TokenB'), ('TokenC', 'TokenE')] + # Expected result + # ('TokenA', 'TokenC') is supported by flashloan_tokens but not in external_pairs + # ('TokenC', 'TokenD') is unsupported by flashloan_tokens and not in external_pairs + # ('TokenB', 'TokenE') is supported by flashloan_tokens but not in external_pairs + expected_result = [('TokenA', 'TokenC'), ('TokenC', 'TokenD'), ('TokenB', 'TokenE')] + + # Function under test + result = PoolFinder._find_unsupported_pairs(flashloan_tokens, carbon_pairs, external_pairs) + + # Check that the function returns the correct list of unsupported pairs + assert sorted(result) == sorted(expected_result) + +def test_find_unsupported_triangles(): + flashloan_tokens = ['TokenA', 'TokenB'] + carbon_pairs = [('TokenA', 'TokenC'), ('TokenC', 'TokenD'), ('TokenB', 'TokenE')] + external_pairs = {('TokenA', 'TokenC'), ('TokenA', 'TokenD')} + # Expected result + # ('TokenA', 'TokenC') is unsupported by triangles + # ('TokenC', 'TokenD') is supported by triangles + # ('TokenB', 'TokenE') is unsupported by triangles + expected_result = [('TokenA', 'TokenC'), ('TokenB', 'TokenE')] + + # Function under test + result = PoolFinder._find_unsupported_triangles(flashloan_tokens, carbon_pairs, external_pairs) + + # Check that the function returns the correct list of unsupported pairs + assert sorted(result) == sorted(expected_result) + + +def test_extract_pairs(): + # Sample data for testing + uni_v2_exchanges = ["bob_ex"] + uni_v3_exchanges = ["fred_ex"] + solidly_v2_exchanges = ["george_ex", "moose_ex"] + flashloan_tokens = ["BNT"] + pools = [ + {"exchange_name": "CarbonX", "tkn0_address": "WBTC", "tkn1_address": "BNT"}, + {"exchange_name": "CarbonX", "tkn0_address": "BNT", "tkn1_address": "WBTC"}, # Reverse order, should be treated as same + {"exchange_name": "NonCarbon", "tkn0_address": "WETH", "tkn1_address": "USDT"}, + {"exchange_name": "NonCarbon", "tkn0_address": "USDC", "tkn1_address": "WBTC"}, + {"exchange_name": "CarbonX", "tkn0_address": "WETH", "tkn1_address": "USDC"} + ] + carbon_forks = ["CarbonX"] + + # Expected results + expected_carbon_pairs = {frozenset(('WBTC', 'BNT')), frozenset(('WETH', 'USDC'))} + expected_other_pairs = {frozenset(('WETH', 'USDT')), frozenset(('USDC', 'WBTC'))} + #expected_carbon_pairs = [('WBTC', 'BNT'), ('WETH', 'USDC')] + pool_finder = PoolFinder(uni_v2_exchanges, uni_v3_exchanges, solidly_v2_exchanges, carbon_forks, flashloan_tokens) + + # Call the function with test data + carbon_pairs, other_pairs = pool_finder._extract_pairs(pools, carbon_forks) + + # Assert the results are as expected + assert frozenset(carbon_pairs[0]) in expected_carbon_pairs + assert frozenset(carbon_pairs[1]) in expected_carbon_pairs + for _pair in other_pairs: + assert _pair in expected_other_pairs + #assert other_pairs == expected_other_pairs + assert len(carbon_pairs) == 2 + assert len(other_pairs) == 2 + +def test_sort_exchanges(): + exchange_pools = { + "bob_ex": ["1", "2", "3"], + "fred_ex": ["4", "5"], + "george_ex": ["6", "7", "8"], + "moose_ex": ["9", "10", "11", "12"] + } + + uni_v2_exchanges = ["bob_ex"] + uni_v3_exchanges = ["fred_ex"] + solidly_v2_exchanges = ["george_ex", "moose_ex"] + uni_v2_pools, uni_v3_pools, solidly_v2_pools = PoolFinder._sort_exchange_pools(ex_pools=exchange_pools, uni_v2_forks=uni_v2_exchanges, uni_v3_forks=uni_v3_exchanges, solidly_v2_forks=solidly_v2_exchanges) + + + assert len(uni_v2_pools.keys()) == 3 + assert len(uni_v3_pools.keys()) == 2 + assert len(solidly_v2_pools.keys()) == 7 + + assert uni_v2_pools["1"] == "bob_ex" + assert uni_v3_pools["5"] == "fred_ex" + assert solidly_v2_pools["7"] == "george_ex" + assert solidly_v2_pools["9"] == "moose_ex" + + + + + diff --git a/main.py b/main.py index f2dce7d9c..3165d3059 100644 --- a/main.py +++ b/main.py @@ -8,6 +8,7 @@ from fastlane_bot.events.event_gatherer import EventGatherer from fastlane_bot.exceptions import ReadOnlyException, FlashloanUnavailableException from fastlane_bot.events.version_utils import check_version_requirements +from fastlane_bot.pool_finder import PoolFinder from fastlane_bot.tools.cpc import T check_version_requirements(required_version="6.11.0", package_name="web3") @@ -224,6 +225,7 @@ def main(args: argparse.Namespace) -> None: prefix_path: {args.prefix_path} self_fund: {args.self_fund} read_only: {args.read_only} + pool_finder: {args.pool_finder} +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -304,6 +306,10 @@ def run(mgr, args, tenderly_uri=None) -> None: event_gatherer = EventGatherer(w3=mgr.w3_async, exchanges=mgr.exchanges, event_contracts=mgr.event_contracts) + pool_finder = PoolFinder(uni_v2_forks=mgr.cfg.network.UNI_V2_FORKS, uni_v3_forks=mgr.cfg.network.UNI_V3_FORKS, solidly_v2_forks=mgr.cfg.network.SOLIDLY_V2_FORKS, carbon_forks=mgr.cfg.network.CARBON_V1_FORKS, flashloan_tokens=args.flashloan_tokens) if args.pool_finder != -1 else None + if pool_finder: + pool_finder.init_exchanges(exchanges=mgr.exchanges, web3=mgr.web3, multicall_address=mgr.cfg.network.MULTICALL_CONTRACT_ADDRESS) + while True: try: # ensure 'last_updated_block' is in pool_data for all pools @@ -513,6 +519,12 @@ def run(mgr, args, tenderly_uri=None) -> None: mgr.solidly_v2_event_mappings = dict( solidly_v2_event_mappings[["address", "exchange"]].values ) + if args.pool_finder != -1 and (loop_idx % args.pool_finder == 0 or loop_idx == 1): + uni_v2, uni_v3, solidly_v2 = pool_finder.get_pools_for_unsupported_pairs(mgr.pool_data, arb_mode=args.arb_mode) + mgr.uniswap_v2_event_mappings.update(uni_v2) + mgr.uniswap_v3_event_mappings.update(uni_v3) + mgr.solidly_v2_event_mappings.update(solidly_v2) + last_block_queried = current_block total_iteration_time += time.time() - iteration_start_time @@ -668,7 +680,7 @@ def run(mgr, args, tenderly_uri=None) -> None: ) parser.add_argument( "--blockchain", - default="ethereum", + default="coinbase_base", help="A blockchain from the list. Blockchains not in this list do not have a deployed Fast Lane contract and are not supported.", choices=["ethereum", "coinbase_base", "fantom", "mantle", "linea", "sei"], ) @@ -709,6 +721,11 @@ def run(mgr, args, tenderly_uri=None) -> None: default=None, help="Custom RPC URL. If not set, the bot will use the default Alchemy RPC URL for the blockchain (if available).", ) + parser.add_argument( + "--pool_finder", + default=100, + help="If not -1, searches for pools that can service Carbon strategies that do not have viable routes.", + ) # Process the arguments args = parser.parse_args() From c9afde9b6322ae2a73bd0c8fc90915b9cf3dd7cd Mon Sep 17 00:00:00 2001 From: Lesigh-3100 Date: Wed, 8 May 2024 11:08:34 +0300 Subject: [PATCH 079/131] Fix to test & code --- fastlane_bot/pool_finder.py | 9 +++++---- fastlane_bot/tests/test_073_TestPoolFinder.py | 11 ++++++----- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/fastlane_bot/pool_finder.py b/fastlane_bot/pool_finder.py index ae7a901d5..f692cc341 100644 --- a/fastlane_bot/pool_finder.py +++ b/fastlane_bot/pool_finder.py @@ -175,9 +175,10 @@ def _extract_pairs(self, pools: List[Dict[str, Any]], carbon_forks: List[str]) - pair = (pool["tkn0_address"], pool["tkn1_address"]) frozen_pair = frozenset(pair) - if pool["exchange_name"] in carbon_forks and frozen_pair not in self.carbon_pairs_seen: - carbon_pairs.add(pair) - self.carbon_pairs_seen.add(frozen_pair) + if pool["exchange_name"] in carbon_forks: + if frozen_pair not in self.carbon_pairs_seen: + carbon_pairs.add(pair) + self.carbon_pairs_seen.add(frozen_pair) else: other_pairs.add(pair) @@ -206,7 +207,7 @@ def _find_unsupported_triangles(flashloan_tokens: List[str], carbon_pairs: List[ return unsupported_triangles @staticmethod - def _find_unsupported_pairs(flashloan_tokens: List[str], carbon_pairs: set, external_pairs: set): + def _find_unsupported_pairs(flashloan_tokens: List[str], carbon_pairs: List[Tuple], external_pairs: set): """ Determines which carbon pairs are unsupported based on the lack of token support and non-existence in external pairs. diff --git a/fastlane_bot/tests/test_073_TestPoolFinder.py b/fastlane_bot/tests/test_073_TestPoolFinder.py index 4b893b36b..e6bbe1262 100644 --- a/fastlane_bot/tests/test_073_TestPoolFinder.py +++ b/fastlane_bot/tests/test_073_TestPoolFinder.py @@ -4,7 +4,7 @@ def test_find_unsupported_pairs(): flashloan_tokens = ['TokenA', 'TokenB'] carbon_pairs = [('TokenA', 'TokenC'), ('TokenC', 'TokenD'), ('TokenB', 'TokenE')] - external_pairs = [('TokenA', 'TokenB'), ('TokenC', 'TokenE')] + external_pairs = {frozenset(('TokenA', 'TokenB')), frozenset(('TokenC', 'TokenE'))} # Expected result # ('TokenA', 'TokenC') is supported by flashloan_tokens but not in external_pairs # ('TokenC', 'TokenD') is unsupported by flashloan_tokens and not in external_pairs @@ -20,7 +20,7 @@ def test_find_unsupported_pairs(): def test_find_unsupported_triangles(): flashloan_tokens = ['TokenA', 'TokenB'] carbon_pairs = [('TokenA', 'TokenC'), ('TokenC', 'TokenD'), ('TokenB', 'TokenE')] - external_pairs = {('TokenA', 'TokenC'), ('TokenA', 'TokenD')} + external_pairs = {frozenset(('TokenA', 'TokenC')), frozenset(('TokenA', 'TokenD'))} # Expected result # ('TokenA', 'TokenC') is unsupported by triangles # ('TokenC', 'TokenD') is supported by triangles @@ -31,7 +31,8 @@ def test_find_unsupported_triangles(): result = PoolFinder._find_unsupported_triangles(flashloan_tokens, carbon_pairs, external_pairs) # Check that the function returns the correct list of unsupported pairs - assert sorted(result) == sorted(expected_result) + assert len(expected_result) == len(result) + assert sorted(expected_result) == sorted(result) def test_extract_pairs(): @@ -53,7 +54,7 @@ def test_extract_pairs(): expected_carbon_pairs = {frozenset(('WBTC', 'BNT')), frozenset(('WETH', 'USDC'))} expected_other_pairs = {frozenset(('WETH', 'USDT')), frozenset(('USDC', 'WBTC'))} #expected_carbon_pairs = [('WBTC', 'BNT'), ('WETH', 'USDC')] - pool_finder = PoolFinder(uni_v2_exchanges, uni_v3_exchanges, solidly_v2_exchanges, carbon_forks, flashloan_tokens) + pool_finder = PoolFinder(uni_v2_forks=uni_v2_exchanges, uni_v3_forks=uni_v3_exchanges, solidly_v2_forks=solidly_v2_exchanges, carbon_forks=carbon_forks, flashloan_tokens=flashloan_tokens) # Call the function with test data carbon_pairs, other_pairs = pool_finder._extract_pairs(pools, carbon_forks) @@ -62,7 +63,7 @@ def test_extract_pairs(): assert frozenset(carbon_pairs[0]) in expected_carbon_pairs assert frozenset(carbon_pairs[1]) in expected_carbon_pairs for _pair in other_pairs: - assert _pair in expected_other_pairs + assert frozenset(_pair) in expected_other_pairs #assert other_pairs == expected_other_pairs assert len(carbon_pairs) == 2 assert len(other_pairs) == 2 From 11fd3b731f27baeb1075883d104e5ecb9b58db10 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Wed, 8 May 2024 21:45:14 +0200 Subject: [PATCH 080/131] feat: dedicated Exchange types for distinct solidly forks --- fastlane_bot/events/exchanges/solidly_v2.py | 181 ------------------ .../events/exchanges/solidly_v2/__init__.py | 25 +++ .../events/exchanges/solidly_v2/base.py | 78 ++++++++ .../exchanges/solidly_v2/cleopatra_v2.py | 22 +++ .../exchanges/solidly_v2/equalizer_v2.py | 22 +++ .../events/exchanges/solidly_v2/lynex_v2.py | 22 +++ .../events/exchanges/solidly_v2/nile_v2.py | 22 +++ .../events/exchanges/solidly_v2/scale_v2.py | 22 +++ .../exchanges/solidly_v2/velocimeter_v2.py | 22 +++ .../exchanges/solidly_v2/velodrome_v2.py | 22 +++ .../events/exchanges/solidly_v2/xfai_v0.py | 36 ++++ run_blockchain_terraformer.py | 4 +- 12 files changed, 295 insertions(+), 183 deletions(-) delete mode 100644 fastlane_bot/events/exchanges/solidly_v2.py create mode 100644 fastlane_bot/events/exchanges/solidly_v2/__init__.py create mode 100644 fastlane_bot/events/exchanges/solidly_v2/base.py create mode 100644 fastlane_bot/events/exchanges/solidly_v2/cleopatra_v2.py create mode 100644 fastlane_bot/events/exchanges/solidly_v2/equalizer_v2.py create mode 100644 fastlane_bot/events/exchanges/solidly_v2/lynex_v2.py create mode 100644 fastlane_bot/events/exchanges/solidly_v2/nile_v2.py create mode 100644 fastlane_bot/events/exchanges/solidly_v2/scale_v2.py create mode 100644 fastlane_bot/events/exchanges/solidly_v2/velocimeter_v2.py create mode 100644 fastlane_bot/events/exchanges/solidly_v2/velodrome_v2.py create mode 100644 fastlane_bot/events/exchanges/solidly_v2/xfai_v0.py diff --git a/fastlane_bot/events/exchanges/solidly_v2.py b/fastlane_bot/events/exchanges/solidly_v2.py deleted file mode 100644 index 5d3951c11..000000000 --- a/fastlane_bot/events/exchanges/solidly_v2.py +++ /dev/null @@ -1,181 +0,0 @@ -""" -Contains the exchange class for SolidlyV2. - -This class is responsible for handling SolidlyV2 events and updating the state of the pools. - - -[DOC-TODO-OPTIONAL-longer description in rst format] - ---- -(c) Copyright Bprotocol foundation 2023-24. -All rights reserved. -Licensed under MIT. -""" -from dataclasses import dataclass -from typing import List, Type, Tuple, Any - -from web3.contract import Contract, AsyncContract - -from fastlane_bot.data.abi import SOLIDLY_V2_POOL_ABI, VELOCIMETER_V2_FACTORY_ABI, SOLIDLY_V2_FACTORY_ABI, \ - SCALE_V2_FACTORY_ABI, CLEOPATRA_V2_FACTORY_ABI, LYNEX_V2_FACTORY_ABI, NILE_V2_FACTORY_ABI, \ - XFAI_V0_FACTORY_ABI, XFAI_V0_CORE_ABI, XFAI_V0_POOL_ABI -from ..exchanges.base import Exchange -from ..pools.base import Pool -from ..interfaces.subscription import Subscription - - -async def _get_fee_1(address: str, contract: Contract, factory_contract: Contract) -> int: - return await factory_contract.caller.getFee(address) - -async def _get_fee_2(address: str, contract: Contract, factory_contract: Contract) -> int: - return await factory_contract.caller.getRealFee(address) - -async def _get_fee_3(address: str, contract: Contract, factory_contract: Contract) -> int: - return await factory_contract.caller.getFee(address, await contract.caller.stable()) - -async def _get_fee_4(address: str, contract: Contract, factory_contract: Contract) -> int: - return await factory_contract.caller.getPairFee(address, await contract.caller.stable()) - -async def _get_fee_5(address: str, contract: Contract, factory_contract: Contract) -> int: - return await factory_contract.caller.getFee(await contract.caller.stable()) - -async def _get_fee_6(address: str, contract: Contract, factory_contract: Contract) -> int: - return await factory_contract.caller.pairFee(address) - -async def _get_fee_7(address: str, contract: Contract, factory_contract: Contract) -> int: - core_address = factory_contract.w3.to_checksum_address(await factory_contract.caller.getXfaiCore()) - core_contract = factory_contract.w3.eth.contract(address=core_address, abi=XFAI_V0_CORE_ABI) - return await core_contract.caller.getTotalFee() - -async def _get_tkn0_A(contract: Contract) -> str: - return await contract.caller.token0() - -async def _get_tkn1_A(contract: Contract) -> str: - return await contract.caller.token1() - -async def _get_tkn0_B(contract: Contract) -> str: - return await contract.caller.poolToken() - -async def _get_tkn1_B(contract: Contract) -> str: - return "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f" # TODO Use the constant WRAPPED_GAS_TOKEN_ADDRESS for this network - - -def _get_pool_function_1(factory_contract): - """ Function to get pools from Factory. - This function is intended to be used with a Multicall. It fetches pools from a Solidly fork Factory contract. - - Args: - factory_contract: The factory contract. - - Returns: - The function. - - """ - return factory_contract.functions.getPair -def _get_pool_function_2(factory_contract): - """ Function to get pools from Factory. - This function is intended to be used with a Multicall. It fetches pools from a Solidly fork Factory contract. - - Args: - factory_contract: The factory contract. - - Returns: - The function. - - """ - return factory_contract.functions.getPool - - -def _get_pool_args_1(tkn0, tkn1, stable): - """ Function to manage args input to get pools from Factory. - - Args: - tkn0: The first token address. - tkn1: The second token address. - stable: (bool) If True, indicates a stable pool. If False, indicates a Volatile pool. - Returns: - The function returns the arguments necessary to get pool addresses from the factory contract. - - """ - return tkn0, tkn1, stable - -def _get_pool_args_2(tkn0, tkn1, stable): - """ Function to manage args input to get pools from Factory. - - Args: - tkn0: The first token address. - tkn1: The second token address. - stable: (bool) If True, indicates a stable pool. If False, indicates a Volatile pool. - Returns: - The function returns the arguments necessary to get pool addresses from the factory contract. - - """ - return tkn0 - -EXCHANGE_INFO = { - "velocimeter_v2": {"decimals": 4, "factory_abi": VELOCIMETER_V2_FACTORY_ABI, "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_1, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A, "get_pool_function": _get_pool_function_1, "get_pool_args": _get_pool_args_1}, - "equalizer_v2" : {"decimals": 4, "factory_abi": SCALE_V2_FACTORY_ABI , "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_2, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A, "get_pool_function": _get_pool_function_1, "get_pool_args": _get_pool_args_1}, - "aerodrome_v2" : {"decimals": 4, "factory_abi": SOLIDLY_V2_FACTORY_ABI , "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_3, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A, "get_pool_function": _get_pool_function_2, "get_pool_args": _get_pool_args_1}, - "velodrome_v2" : {"decimals": 4, "factory_abi": SOLIDLY_V2_FACTORY_ABI , "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_3, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A, "get_pool_function": _get_pool_function_2, "get_pool_args": _get_pool_args_1}, - "scale_v2" : {"decimals": 18, "factory_abi": SCALE_V2_FACTORY_ABI , "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_2, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A, "get_pool_function": _get_pool_function_1, "get_pool_args": _get_pool_args_1}, - "cleopatra_v2" : {"decimals": 4, "factory_abi": CLEOPATRA_V2_FACTORY_ABI , "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_4, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A, "get_pool_function": _get_pool_function_1, "get_pool_args": _get_pool_args_1}, - "stratum_v2" : {"decimals": 4, "factory_abi": VELOCIMETER_V2_FACTORY_ABI, "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_1, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A, "get_pool_function": _get_pool_function_1, "get_pool_args": _get_pool_args_1}, - "lynex_v2" : {"decimals": 4, "factory_abi": LYNEX_V2_FACTORY_ABI , "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_5, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A, "get_pool_function": _get_pool_function_1, "get_pool_args": _get_pool_args_1}, - "nile_v2" : {"decimals": 4, "factory_abi": NILE_V2_FACTORY_ABI , "pool_abi": SOLIDLY_V2_POOL_ABI, "get_fee": _get_fee_6, "get_tkn0": _get_tkn0_A, "get_tkn1": _get_tkn1_A, "get_pool_function": _get_pool_function_1, "get_pool_args": _get_pool_args_1}, - "xfai_v0" : {"decimals": 4, "factory_abi": XFAI_V0_FACTORY_ABI , "pool_abi": XFAI_V0_POOL_ABI , "get_fee": _get_fee_7, "get_tkn0": _get_tkn0_B, "get_tkn1": _get_tkn1_B, "get_pool_function": _get_pool_function_2, "get_pool_args": _get_pool_args_2}, -} - -@dataclass -class SolidlyV2(Exchange): - """ - SolidlyV2 exchange class - """ - - base_exchange_name: str = "solidly_v2" - exchange_name: str = None - fee: str = None - router_address: str = None - exchange_initialized: bool = False - - stable_fee: float = None - volatile_fee: float = None - factory_address: str = None - factory_contract: AsyncContract = None - - @property - def fee_float(self): - return float(self.fee) - - def add_pool(self, pool: Pool): - self.pools[pool.state["address"]] = pool - - def get_abi(self): - return EXCHANGE_INFO[self.exchange_name]["pool_abi"] - - @property - def get_factory_abi(self): - return EXCHANGE_INFO[self.exchange_name]["factory_abi"] - - def get_events(self, contract: Contract) -> List[Type[Contract]]: - return [contract.events.Sync] if self.exchange_initialized else [] - - def get_subscriptions(self, contract: Contract) -> List[Subscription]: - return [Subscription(contract.events.Sync)] - - async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, float]: - exchange_info = EXCHANGE_INFO[self.exchange_name] - fee = await exchange_info["get_fee"](address, contract, self.factory_contract) - fee_float = float(fee) / 10 ** exchange_info["decimals"] - return str(fee_float), fee_float - - async def get_tkn0(self, address: str, contract: Contract, event: Any) -> str: - return await EXCHANGE_INFO[self.exchange_name]["get_tkn0"](contract) - - async def get_tkn1(self, address: str, contract: Contract, event: Any) -> str: - return await EXCHANGE_INFO[self.exchange_name]["get_tkn1"](contract) - - def get_pool_function(self, factory_contract): - return EXCHANGE_INFO[self.exchange_name]["get_pool_function"](factory_contract) - - def get_pool_args(self, tkn0, tkn1, stable): - return EXCHANGE_INFO[self.exchange_name]["get_pool_args"](tkn0, tkn1, stable) diff --git a/fastlane_bot/events/exchanges/solidly_v2/__init__.py b/fastlane_bot/events/exchanges/solidly_v2/__init__.py new file mode 100644 index 000000000..c81f0bca4 --- /dev/null +++ b/fastlane_bot/events/exchanges/solidly_v2/__init__.py @@ -0,0 +1,25 @@ +from ..base import Exchange +from .velocimeter_v2 import VelocimeterV2 +from .equalizer_v2 import EqualizerV2 +from .velodrome_v2 import VelodromeV2 +from .scale_v2 import ScaleV2 +from .cleopatra_v2 import CleopatraV2 +from .lynex_v2 import LynexV2 +from .nile_v2 import NileV2 +from .xfai_v0 import XFaiV2 + + +class SolidlyV2(Exchange): + def __new__(cls, **kwargs): + return { + "velocimeter_v2": VelocimeterV2, + "equalizer_v2": EqualizerV2, + "aerodrome_v2": VelodromeV2, + "velodrome_v2": VelodromeV2, + "scale_v2": ScaleV2, + "cleopatra_v2": CleopatraV2, + "stratum_v2": VelocimeterV2, + "lynex_v2": LynexV2, + "nile_v2": NileV2, + "xfai_v0": XFaiV2, + }[kwargs["exchange_name"]](**kwargs) diff --git a/fastlane_bot/events/exchanges/solidly_v2/base.py b/fastlane_bot/events/exchanges/solidly_v2/base.py new file mode 100644 index 000000000..56287b650 --- /dev/null +++ b/fastlane_bot/events/exchanges/solidly_v2/base.py @@ -0,0 +1,78 @@ +""" +Contains the exchange class for SolidlyV2. + +This class is responsible for handling SolidlyV2 events and updating the state of the pools. + + +[DOC-TODO-OPTIONAL-longer description in rst format] + +--- +(c) Copyright Bprotocol foundation 2023-24. +All rights reserved. +Licensed under MIT. +""" +from abc import abstractmethod +from dataclasses import dataclass +from typing import List, Type, Any + +from web3.contract import Contract, AsyncContract + +from fastlane_bot.data.abi import SOLIDLY_V2_POOL_ABI +from fastlane_bot.events.exchanges.base import Exchange +from ...exchanges.base import Exchange +from ...pools.base import Pool +from ...interfaces.subscription import Subscription + + +@dataclass +class SolidlyV2(Exchange): + """ + SolidlyV2 exchange class + """ + base_exchange_name: str = "solidly_v2" + exchange_name: str = None + fee: str = None + router_address: str = None + exchange_initialized: bool = False + + stable_fee: float = None + volatile_fee: float = None + factory_address: str = None + factory_contract: AsyncContract = None + + @property + def fee_float(self): # TODO: why is this here? + return float(self.fee) + + def add_pool(self, pool: Pool): + self.pools[pool.state["address"]] = pool + + def get_events(self, contract: Contract) -> List[Type[Contract]]: + return [contract.events.Sync] if self.exchange_initialized else [] + + def get_subscriptions(self, contract: Contract) -> List[Subscription]: + return [Subscription(contract.events.Sync)] + + def get_abi(self): + return SOLIDLY_V2_POOL_ABI + + async def get_tkn0(self, address: str, contract: Contract, event: Any) -> str: + return await contract.caller.token0() + + async def get_tkn1(self, address: str, contract: Contract, event: Any) -> str: + return await contract.caller.token1() + + def get_pool_args(self, tkn0, tkn1, stable): + return tkn0, tkn1, stable + + @property + @abstractmethod + def get_factory_abi(self): + ... + + @abstractmethod + async def get_fee(self, address: str, contract: Contract, factory_contract: Contract): + ... + + def get_pool_function(self, factory_contract): + ... diff --git a/fastlane_bot/events/exchanges/solidly_v2/cleopatra_v2.py b/fastlane_bot/events/exchanges/solidly_v2/cleopatra_v2.py new file mode 100644 index 000000000..71da0b657 --- /dev/null +++ b/fastlane_bot/events/exchanges/solidly_v2/cleopatra_v2.py @@ -0,0 +1,22 @@ +from dataclasses import dataclass +from typing import Tuple + +from web3.contract import AsyncContract + +from fastlane_bot.data.abi import CLEOPATRA_V2_FACTORY_ABI +from .base import SolidlyV2 + + +@dataclass +class CleopatraV2(SolidlyV2): + @property + def get_factory_abi(self): + return CLEOPATRA_V2_FACTORY_ABI + + async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, float]: + fee = await self.factory_contract.caller.getPairFee(address, await contract.caller.stable()) + fee_float = float(fee) / 10 ** 4 + return str(fee_float), fee_float + + def get_pool_function(self, factory_contract): + return factory_contract.functions.getPair diff --git a/fastlane_bot/events/exchanges/solidly_v2/equalizer_v2.py b/fastlane_bot/events/exchanges/solidly_v2/equalizer_v2.py new file mode 100644 index 000000000..06992a1b2 --- /dev/null +++ b/fastlane_bot/events/exchanges/solidly_v2/equalizer_v2.py @@ -0,0 +1,22 @@ +from dataclasses import dataclass +from typing import Tuple + +from web3.contract import AsyncContract + +from fastlane_bot.data.abi import SCALE_V2_FACTORY_ABI +from .base import SolidlyV2 + + +@dataclass +class EqualizerV2(SolidlyV2): + @property + def get_factory_abi(self): + return SCALE_V2_FACTORY_ABI + + async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, float]: + fee = await self.factory_contract.caller.getRealFee(address) + fee_float = float(fee) / 10 ** 4 + return str(fee_float), fee_float + + def get_pool_function(self, factory_contract): + return factory_contract.functions.getPair diff --git a/fastlane_bot/events/exchanges/solidly_v2/lynex_v2.py b/fastlane_bot/events/exchanges/solidly_v2/lynex_v2.py new file mode 100644 index 000000000..ede370136 --- /dev/null +++ b/fastlane_bot/events/exchanges/solidly_v2/lynex_v2.py @@ -0,0 +1,22 @@ +from dataclasses import dataclass +from typing import Tuple + +from web3.contract import AsyncContract + +from fastlane_bot.data.abi import LYNEX_V2_FACTORY_ABI +from .base import SolidlyV2 + + +@dataclass +class LynexV2(SolidlyV2): + @property + def get_factory_abi(self): + return LYNEX_V2_FACTORY_ABI + + async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, float]: + fee = await self.factory_contract.caller.getFee(await contract.caller.stable()) + fee_float = float(fee) / 10 ** 4 + return str(fee_float), fee_float + + def get_pool_function(self, factory_contract): + return factory_contract.functions.getPair diff --git a/fastlane_bot/events/exchanges/solidly_v2/nile_v2.py b/fastlane_bot/events/exchanges/solidly_v2/nile_v2.py new file mode 100644 index 000000000..9b90f0e26 --- /dev/null +++ b/fastlane_bot/events/exchanges/solidly_v2/nile_v2.py @@ -0,0 +1,22 @@ +from dataclasses import dataclass +from typing import Tuple + +from web3.contract import AsyncContract + +from fastlane_bot.data.abi import NILE_V2_FACTORY_ABI +from .base import SolidlyV2 + + +@dataclass +class NileV2(SolidlyV2): + @property + def get_factory_abi(self): + return NILE_V2_FACTORY_ABI + + async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, float]: + fee = await self.factory_contract.caller.pairFee(address) + fee_float = float(fee) / 10 ** 4 + return str(fee_float), fee_float + + def get_pool_function(self, factory_contract): + return factory_contract.functions.getPair diff --git a/fastlane_bot/events/exchanges/solidly_v2/scale_v2.py b/fastlane_bot/events/exchanges/solidly_v2/scale_v2.py new file mode 100644 index 000000000..29a53e118 --- /dev/null +++ b/fastlane_bot/events/exchanges/solidly_v2/scale_v2.py @@ -0,0 +1,22 @@ +from dataclasses import dataclass +from typing import Tuple + +from web3.contract import AsyncContract + +from fastlane_bot.data.abi import SCALE_V2_FACTORY_ABI +from .base import SolidlyV2 + + +@dataclass +class ScaleV2(SolidlyV2): + @property + def get_factory_abi(self): + return SCALE_V2_FACTORY_ABI + + async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, float]: + fee = await self.factory_contract.caller.getRealFee(address) + fee_float = float(fee) / 10 ** 18 + return str(fee_float), fee_float + + def get_pool_function(self, factory_contract): + return factory_contract.functions.getPair diff --git a/fastlane_bot/events/exchanges/solidly_v2/velocimeter_v2.py b/fastlane_bot/events/exchanges/solidly_v2/velocimeter_v2.py new file mode 100644 index 000000000..51b1d88ec --- /dev/null +++ b/fastlane_bot/events/exchanges/solidly_v2/velocimeter_v2.py @@ -0,0 +1,22 @@ +from dataclasses import dataclass +from typing import Tuple + +from web3.contract import AsyncContract + +from fastlane_bot.data.abi import VELOCIMETER_V2_FACTORY_ABI +from .base import SolidlyV2 + + +@dataclass +class VelocimeterV2(SolidlyV2): + @property + def get_factory_abi(self): + return VELOCIMETER_V2_FACTORY_ABI + + async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, float]: + fee = await self.factory_contract.caller.getFee(address) + fee_float = float(fee) / 10 ** 4 + return str(fee_float), fee_float + + def get_pool_function(self, factory_contract): + return factory_contract.functions.getPair diff --git a/fastlane_bot/events/exchanges/solidly_v2/velodrome_v2.py b/fastlane_bot/events/exchanges/solidly_v2/velodrome_v2.py new file mode 100644 index 000000000..9de5fdf1a --- /dev/null +++ b/fastlane_bot/events/exchanges/solidly_v2/velodrome_v2.py @@ -0,0 +1,22 @@ +from dataclasses import dataclass +from typing import Tuple + +from web3.contract import AsyncContract + +from fastlane_bot.data.abi import SOLIDLY_V2_FACTORY_ABI +from .base import SolidlyV2 + + +@dataclass +class VelodromeV2(SolidlyV2): + @property + def get_factory_abi(self): + return SOLIDLY_V2_FACTORY_ABI + + async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, float]: + fee = await self.factory_contract.caller.getFee(address, await contract.caller.stable()) + fee_float = float(fee) / 10 ** 4 + return str(fee_float), fee_float + + def get_pool_function(self, factory_contract): + return factory_contract.functions.getPool diff --git a/fastlane_bot/events/exchanges/solidly_v2/xfai_v0.py b/fastlane_bot/events/exchanges/solidly_v2/xfai_v0.py new file mode 100644 index 000000000..3ef5e2006 --- /dev/null +++ b/fastlane_bot/events/exchanges/solidly_v2/xfai_v0.py @@ -0,0 +1,36 @@ +from dataclasses import dataclass +from typing import Any, Tuple + +from web3.contract import Contract, AsyncContract + +from fastlane_bot.data.abi import XFAI_V0_POOL_ABI, XFAI_V0_FACTORY_ABI +from .base import SolidlyV2 + + +@dataclass +class XFaiV2(SolidlyV2): + def get_abi(self): + return XFAI_V0_POOL_ABI + + async def get_tkn0(self, address: str, contract: Contract, event: Any) -> str: + return await contract.caller.poolToken() + + async def get_tkn1(self, address: str, contract: Contract, event: Any) -> str: + return "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f" # TODO Use the constant WRAPPED_GAS_TOKEN_ADDRESS for this network + + def get_pool_args(self, tkn0, tkn1, stable): + return tkn0 + + @property + def get_factory_abi(self): + return XFAI_V0_FACTORY_ABI + + async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, float]: + core_address = self.factory_contract.w3.to_checksum_address(await self.factory_contract.caller.getXfaiCore()) + core_contract = self.factory_contract.w3.eth.contract(address=core_address, abi=self.get_abi()) + fee = await core_contract.caller.getTotalFee() + fee_float = float(fee) / 10 ** 4 + return str(fee_float), fee_float + + def get_pool_function(self, factory_contract): + return factory_contract.functions.getPool diff --git a/run_blockchain_terraformer.py b/run_blockchain_terraformer.py index 96269107f..1fd29fb27 100644 --- a/run_blockchain_terraformer.py +++ b/run_blockchain_terraformer.py @@ -15,7 +15,6 @@ from fastlane_bot.utils import safe_int from fastlane_bot.events.exchanges.solidly_v2 import SolidlyV2 -from fastlane_bot.events.exchanges.solidly_v2 import EXCHANGE_INFO as SOLIDLY_EXCHANGE_INFO from fastlane_bot.data.abi import ERC20_ABI, UNISWAP_V2_FACTORY_ABI, UNISWAP_V3_FACTORY_ABI import asyncio @@ -1024,8 +1023,9 @@ def terraform_blockchain(network_name: str): univ3_mapdf = pd.concat([univ3_mapdf, m_df], ignore_index=True) elif "solidly" in fork: add_to_exchange_ids(exchange=exchange_name, fork=fork) + solidly_exchange = SolidlyV2(exchange_name=exchange_name) + factory_abi = solidly_exchange.get_factory_abi - factory_abi = SOLIDLY_EXCHANGE_INFO[exchange_name]["factory_abi"] factory_contract = web3.eth.contract( address=factory_address, abi=factory_abi ) From c3b2849e8ec06c310eb1dcb4b54b514eec9e0cf2 Mon Sep 17 00:00:00 2001 From: Lesigh-3100 Date: Thu, 9 May 2024 12:45:23 +0300 Subject: [PATCH 081/131] Add chunking to Poolfinder & results logging --- fastlane_bot/pool_finder.py | 29 +++++++++++++++++------------ main.py | 3 +++ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/fastlane_bot/pool_finder.py b/fastlane_bot/pool_finder.py index f692cc341..71ce763b6 100644 --- a/fastlane_bot/pool_finder.py +++ b/fastlane_bot/pool_finder.py @@ -103,22 +103,27 @@ def _find_pools(self, unsupported_pairs: List[Tuple]) -> Dict[str, List[str]]: get_pool_function method if it encounters a problem. """ pairs = [(tkn, token) for pair in unsupported_pairs for tkn in pair for token in self.flashloan_tokens] - + chunk_size = 400 + # Create the list of chunks + chunked_pairs = [pairs[i:i + chunk_size] for i in range(0, len(pairs), chunk_size)] result_list = {} + for ex_name, ex_data in self.multicallers.items(): mc = ex_data["multicaller"] ex = ex_data["exchange"] - with mc: - for pair in pairs: - if ex.base_exchange_name == UNISWAP_V2_NAME: - mc.add_call(ex.get_pool_function(ex.sync_factory_contract), pair[0], pair[1]) - elif ex.base_exchange_name == UNISWAP_V3_NAME: - for fee in self.uni_v3_fee_tiers[ex.exchange_name]: - mc.add_call(ex.get_pool_function(ex.sync_factory_contract), pair[0], pair[1], fee) - elif ex.base_exchange_name == SOLIDLY_V2_NAME: - mc.add_call(ex.get_pool_function(ex.sync_factory_contract), *ex.get_pool_args(pair[0], pair[1], False)) - results = mc.multicall() - result_list[ex.exchange_name] = [mc.web3.to_checksum_address(addr) for addr in results if addr != ZERO_ADDRESS] + for pair_chunk in chunked_pairs: + with mc: + for pair in pair_chunk: + if ex.base_exchange_name == UNISWAP_V2_NAME: + mc.add_call(ex.get_pool_function(ex.sync_factory_contract), pair[0], pair[1]) + elif ex.base_exchange_name == UNISWAP_V3_NAME: + for fee in self.uni_v3_fee_tiers[ex.exchange_name]: + mc.add_call(ex.get_pool_function(ex.sync_factory_contract), pair[0], pair[1], fee) + elif ex.base_exchange_name == SOLIDLY_V2_NAME: + mc.add_call(ex.get_pool_function(ex.sync_factory_contract), *ex.get_pool_args(pair[0], pair[1], False)) + results = mc.multicall() + mc._contract_calls = [] + result_list[ex.exchange_name] = [mc.web3.to_checksum_address(addr) for addr in results if addr != ZERO_ADDRESS] return result_list @staticmethod diff --git a/main.py b/main.py index 3165d3059..3d51e1131 100644 --- a/main.py +++ b/main.py @@ -520,7 +520,10 @@ def run(mgr, args, tenderly_uri=None) -> None: solidly_v2_event_mappings[["address", "exchange"]].values ) if args.pool_finder != -1 and (loop_idx % args.pool_finder == 0 or loop_idx == 1): + mgr.cfg.logger.info(f"Searching for unsupported Carbon pairs.") uni_v2, uni_v3, solidly_v2 = pool_finder.get_pools_for_unsupported_pairs(mgr.pool_data, arb_mode=args.arb_mode) + result = f"Added {len(uni_v2) + len(uni_v3) + len(solidly_v2)} pools." if (uni_v2 or uni_v3 or solidly_v2) else f"No pools added." + mgr.cfg.logger.info(result) mgr.uniswap_v2_event_mappings.update(uni_v2) mgr.uniswap_v3_event_mappings.update(uni_v3) mgr.solidly_v2_event_mappings.update(solidly_v2) From 6619516263f92cdc074416c43589c38e0de130cf Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Thu, 9 May 2024 14:50:54 +0200 Subject: [PATCH 082/131] refactor: pool_finder --- fastlane_bot/events/exchanges/balancer.py | 4 +- fastlane_bot/events/exchanges/bancor_pol.py | 2 +- fastlane_bot/events/exchanges/bancor_v2.py | 2 +- fastlane_bot/events/exchanges/bancor_v3.py | 3 +- fastlane_bot/events/exchanges/carbon_v1.py | 2 +- fastlane_bot/pool_finder.py | 153 +++++++------------- main.py | 16 +- 7 files changed, 75 insertions(+), 107 deletions(-) diff --git a/fastlane_bot/events/exchanges/balancer.py b/fastlane_bot/events/exchanges/balancer.py index 3481d5fe1..c9bb4e453 100644 --- a/fastlane_bot/events/exchanges/balancer.py +++ b/fastlane_bot/events/exchanges/balancer.py @@ -91,6 +91,6 @@ async def get_tkn_n(self, address: str, contract: Contract, event: Any, index: i def get_pool_function(self, factory_contract: Contract): """ - This function is unused for Carbon. + This function is unused for Balancer. """ - pass \ No newline at end of file + raise NotImplementedError \ No newline at end of file diff --git a/fastlane_bot/events/exchanges/bancor_pol.py b/fastlane_bot/events/exchanges/bancor_pol.py index 7d0075f80..f86fd8a77 100644 --- a/fastlane_bot/events/exchanges/bancor_pol.py +++ b/fastlane_bot/events/exchanges/bancor_pol.py @@ -67,7 +67,7 @@ def get_pool_function(self, factory_contract: Contract): """ This function is unused for Bancor POL. """ - pass + raise NotImplementedError def save_strategy( self, diff --git a/fastlane_bot/events/exchanges/bancor_v2.py b/fastlane_bot/events/exchanges/bancor_v2.py index ab23a3b86..b445e4e47 100644 --- a/fastlane_bot/events/exchanges/bancor_v2.py +++ b/fastlane_bot/events/exchanges/bancor_v2.py @@ -82,4 +82,4 @@ def get_pool_function(self, factory_contract: Contract): """ This function is unused for Bancor V2. """ - pass \ No newline at end of file + raise NotImplementedError \ No newline at end of file diff --git a/fastlane_bot/events/exchanges/bancor_v3.py b/fastlane_bot/events/exchanges/bancor_v3.py index 53c584ef3..1d5328dba 100644 --- a/fastlane_bot/events/exchanges/bancor_v3.py +++ b/fastlane_bot/events/exchanges/bancor_v3.py @@ -64,8 +64,9 @@ async def get_tkn1(self, address: str, contract: Contract, event: Event) -> str: if event.args["pool"] != self.BNT_ADDRESS else event.args["tkn_address"] ) + def get_pool_function(self, factory_contract: Contract): """ This function is unused for Bancor V3. """ - pass \ No newline at end of file + raise NotImplementedError \ No newline at end of file diff --git a/fastlane_bot/events/exchanges/carbon_v1.py b/fastlane_bot/events/exchanges/carbon_v1.py index e95416c6e..2e117736b 100644 --- a/fastlane_bot/events/exchanges/carbon_v1.py +++ b/fastlane_bot/events/exchanges/carbon_v1.py @@ -249,4 +249,4 @@ def get_pool_function(self, factory_contract: Contract): """ This function is unused for Carbon. """ - pass \ No newline at end of file + raise NotImplementedError \ No newline at end of file diff --git a/fastlane_bot/pool_finder.py b/fastlane_bot/pool_finder.py index 71ce763b6..7133b8fe4 100644 --- a/fastlane_bot/pool_finder.py +++ b/fastlane_bot/pool_finder.py @@ -18,31 +18,24 @@ class PoolFinder: """A class that provides methods to find unsupported carbon pairs and triangles within a given set of flashloan tokens and external pairs. """ - - multicallers = [] - - def __init__(self, uni_v2_forks: List[str], uni_v3_forks: List[str], solidly_v2_forks: List[str], carbon_forks: List[str], flashloan_tokens: List[str]): - self.uni_v2_forks = uni_v2_forks - self.uni_v3_forks = uni_v3_forks - self.solidly_v2_forks = solidly_v2_forks - self.carbon_forks = carbon_forks - self.flashloan_tokens = flashloan_tokens - self.uni_v3_fee_tiers = defaultdict(set) - self.carbon_pairs_seen = set() - - def init_exchanges(self, exchanges: List[Exchange], web3: Any, multicall_address: str): - """ This function initializes multicallers that will be used for each exchange. - - The function is separated from the main __init__ function to enable easier testing. - - Args: - exchanges (List[Exchange]): List of exchange objects for which to make multicalls. - web3 (Web3): Web3 object - multicall_address (str): The address of the multicall contract. - - - """ - self.multicallers = {ex_name: {"multicaller": MultiCaller(contract=exchange.sync_factory_contract, web3=web3, multicall_address=multicall_address), "exchange": exchange} for ex_name, exchange in exchanges.items() if ex_name in self.uni_v2_forks + self.uni_v3_forks + self.solidly_v2_forks} + def __init__( + self, + carbon_forks: List[str], + uni_v3_forks: List[str], + flashloan_tokens: List[str], + exchanges: List[Exchange], + web3: Any, + multicall_address: str + ): + self._carbon_forks = carbon_forks + self._uni_v3_forks = uni_v3_forks + self._flashloan_tokens = flashloan_tokens + self._uni_v3_fee_tiers = defaultdict(set) + self._carbon_pairs_seen = set() + + self._exchanges = list(filter(lambda e: e.base_exchange_name in [UNISWAP_V2_NAME, UNISWAP_V3_NAME, SOLIDLY_V2_NAME], exchanges.values())) + self._web3 = web3 + self._multicall_address = multicall_address def extract_univ3_fee_tiers(self, pools: List[Dict[str, Any]]): """ @@ -54,8 +47,8 @@ def extract_univ3_fee_tiers(self, pools: List[Dict[str, Any]]): This function updates the 'uni_v3_fee_tiers' dictionary where each exchange name is mapped to a set of unique fees. """ for pool in pools: - if pool["exchange_name"] in self.uni_v3_forks: - self.uni_v3_fee_tiers[pool["exchange_name"]].add(int(pool["fee"])) + if pool["exchange_name"] in self._uni_v3_forks: + self._uni_v3_fee_tiers[pool["exchange_name"]].add(int(pool["fee"])) def get_pools_for_unsupported_pairs(self, pools: List[Dict[str, Any]], arb_mode: str): @@ -72,14 +65,16 @@ def get_pools_for_unsupported_pairs(self, pools: List[Dict[str, Any]], arb_mode: and Solidly V2 forks), each associated with their specific supporting pools based on the unsupported configurations identified. """ - carbon_pairs, other_pairs = self._extract_pairs(pools=pools, carbon_forks=self.carbon_forks) + carbon_pairs, other_pairs = self._extract_pairs(pools=pools) if not carbon_pairs: return [], [], [] - self.extract_univ3_fee_tiers(pools) - func = PoolFinder._find_unsupported_triangles if arb_mode in ["triangle", "multi_triangle"] else PoolFinder._find_unsupported_pairs - unsupported = func(self.flashloan_tokens, carbon_pairs=carbon_pairs, external_pairs=other_pairs) - supporting_pools = self._find_pools(unsupported) - return self._sort_exchange_pools(supporting_pools, self.uni_v2_forks, self.uni_v3_forks, self.solidly_v2_forks) + self.extract_univ3_fee_tiers(pools) # TODO: these should be configured per exchange + if arb_mode in ["triangle", "multi_triangle"]: + unsupported_pairs = PoolFinder._find_unsupported_triangles(self._flashloan_tokens, carbon_pairs=carbon_pairs, external_pairs=other_pairs) + else: + unsupported_pairs = PoolFinder._find_unsupported_pairs(self._flashloan_tokens, carbon_pairs=carbon_pairs, external_pairs=other_pairs) + missing_pools = self._find_pools(unsupported_pairs) + return missing_pools[UNISWAP_V2_NAME], missing_pools[UNISWAP_V3_NAME], missing_pools[SOLIDLY_V2_NAME] def _find_pools(self, unsupported_pairs: List[Tuple]) -> Dict[str, List[str]]: @@ -102,72 +97,40 @@ def _find_pools(self, unsupported_pairs: List[Tuple]) -> Dict[str, List[str]]: implementation specifics of the multicall context manager or the exchange's get_pool_function method if it encounters a problem. """ - pairs = [(tkn, token) for pair in unsupported_pairs for tkn in pair for token in self.flashloan_tokens] + pairs = [(tkn, token) for pair in unsupported_pairs for tkn in pair for token in self._flashloan_tokens] chunk_size = 400 # Create the list of chunks chunked_pairs = [pairs[i:i + chunk_size] for i in range(0, len(pairs), chunk_size)] - result_list = {} + result = defaultdict(dict) - for ex_name, ex_data in self.multicallers.items(): - mc = ex_data["multicaller"] - ex = ex_data["exchange"] + for exchange in self._exchanges: for pair_chunk in chunked_pairs: - with mc: - for pair in pair_chunk: - if ex.base_exchange_name == UNISWAP_V2_NAME: - mc.add_call(ex.get_pool_function(ex.sync_factory_contract), pair[0], pair[1]) - elif ex.base_exchange_name == UNISWAP_V3_NAME: - for fee in self.uni_v3_fee_tiers[ex.exchange_name]: - mc.add_call(ex.get_pool_function(ex.sync_factory_contract), pair[0], pair[1], fee) - elif ex.base_exchange_name == SOLIDLY_V2_NAME: - mc.add_call(ex.get_pool_function(ex.sync_factory_contract), *ex.get_pool_args(pair[0], pair[1], False)) - results = mc.multicall() - mc._contract_calls = [] - result_list[ex.exchange_name] = [mc.web3.to_checksum_address(addr) for addr in results if addr != ZERO_ADDRESS] - return result_list - - @staticmethod - def _sort_exchange_pools(ex_pools: Dict, uni_v2_forks: List[str], uni_v3_forks: List[str], solidly_v2_forks: List[str]): - """ - Categorizes pools based on the type of exchange they belong to into separate dictionaries. - - Args: - ex_pools (List[Dict]): A list of dictionary where keys are exchange names and values are lists of pool addresses. - - Returns: - Tuple[Dict, Dict, Dict]: Three dictionaries categorizing pool addresses into Uniswap V2 forks, - Uniswap V3 forks, and Solidly V2 forks. - """ - # Initialize separate dictionaries for each type of exchange fork - uni_v2_pools = {} - uni_v3_pools = {} - solidly_v2_pools = {} - - # Assign pools to the appropriate category based on the exchange type - for ex_name, pools in ex_pools.items(): - if ex_name in uni_v2_forks: - target_pools = uni_v2_pools - elif ex_name in uni_v3_forks: - target_pools = uni_v3_pools - elif ex_name in solidly_v2_forks: - target_pools = solidly_v2_pools - else: - continue # Skip exchanges that do not match any known category - - for addr in pools: - target_pools[addr] = ex_name # Map pool address to exchange name - - return uni_v2_pools, uni_v3_pools, solidly_v2_pools - - - def _extract_pairs(self, pools: List[Dict[str, Any]], carbon_forks: List[str]) -> (List, set): + mc = MultiCaller(contract=exchange.sync_factory_contract, web3=self._web3, multicall_address=self._multicall_address) + for pair in pair_chunk: + if exchange.base_exchange_name == UNISWAP_V2_NAME: + mc.add_call(exchange.get_pool_function(exchange.sync_factory_contract), pair[0], pair[1]) + elif exchange.base_exchange_name == UNISWAP_V3_NAME: + for fee in self._uni_v3_fee_tiers[exchange.exchange_name]: + mc.add_call(exchange.get_pool_function(exchange.sync_factory_contract), pair[0], pair[1], fee) + elif exchange.base_exchange_name == SOLIDLY_V2_NAME: + mc.add_call(exchange.get_pool_function(exchange.sync_factory_contract), *exchange.get_pool_args(pair[0], pair[1], False)) + response = mc.multicall() + result[exchange.base_exchange_name] = { + mc.web3.to_checksum_address(addr): exchange.exchange_name + for addr + in response + if addr != ZERO_ADDRESS + } + return result + + + def _extract_pairs(self, pools: List[Dict[str, Any]]) -> Tuple[List, set]: """ Extracts unique, order-insensitive pairs of tokens from pools, categorizing them into carbon pairs and other pairs based on the exchange's presence in carbon_forks. Args: pools (List[Dict[str, Any]]): List of pool dictionaries containing token addresses and exchange names. - carbon_forks (List[str]): List of exchange names categorized under carbon forks. Returns: tuple: Two sets of unique token pairs, one for carbon forks and one for other exchanges. @@ -178,12 +141,12 @@ def _extract_pairs(self, pools: List[Dict[str, Any]], carbon_forks: List[str]) - for pool in pools: # Create a frozenset for each pair to ensure the pair is treated as order-insensitive pair = (pool["tkn0_address"], pool["tkn1_address"]) - frozen_pair = frozenset(pair) - if pool["exchange_name"] in carbon_forks: - if frozen_pair not in self.carbon_pairs_seen: + if pool["exchange_name"] in self._carbon_forks: + frozen_pair = frozenset(pair) + if frozen_pair not in self._carbon_pairs_seen: carbon_pairs.add(pair) - self.carbon_pairs_seen.add(frozen_pair) + self._carbon_pairs_seen.add(frozen_pair) else: other_pairs.add(pair) @@ -229,11 +192,7 @@ def _find_unsupported_pairs(flashloan_tokens: List[str], carbon_pairs: List[Tupl tkn0, tkn1 = pair[0], pair[1] if (tkn0 not in flashloan_tokens and tkn1 not in flashloan_tokens): unsupported_pairs.append(pair) - continue - if pair not in external_pairs: + elif pair not in external_pairs: unsupported_pairs.append(pair) return unsupported_pairs - - - diff --git a/main.py b/main.py index 3d51e1131..a4df7f892 100644 --- a/main.py +++ b/main.py @@ -306,9 +306,17 @@ def run(mgr, args, tenderly_uri=None) -> None: event_gatherer = EventGatherer(w3=mgr.w3_async, exchanges=mgr.exchanges, event_contracts=mgr.event_contracts) - pool_finder = PoolFinder(uni_v2_forks=mgr.cfg.network.UNI_V2_FORKS, uni_v3_forks=mgr.cfg.network.UNI_V3_FORKS, solidly_v2_forks=mgr.cfg.network.SOLIDLY_V2_FORKS, carbon_forks=mgr.cfg.network.CARBON_V1_FORKS, flashloan_tokens=args.flashloan_tokens) if args.pool_finder != -1 else None - if pool_finder: - pool_finder.init_exchanges(exchanges=mgr.exchanges, web3=mgr.web3, multicall_address=mgr.cfg.network.MULTICALL_CONTRACT_ADDRESS) + if args.pool_finder != -1: + pool_finder = PoolFinder( + carbon_forks=mgr.cfg.network.CARBON_V1_FORKS, + uni_v3_forks=mgr.cfg.network.UNI_V3_FORKS, + flashloan_tokens=args.flashloan_tokens, + exchanges=mgr.exchanges, + web3=mgr.web3, + multicall_address=mgr.cfg.network.MULTICALL_CONTRACT_ADDRESS + ) + else: + pool_finder = None while True: try: @@ -519,7 +527,7 @@ def run(mgr, args, tenderly_uri=None) -> None: mgr.solidly_v2_event_mappings = dict( solidly_v2_event_mappings[["address", "exchange"]].values ) - if args.pool_finder != -1 and (loop_idx % args.pool_finder == 0 or loop_idx == 1): + if pool_finder is not None and (loop_idx % args.pool_finder == 0 or loop_idx == 1): mgr.cfg.logger.info(f"Searching for unsupported Carbon pairs.") uni_v2, uni_v3, solidly_v2 = pool_finder.get_pools_for_unsupported_pairs(mgr.pool_data, arb_mode=args.arb_mode) result = f"Added {len(uni_v2) + len(uni_v3) + len(solidly_v2)} pools." if (uni_v2 or uni_v3 or solidly_v2) else f"No pools added." From ab2e57342cd7415300848d0073f61e586c632910 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Thu, 9 May 2024 15:02:57 +0200 Subject: [PATCH 083/131] refactor: pool multical --- fastlane_bot/events/exchanges/balancer.py | 5 +++-- fastlane_bot/events/exchanges/bancor_pol.py | 5 +++-- fastlane_bot/events/exchanges/bancor_v2.py | 5 +++-- fastlane_bot/events/exchanges/bancor_v3.py | 5 +++-- fastlane_bot/events/exchanges/base.py | 6 +++--- fastlane_bot/events/exchanges/carbon_v1.py | 3 ++- fastlane_bot/events/exchanges/solidly_v2/base.py | 4 ++++ .../events/exchanges/solidly_v2/cleopatra_v2.py | 3 --- .../events/exchanges/solidly_v2/equalizer_v2.py | 3 --- .../events/exchanges/solidly_v2/lynex_v2.py | 3 --- .../events/exchanges/solidly_v2/nile_v2.py | 3 --- .../events/exchanges/solidly_v2/scale_v2.py | 3 --- .../events/exchanges/solidly_v2/velocimeter_v2.py | 3 --- .../events/exchanges/solidly_v2/velodrome_v2.py | 5 +++-- .../events/exchanges/solidly_v2/xfai_v0.py | 5 +++-- fastlane_bot/events/exchanges/uniswap_v2.py | 15 +++------------ fastlane_bot/events/exchanges/uniswap_v3.py | 15 +++------------ fastlane_bot/pool_finder.py | 8 +++----- 18 files changed, 36 insertions(+), 63 deletions(-) diff --git a/fastlane_bot/events/exchanges/balancer.py b/fastlane_bot/events/exchanges/balancer.py index c9bb4e453..ade0dc1e8 100644 --- a/fastlane_bot/events/exchanges/balancer.py +++ b/fastlane_bot/events/exchanges/balancer.py @@ -16,6 +16,7 @@ from web3.contract import Contract +from fastlane_bot.config.multicaller import MultiCaller from fastlane_bot.data.abi import BALANCER_VAULT_ABI, BALANCER_POOL_ABI_V1 from ..exchanges.base import Exchange from ..pools.base import Pool @@ -89,8 +90,8 @@ async def get_tkn_n(self, address: str, contract: Contract, event: Any, index: i token_balances = pool_balances[1] return token_balances[index] - def get_pool_function(self, factory_contract: Contract): + def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2): """ - This function is unused for Balancer. + This function is unused for Carbon. """ raise NotImplementedError \ No newline at end of file diff --git a/fastlane_bot/events/exchanges/bancor_pol.py b/fastlane_bot/events/exchanges/bancor_pol.py index f86fd8a77..64beb7840 100644 --- a/fastlane_bot/events/exchanges/bancor_pol.py +++ b/fastlane_bot/events/exchanges/bancor_pol.py @@ -16,6 +16,7 @@ from web3.contract import Contract +from fastlane_bot.config.multicaller import MultiCaller from fastlane_bot.data.abi import BANCOR_POL_ABI from fastlane_bot import Config from ..exchanges.base import Exchange @@ -63,9 +64,9 @@ async def get_tkn0(self, address: str, contract: Contract, event: Event) -> str: async def get_tkn1(self, address: str, contract: Contract, event: Event) -> str: return self.ETH_ADDRESS if event.args["token"] not in self.ETH_ADDRESS else self.BNT_ADDRESS - def get_pool_function(self, factory_contract: Contract): + def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2): """ - This function is unused for Bancor POL. + This function is unused for Carbon. """ raise NotImplementedError diff --git a/fastlane_bot/events/exchanges/bancor_v2.py b/fastlane_bot/events/exchanges/bancor_v2.py index b445e4e47..9f783c30d 100644 --- a/fastlane_bot/events/exchanges/bancor_v2.py +++ b/fastlane_bot/events/exchanges/bancor_v2.py @@ -17,6 +17,7 @@ from web3 import AsyncWeb3 from web3.contract import Contract, AsyncContract +from fastlane_bot.config.multicaller import MultiCaller from fastlane_bot.data.abi import BANCOR_V2_CONVERTER_ABI from ..exchanges.base import Exchange from ..pools.base import Pool @@ -78,8 +79,8 @@ async def get_tkn1(self, address: str, contract: Contract, event: Event) -> str: async def get_anchor(self, contract: Contract) -> str: return await contract.caller.anchor() - def get_pool_function(self, factory_contract: Contract): + def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2): """ - This function is unused for Bancor V2. + This function is unused for Carbon. """ raise NotImplementedError \ No newline at end of file diff --git a/fastlane_bot/events/exchanges/bancor_v3.py b/fastlane_bot/events/exchanges/bancor_v3.py index 1d5328dba..f1f5d9092 100644 --- a/fastlane_bot/events/exchanges/bancor_v3.py +++ b/fastlane_bot/events/exchanges/bancor_v3.py @@ -16,6 +16,7 @@ from web3.contract import Contract +from fastlane_bot.config.multicaller import MultiCaller from fastlane_bot.data.abi import BANCOR_V3_POOL_COLLECTION_ABI from ..exchanges.base import Exchange from ..pools.base import Pool @@ -65,8 +66,8 @@ async def get_tkn1(self, address: str, contract: Contract, event: Event) -> str: else event.args["tkn_address"] ) - def get_pool_function(self, factory_contract: Contract): + def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2): """ - This function is unused for Bancor V3. + This function is unused for Carbon. """ raise NotImplementedError \ No newline at end of file diff --git a/fastlane_bot/events/exchanges/base.py b/fastlane_bot/events/exchanges/base.py index fd13105d2..2f6095efd 100644 --- a/fastlane_bot/events/exchanges/base.py +++ b/fastlane_bot/events/exchanges/base.py @@ -17,6 +17,7 @@ from web3.contract import Contract, AsyncContract from fastlane_bot.config.constants import CARBON_V1_NAME +from fastlane_bot.config.multicaller import MultiCaller from ..pools.base import Pool from ..interfaces.subscription import Subscription @@ -123,13 +124,12 @@ async def get_fee(address: str, contract: AsyncContract) -> float: """ pass - @staticmethod @abstractmethod - def get_pool_function(contract: Contract, *args): + def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2, *args): """ Returns the Factory contract function used to fetch liquidity pools. """ - pass + ... @staticmethod @abstractmethod diff --git a/fastlane_bot/events/exchanges/carbon_v1.py b/fastlane_bot/events/exchanges/carbon_v1.py index 2e117736b..fa1ebe985 100644 --- a/fastlane_bot/events/exchanges/carbon_v1.py +++ b/fastlane_bot/events/exchanges/carbon_v1.py @@ -17,6 +17,7 @@ from fastlane_bot import Config from web3.contract import Contract +from fastlane_bot.config.multicaller import MultiCaller from fastlane_bot.data.abi import CARBON_CONTROLLER_ABI from ..exchanges.base import Exchange from ..pools.base import Pool @@ -245,7 +246,7 @@ def save_strategy( block_number=block_number, ) - def get_pool_function(self, factory_contract: Contract): + def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2): """ This function is unused for Carbon. """ diff --git a/fastlane_bot/events/exchanges/solidly_v2/base.py b/fastlane_bot/events/exchanges/solidly_v2/base.py index 56287b650..58c1433f2 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/base.py +++ b/fastlane_bot/events/exchanges/solidly_v2/base.py @@ -17,6 +17,7 @@ from web3.contract import Contract, AsyncContract +from fastlane_bot.config.multicaller import MultiCaller from fastlane_bot.data.abi import SOLIDLY_V2_POOL_ABI from fastlane_bot.events.exchanges.base import Exchange from ...exchanges.base import Exchange @@ -62,6 +63,9 @@ async def get_tkn0(self, address: str, contract: Contract, event: Any) -> str: async def get_tkn1(self, address: str, contract: Contract, event: Any) -> str: return await contract.caller.token1() + def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2): + mc.add_call(self.sync_factory_contract.functions.getPair, addr1, addr2, True) + def get_pool_args(self, tkn0, tkn1, stable): return tkn0, tkn1, stable diff --git a/fastlane_bot/events/exchanges/solidly_v2/cleopatra_v2.py b/fastlane_bot/events/exchanges/solidly_v2/cleopatra_v2.py index 71da0b657..94662910a 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/cleopatra_v2.py +++ b/fastlane_bot/events/exchanges/solidly_v2/cleopatra_v2.py @@ -17,6 +17,3 @@ async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, flo fee = await self.factory_contract.caller.getPairFee(address, await contract.caller.stable()) fee_float = float(fee) / 10 ** 4 return str(fee_float), fee_float - - def get_pool_function(self, factory_contract): - return factory_contract.functions.getPair diff --git a/fastlane_bot/events/exchanges/solidly_v2/equalizer_v2.py b/fastlane_bot/events/exchanges/solidly_v2/equalizer_v2.py index 06992a1b2..861e53777 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/equalizer_v2.py +++ b/fastlane_bot/events/exchanges/solidly_v2/equalizer_v2.py @@ -17,6 +17,3 @@ async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, flo fee = await self.factory_contract.caller.getRealFee(address) fee_float = float(fee) / 10 ** 4 return str(fee_float), fee_float - - def get_pool_function(self, factory_contract): - return factory_contract.functions.getPair diff --git a/fastlane_bot/events/exchanges/solidly_v2/lynex_v2.py b/fastlane_bot/events/exchanges/solidly_v2/lynex_v2.py index ede370136..b3564b306 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/lynex_v2.py +++ b/fastlane_bot/events/exchanges/solidly_v2/lynex_v2.py @@ -17,6 +17,3 @@ async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, flo fee = await self.factory_contract.caller.getFee(await contract.caller.stable()) fee_float = float(fee) / 10 ** 4 return str(fee_float), fee_float - - def get_pool_function(self, factory_contract): - return factory_contract.functions.getPair diff --git a/fastlane_bot/events/exchanges/solidly_v2/nile_v2.py b/fastlane_bot/events/exchanges/solidly_v2/nile_v2.py index 9b90f0e26..3e4102ecb 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/nile_v2.py +++ b/fastlane_bot/events/exchanges/solidly_v2/nile_v2.py @@ -17,6 +17,3 @@ async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, flo fee = await self.factory_contract.caller.pairFee(address) fee_float = float(fee) / 10 ** 4 return str(fee_float), fee_float - - def get_pool_function(self, factory_contract): - return factory_contract.functions.getPair diff --git a/fastlane_bot/events/exchanges/solidly_v2/scale_v2.py b/fastlane_bot/events/exchanges/solidly_v2/scale_v2.py index 29a53e118..f0d50dec1 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/scale_v2.py +++ b/fastlane_bot/events/exchanges/solidly_v2/scale_v2.py @@ -17,6 +17,3 @@ async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, flo fee = await self.factory_contract.caller.getRealFee(address) fee_float = float(fee) / 10 ** 18 return str(fee_float), fee_float - - def get_pool_function(self, factory_contract): - return factory_contract.functions.getPair diff --git a/fastlane_bot/events/exchanges/solidly_v2/velocimeter_v2.py b/fastlane_bot/events/exchanges/solidly_v2/velocimeter_v2.py index 51b1d88ec..858d36ecd 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/velocimeter_v2.py +++ b/fastlane_bot/events/exchanges/solidly_v2/velocimeter_v2.py @@ -17,6 +17,3 @@ async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, flo fee = await self.factory_contract.caller.getFee(address) fee_float = float(fee) / 10 ** 4 return str(fee_float), fee_float - - def get_pool_function(self, factory_contract): - return factory_contract.functions.getPair diff --git a/fastlane_bot/events/exchanges/solidly_v2/velodrome_v2.py b/fastlane_bot/events/exchanges/solidly_v2/velodrome_v2.py index 9de5fdf1a..eb9392ac7 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/velodrome_v2.py +++ b/fastlane_bot/events/exchanges/solidly_v2/velodrome_v2.py @@ -3,6 +3,7 @@ from web3.contract import AsyncContract +from fastlane_bot.config.multicaller import MultiCaller from fastlane_bot.data.abi import SOLIDLY_V2_FACTORY_ABI from .base import SolidlyV2 @@ -18,5 +19,5 @@ async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, flo fee_float = float(fee) / 10 ** 4 return str(fee_float), fee_float - def get_pool_function(self, factory_contract): - return factory_contract.functions.getPool + def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2): + mc.add_call(self.sync_factory_contract.functions.getPool, addr1, addr2, True) diff --git a/fastlane_bot/events/exchanges/solidly_v2/xfai_v0.py b/fastlane_bot/events/exchanges/solidly_v2/xfai_v0.py index 3ef5e2006..6d27b210d 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/xfai_v0.py +++ b/fastlane_bot/events/exchanges/solidly_v2/xfai_v0.py @@ -3,6 +3,7 @@ from web3.contract import Contract, AsyncContract +from fastlane_bot.config.multicaller import MultiCaller from fastlane_bot.data.abi import XFAI_V0_POOL_ABI, XFAI_V0_FACTORY_ABI from .base import SolidlyV2 @@ -32,5 +33,5 @@ async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, flo fee_float = float(fee) / 10 ** 4 return str(fee_float), fee_float - def get_pool_function(self, factory_contract): - return factory_contract.functions.getPool + def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2): + mc.add_call(self.sync_factory_contract.functions.getPool, addr1) diff --git a/fastlane_bot/events/exchanges/uniswap_v2.py b/fastlane_bot/events/exchanges/uniswap_v2.py index b08e0ef27..a21067fae 100644 --- a/fastlane_bot/events/exchanges/uniswap_v2.py +++ b/fastlane_bot/events/exchanges/uniswap_v2.py @@ -16,6 +16,7 @@ from web3.contract import Contract, AsyncContract +from fastlane_bot.config.multicaller import MultiCaller from fastlane_bot.data.abi import UNISWAP_V2_POOL_ABI, UNISWAP_V2_FACTORY_ABI from ..exchanges.base import Exchange from ..pools.base import Pool @@ -63,15 +64,5 @@ async def get_tkn0(address: str, contract: AsyncContract, event: Any) -> str: async def get_tkn1(address: str, contract: AsyncContract, event: Any) -> str: return await contract.caller.token1() - def get_pool_function(self, factory_contract: Contract): - """ Function to get pools from Factory. - This function is intended to be used with a Multicall. It fetches pools from a Uniswap V2 fork Factory contract. - - Args: - factory_contract: The factory contract. - - Returns: - The function. - - """ - return factory_contract.functions.getPair + def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2): + mc.add_call(self.sync_factory_contract.functions.getPair, addr1, addr2) diff --git a/fastlane_bot/events/exchanges/uniswap_v3.py b/fastlane_bot/events/exchanges/uniswap_v3.py index 0eb8fb6c4..14f31855d 100644 --- a/fastlane_bot/events/exchanges/uniswap_v3.py +++ b/fastlane_bot/events/exchanges/uniswap_v3.py @@ -17,6 +17,7 @@ from web3.contract import Contract, AsyncContract from fastlane_bot.config.constants import AGNI_V3_NAME, PANCAKESWAP_V3_NAME, FUSIONX_V3_NAME, ECHODEX_V3_NAME, SECTA_V3_NAME +from fastlane_bot.config.multicaller import MultiCaller from fastlane_bot.data.abi import UNISWAP_V3_POOL_ABI, UNISWAP_V3_FACTORY_ABI, PANCAKESWAP_V3_POOL_ABI from ..exchanges.base import Exchange from ..pools.base import Pool @@ -60,15 +61,5 @@ async def get_tkn0(self, address: str, contract: Contract, event: Any) -> str: async def get_tkn1(self, address: str, contract: Contract, event: Any) -> str: return await contract.caller.token1() - def get_pool_function(self, factory_contract: Contract): - """ Function to get pools from Factory. - This function is intended to be used with a Multicall. It fetches pools from a Uniswap V3 fork Factory contract. - - Args: - factory_contract: The factory contract. - - Returns: - The function. - - """ - return factory_contract.functions.getPool + def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2, fee): + mc.add_call(self.sync_factory_contract.functions.getPool, addr1, addr2, fee) diff --git a/fastlane_bot/pool_finder.py b/fastlane_bot/pool_finder.py index 7133b8fe4..3a6969dfe 100644 --- a/fastlane_bot/pool_finder.py +++ b/fastlane_bot/pool_finder.py @@ -107,13 +107,11 @@ def _find_pools(self, unsupported_pairs: List[Tuple]) -> Dict[str, List[str]]: for pair_chunk in chunked_pairs: mc = MultiCaller(contract=exchange.sync_factory_contract, web3=self._web3, multicall_address=self._multicall_address) for pair in pair_chunk: - if exchange.base_exchange_name == UNISWAP_V2_NAME: - mc.add_call(exchange.get_pool_function(exchange.sync_factory_contract), pair[0], pair[1]) + if exchange.base_exchange_name in [UNISWAP_V2_NAME, SOLIDLY_V2_NAME]: + exchange.get_pool_with_multicall(mc, pair[0], pair[1]) elif exchange.base_exchange_name == UNISWAP_V3_NAME: for fee in self._uni_v3_fee_tiers[exchange.exchange_name]: - mc.add_call(exchange.get_pool_function(exchange.sync_factory_contract), pair[0], pair[1], fee) - elif exchange.base_exchange_name == SOLIDLY_V2_NAME: - mc.add_call(exchange.get_pool_function(exchange.sync_factory_contract), *exchange.get_pool_args(pair[0], pair[1], False)) + exchange.get_pool_with_multicall(mc, pair[0], pair[1], fee) response = mc.multicall() result[exchange.base_exchange_name] = { mc.web3.to_checksum_address(addr): exchange.exchange_name From 654a0eb4a1761b994bc0c0f4f2eed1564bef575d Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Thu, 9 May 2024 15:10:16 +0200 Subject: [PATCH 084/131] fix: PR review --- fastlane_bot/events/managers/base.py | 1 + main.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/fastlane_bot/events/managers/base.py b/fastlane_bot/events/managers/base.py index 6600c9304..a410135f7 100644 --- a/fastlane_bot/events/managers/base.py +++ b/fastlane_bot/events/managers/base.py @@ -164,6 +164,7 @@ def initialize_factory_contract(self, exchange): exchange.sync_factory_contract = self.sync_factory_contracts[exchange.exchange_name] return exchange + @property def fee_pairs(self) -> Dict: """ diff --git a/main.py b/main.py index a4df7f892..d926d5614 100644 --- a/main.py +++ b/main.py @@ -691,7 +691,7 @@ def run(mgr, args, tenderly_uri=None) -> None: ) parser.add_argument( "--blockchain", - default="coinbase_base", + default="ethereum", help="A blockchain from the list. Blockchains not in this list do not have a deployed Fast Lane contract and are not supported.", choices=["ethereum", "coinbase_base", "fantom", "mantle", "linea", "sei"], ) From b035165afd627642a61231a45bbfbfc21148ed19 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Thu, 9 May 2024 19:39:21 +0200 Subject: [PATCH 085/131] refactor: factory contract and abi --- fastlane_bot/events/exchanges/balancer.py | 2 +- fastlane_bot/events/exchanges/bancor_pol.py | 2 +- fastlane_bot/events/exchanges/bancor_v2.py | 2 +- fastlane_bot/events/exchanges/bancor_v3.py | 2 +- fastlane_bot/events/exchanges/base.py | 4 +-- fastlane_bot/events/exchanges/carbon_v1.py | 2 +- fastlane_bot/events/exchanges/factory.py | 13 ++++++- .../events/exchanges/solidly_v2/base.py | 10 ++---- .../exchanges/solidly_v2/cleopatra_v2.py | 2 +- .../exchanges/solidly_v2/equalizer_v2.py | 2 +- .../events/exchanges/solidly_v2/lynex_v2.py | 2 +- .../events/exchanges/solidly_v2/nile_v2.py | 2 +- .../events/exchanges/solidly_v2/scale_v2.py | 2 +- .../exchanges/solidly_v2/velocimeter_v2.py | 2 +- .../exchanges/solidly_v2/velodrome_v2.py | 4 +-- .../events/exchanges/solidly_v2/xfai_v0.py | 7 ++-- fastlane_bot/events/exchanges/uniswap_v2.py | 4 +-- fastlane_bot/events/exchanges/uniswap_v3.py | 4 +-- fastlane_bot/events/managers/base.py | 34 +------------------ fastlane_bot/pool_finder.py | 4 +-- run_blockchain_terraformer.py | 2 +- 21 files changed, 39 insertions(+), 69 deletions(-) diff --git a/fastlane_bot/events/exchanges/balancer.py b/fastlane_bot/events/exchanges/balancer.py index ade0dc1e8..2f9f99fc9 100644 --- a/fastlane_bot/events/exchanges/balancer.py +++ b/fastlane_bot/events/exchanges/balancer.py @@ -39,7 +39,7 @@ def get_abi(self): return BALANCER_VAULT_ABI @property - def get_factory_abi(self): + def factory_abi(self): # Not used for Balancer return BALANCER_VAULT_ABI diff --git a/fastlane_bot/events/exchanges/bancor_pol.py b/fastlane_bot/events/exchanges/bancor_pol.py index 64beb7840..3fbb0fbb0 100644 --- a/fastlane_bot/events/exchanges/bancor_pol.py +++ b/fastlane_bot/events/exchanges/bancor_pol.py @@ -42,7 +42,7 @@ def get_abi(self): return BANCOR_POL_ABI @property - def get_factory_abi(self): + def factory_abi(self): # Not used for Bancor POL return BANCOR_POL_ABI diff --git a/fastlane_bot/events/exchanges/bancor_v2.py b/fastlane_bot/events/exchanges/bancor_v2.py index 9f783c30d..41ff63860 100644 --- a/fastlane_bot/events/exchanges/bancor_v2.py +++ b/fastlane_bot/events/exchanges/bancor_v2.py @@ -41,7 +41,7 @@ def get_abi(self): return BANCOR_V2_CONVERTER_ABI @property - def get_factory_abi(self): + def factory_abi(self): # Not used for Bancor V2 return BANCOR_V2_CONVERTER_ABI diff --git a/fastlane_bot/events/exchanges/bancor_v3.py b/fastlane_bot/events/exchanges/bancor_v3.py index f1f5d9092..b21c6f7bb 100644 --- a/fastlane_bot/events/exchanges/bancor_v3.py +++ b/fastlane_bot/events/exchanges/bancor_v3.py @@ -43,7 +43,7 @@ def get_abi(self): return BANCOR_V3_POOL_COLLECTION_ABI @property - def get_factory_abi(self): + def factory_abi(self): # Not used for Bancor V3 return BANCOR_V3_POOL_COLLECTION_ABI diff --git a/fastlane_bot/events/exchanges/base.py b/fastlane_bot/events/exchanges/base.py index 2f6095efd..93020c3b5 100644 --- a/fastlane_bot/events/exchanges/base.py +++ b/fastlane_bot/events/exchanges/base.py @@ -31,7 +31,7 @@ class Exchange(ABC): exchange_name: str base_exchange_name: str = '' pools: Dict[str, Pool] = field(default_factory=dict) - sync_factory_contract: Contract = None + factory_contract: Contract = None __VERSION__ = "0.0.3" __DATE__ = "2024-03-20" @@ -195,7 +195,7 @@ def get_pool(self, key: str) -> Pool: return self.pools[key] if key in self.pools else None @abstractmethod - def get_factory_abi(self): + def factory_abi(self): """ Get the ABI of the exchange's Factory contract diff --git a/fastlane_bot/events/exchanges/carbon_v1.py b/fastlane_bot/events/exchanges/carbon_v1.py index fa1ebe985..b3708c822 100644 --- a/fastlane_bot/events/exchanges/carbon_v1.py +++ b/fastlane_bot/events/exchanges/carbon_v1.py @@ -68,7 +68,7 @@ def get_abi(self): return CARBON_CONTROLLER_ABI @property - def get_factory_abi(self): + def factory_abi(self): return CARBON_CONTROLLER_ABI def get_events(self, contract: Contract) -> List[Type[Contract]]: diff --git a/fastlane_bot/events/exchanges/factory.py b/fastlane_bot/events/exchanges/factory.py index 670bdc5df..9fb50823d 100644 --- a/fastlane_bot/events/exchanges/factory.py +++ b/fastlane_bot/events/exchanges/factory.py @@ -12,6 +12,8 @@ """ from typing import Dict, Any +from fastlane_bot.config.constants import SOLIDLY_V2_NAME, UNISWAP_V2_NAME, UNISWAP_V3_NAME + class ExchangeFactory: """ @@ -60,7 +62,16 @@ def get_exchange(self, key, cfg: Any, exchange_initialized: bool = None): creator = self._creators.get(fork_name) args = self.get_fork_extras(exchange_name=key, cfg=cfg, exchange_initialized=exchange_initialized) - return creator(**args) + exchange = creator(**args) + + base_exchange_name = cfg.network.exchange_name_base_from_fork(exchange_name=key) + if base_exchange_name in [SOLIDLY_V2_NAME, UNISWAP_V2_NAME, UNISWAP_V3_NAME]: + exchange.factory_contract = self.w3_async.eth.contract( + address=cfg.FACTORY_MAPPING[key], + abi=exchange.factory_abi, + ) + + return exchange def get_fork_extras(self, exchange_name: str, cfg: Any, exchange_initialized: bool) -> Dict[str, str]: """ diff --git a/fastlane_bot/events/exchanges/solidly_v2/base.py b/fastlane_bot/events/exchanges/solidly_v2/base.py index 58c1433f2..52a971e7e 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/base.py +++ b/fastlane_bot/events/exchanges/solidly_v2/base.py @@ -64,19 +64,13 @@ async def get_tkn1(self, address: str, contract: Contract, event: Any) -> str: return await contract.caller.token1() def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2): - mc.add_call(self.sync_factory_contract.functions.getPair, addr1, addr2, True) - - def get_pool_args(self, tkn0, tkn1, stable): - return tkn0, tkn1, stable + mc.add_call(self.factory_contract.functions.getPair, addr1, addr2, True) @property @abstractmethod - def get_factory_abi(self): + def factory_abi(self): ... @abstractmethod async def get_fee(self, address: str, contract: Contract, factory_contract: Contract): ... - - def get_pool_function(self, factory_contract): - ... diff --git a/fastlane_bot/events/exchanges/solidly_v2/cleopatra_v2.py b/fastlane_bot/events/exchanges/solidly_v2/cleopatra_v2.py index 94662910a..ecff33375 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/cleopatra_v2.py +++ b/fastlane_bot/events/exchanges/solidly_v2/cleopatra_v2.py @@ -10,7 +10,7 @@ @dataclass class CleopatraV2(SolidlyV2): @property - def get_factory_abi(self): + def factory_abi(self): return CLEOPATRA_V2_FACTORY_ABI async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, float]: diff --git a/fastlane_bot/events/exchanges/solidly_v2/equalizer_v2.py b/fastlane_bot/events/exchanges/solidly_v2/equalizer_v2.py index 861e53777..820f9a8ec 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/equalizer_v2.py +++ b/fastlane_bot/events/exchanges/solidly_v2/equalizer_v2.py @@ -10,7 +10,7 @@ @dataclass class EqualizerV2(SolidlyV2): @property - def get_factory_abi(self): + def factory_abi(self): return SCALE_V2_FACTORY_ABI async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, float]: diff --git a/fastlane_bot/events/exchanges/solidly_v2/lynex_v2.py b/fastlane_bot/events/exchanges/solidly_v2/lynex_v2.py index b3564b306..79339519d 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/lynex_v2.py +++ b/fastlane_bot/events/exchanges/solidly_v2/lynex_v2.py @@ -10,7 +10,7 @@ @dataclass class LynexV2(SolidlyV2): @property - def get_factory_abi(self): + def factory_abi(self): return LYNEX_V2_FACTORY_ABI async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, float]: diff --git a/fastlane_bot/events/exchanges/solidly_v2/nile_v2.py b/fastlane_bot/events/exchanges/solidly_v2/nile_v2.py index 3e4102ecb..fe81c9921 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/nile_v2.py +++ b/fastlane_bot/events/exchanges/solidly_v2/nile_v2.py @@ -10,7 +10,7 @@ @dataclass class NileV2(SolidlyV2): @property - def get_factory_abi(self): + def factory_abi(self): return NILE_V2_FACTORY_ABI async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, float]: diff --git a/fastlane_bot/events/exchanges/solidly_v2/scale_v2.py b/fastlane_bot/events/exchanges/solidly_v2/scale_v2.py index f0d50dec1..cb2744792 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/scale_v2.py +++ b/fastlane_bot/events/exchanges/solidly_v2/scale_v2.py @@ -10,7 +10,7 @@ @dataclass class ScaleV2(SolidlyV2): @property - def get_factory_abi(self): + def factory_abi(self): return SCALE_V2_FACTORY_ABI async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, float]: diff --git a/fastlane_bot/events/exchanges/solidly_v2/velocimeter_v2.py b/fastlane_bot/events/exchanges/solidly_v2/velocimeter_v2.py index 858d36ecd..65634dc5a 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/velocimeter_v2.py +++ b/fastlane_bot/events/exchanges/solidly_v2/velocimeter_v2.py @@ -10,7 +10,7 @@ @dataclass class VelocimeterV2(SolidlyV2): @property - def get_factory_abi(self): + def factory_abi(self): return VELOCIMETER_V2_FACTORY_ABI async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, float]: diff --git a/fastlane_bot/events/exchanges/solidly_v2/velodrome_v2.py b/fastlane_bot/events/exchanges/solidly_v2/velodrome_v2.py index eb9392ac7..1224c6df6 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/velodrome_v2.py +++ b/fastlane_bot/events/exchanges/solidly_v2/velodrome_v2.py @@ -11,7 +11,7 @@ @dataclass class VelodromeV2(SolidlyV2): @property - def get_factory_abi(self): + def factory_abi(self): return SOLIDLY_V2_FACTORY_ABI async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, float]: @@ -20,4 +20,4 @@ async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, flo return str(fee_float), fee_float def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2): - mc.add_call(self.sync_factory_contract.functions.getPool, addr1, addr2, True) + mc.add_call(self.factory_contract.functions.getPool, addr1, addr2, True) diff --git a/fastlane_bot/events/exchanges/solidly_v2/xfai_v0.py b/fastlane_bot/events/exchanges/solidly_v2/xfai_v0.py index 6d27b210d..e8d7eb55e 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/xfai_v0.py +++ b/fastlane_bot/events/exchanges/solidly_v2/xfai_v0.py @@ -19,11 +19,8 @@ async def get_tkn0(self, address: str, contract: Contract, event: Any) -> str: async def get_tkn1(self, address: str, contract: Contract, event: Any) -> str: return "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f" # TODO Use the constant WRAPPED_GAS_TOKEN_ADDRESS for this network - def get_pool_args(self, tkn0, tkn1, stable): - return tkn0 - @property - def get_factory_abi(self): + def factory_abi(self): # TODO: change to staticmethod return XFAI_V0_FACTORY_ABI async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, float]: @@ -34,4 +31,4 @@ async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, flo return str(fee_float), fee_float def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2): - mc.add_call(self.sync_factory_contract.functions.getPool, addr1) + mc.add_call(self.factory_contract.functions.getPool, addr1) diff --git a/fastlane_bot/events/exchanges/uniswap_v2.py b/fastlane_bot/events/exchanges/uniswap_v2.py index a21067fae..c7ed2615f 100644 --- a/fastlane_bot/events/exchanges/uniswap_v2.py +++ b/fastlane_bot/events/exchanges/uniswap_v2.py @@ -38,7 +38,7 @@ def fee_float(self): return float(self.fee) @property - def get_factory_abi(self): + def factory_abi(self): return UNISWAP_V2_FACTORY_ABI def add_pool(self, pool: Pool): @@ -65,4 +65,4 @@ async def get_tkn1(address: str, contract: AsyncContract, event: Any) -> str: return await contract.caller.token1() def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2): - mc.add_call(self.sync_factory_contract.functions.getPair, addr1, addr2) + mc.add_call(self.factory_contract.functions.getPair, addr1, addr2) diff --git a/fastlane_bot/events/exchanges/uniswap_v3.py b/fastlane_bot/events/exchanges/uniswap_v3.py index 14f31855d..604ba5af9 100644 --- a/fastlane_bot/events/exchanges/uniswap_v3.py +++ b/fastlane_bot/events/exchanges/uniswap_v3.py @@ -41,7 +41,7 @@ def get_abi(self): return UNISWAP_V3_POOL_ABI if self.exchange_name not in [PANCAKESWAP_V3_NAME, AGNI_V3_NAME, FUSIONX_V3_NAME, ECHODEX_V3_NAME, SECTA_V3_NAME] else PANCAKESWAP_V3_POOL_ABI @property - def get_factory_abi(self): + def factory_abi(self): return UNISWAP_V3_FACTORY_ABI def get_events(self, contract: Contract) -> List[Type[Contract]]: @@ -62,4 +62,4 @@ async def get_tkn1(self, address: str, contract: Contract, event: Any) -> str: return await contract.caller.token1() def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2, fee): - mc.add_call(self.sync_factory_contract.functions.getPool, addr1, addr2, fee) + mc.add_call(self.factory_contract.functions.getPool, addr1, addr2, fee) diff --git a/fastlane_bot/events/managers/base.py b/fastlane_bot/events/managers/base.py index a410135f7..ca6361fbd 100644 --- a/fastlane_bot/events/managers/base.py +++ b/fastlane_bot/events/managers/base.py @@ -17,7 +17,7 @@ from fastlane_bot import Config from fastlane_bot.config.constants import PANCAKESWAP_V2_NAME, PANCAKESWAP_V3_NAME, VELOCIMETER_V2_NAME, AGNI_V3_NAME, \ - SOLIDLY_V2_NAME, FUSIONX_V3_NAME, UNISWAP_V2_NAME, UNISWAP_V3_NAME + FUSIONX_V3_NAME from fastlane_bot.config.multicaller import MultiCaller from fastlane_bot.events.exchanges import exchange_factory from fastlane_bot.events.exchanges.base import Exchange @@ -78,8 +78,6 @@ class BaseManager: token_contracts: Dict[str, Contract or Type[Contract]] = field(default_factory=dict) erc20_contracts: Dict[str, Contract or Type[Contract]] = field(default_factory=dict) exchanges: Dict[str, Exchange] = field(default_factory=dict) - sync_factory_contracts: Dict[str, Contract or Type[Contract]] = field(default_factory=dict) - factory_contracts: Dict[str, Contract or Type[Contract]] = field(default_factory=dict) uniswap_v2_event_mappings: Dict[str, str] = field(default_factory=dict) uniswap_v3_event_mappings: Dict[str, str] = field(default_factory=dict) solidly_v2_event_mappings: Dict[str, str] = field(default_factory=dict) @@ -130,41 +128,11 @@ def __post_init__(self): self.SUPPORTED_BASE_EXCHANGES.append(base_exchange_name) self.exchanges[exchange_name] = exchange_factory.get_exchange(key=exchange_name, cfg=self.cfg, exchange_initialized=initialize_events) - if base_exchange_name == SOLIDLY_V2_NAME: - self.exchanges[exchange_name] = self.handle_solidly_exchanges(exchange=self.exchanges[exchange_name]) - if base_exchange_name in [SOLIDLY_V2_NAME, UNISWAP_V2_NAME, UNISWAP_V3_NAME]: - self.exchanges[exchange_name] = self.initialize_factory_contract(exchange=self.exchanges[exchange_name]) self.init_exchange_contracts() self.set_carbon_v1_fee_pairs() self.init_tenderly_event_contracts() - def handle_solidly_exchanges(self, exchange): - """ - Handles getting stable & volatile fees for Solidly forks - """ - exchange_name = exchange.exchange_name - self.factory_contracts[exchange_name] = self.w3_async.eth.contract( - address=self.cfg.FACTORY_MAPPING[exchange_name], - abi=exchange.get_factory_abi, - ) - exchange.factory_contract = self.factory_contracts[exchange.exchange_name] - - return exchange - - def initialize_factory_contract(self, exchange): - """ - Initialize factory contract for exchange. - """ - exchange_name = exchange.exchange_name - self.sync_factory_contracts[exchange_name] = self.web3.eth.contract( - address=self.cfg.FACTORY_MAPPING[exchange_name], - abi=exchange.get_factory_abi, - ) - exchange.sync_factory_contract = self.sync_factory_contracts[exchange.exchange_name] - - return exchange - @property def fee_pairs(self) -> Dict: """ diff --git a/fastlane_bot/pool_finder.py b/fastlane_bot/pool_finder.py index 3a6969dfe..8f56436e4 100644 --- a/fastlane_bot/pool_finder.py +++ b/fastlane_bot/pool_finder.py @@ -95,7 +95,7 @@ def _find_pools(self, unsupported_pairs: List[Tuple]) -> Dict[str, List[str]]: Raises: Exception: An exception could be raised from the multicall operation depending on the implementation specifics of the multicall context manager or the exchange's - get_pool_function method if it encounters a problem. + get_pool_with_multicall method if it encounters a problem. """ pairs = [(tkn, token) for pair in unsupported_pairs for tkn in pair for token in self._flashloan_tokens] chunk_size = 400 @@ -105,7 +105,7 @@ def _find_pools(self, unsupported_pairs: List[Tuple]) -> Dict[str, List[str]]: for exchange in self._exchanges: for pair_chunk in chunked_pairs: - mc = MultiCaller(contract=exchange.sync_factory_contract, web3=self._web3, multicall_address=self._multicall_address) + mc = MultiCaller(contract=exchange.factory_contract, web3=self._web3, multicall_address=self._multicall_address) for pair in pair_chunk: if exchange.base_exchange_name in [UNISWAP_V2_NAME, SOLIDLY_V2_NAME]: exchange.get_pool_with_multicall(mc, pair[0], pair[1]) diff --git a/run_blockchain_terraformer.py b/run_blockchain_terraformer.py index 1fd29fb27..854119d40 100644 --- a/run_blockchain_terraformer.py +++ b/run_blockchain_terraformer.py @@ -1024,7 +1024,7 @@ def terraform_blockchain(network_name: str): elif "solidly" in fork: add_to_exchange_ids(exchange=exchange_name, fork=fork) solidly_exchange = SolidlyV2(exchange_name=exchange_name) - factory_abi = solidly_exchange.get_factory_abi + factory_abi = solidly_exchange.factory_abi factory_contract = web3.eth.contract( address=factory_address, abi=factory_abi From ba63ba953d73f25866e8d40c45760fcf083d2377 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Fri, 10 May 2024 01:14:51 +0300 Subject: [PATCH 086/131] fix: tests --- fastlane_bot/events/exchanges/factory.py | 2 +- fastlane_bot/tests/test_073_TestPoolFinder.py | 41 ++++--------------- 2 files changed, 10 insertions(+), 33 deletions(-) diff --git a/fastlane_bot/events/exchanges/factory.py b/fastlane_bot/events/exchanges/factory.py index 9fb50823d..fe98beea6 100644 --- a/fastlane_bot/events/exchanges/factory.py +++ b/fastlane_bot/events/exchanges/factory.py @@ -66,7 +66,7 @@ def get_exchange(self, key, cfg: Any, exchange_initialized: bool = None): base_exchange_name = cfg.network.exchange_name_base_from_fork(exchange_name=key) if base_exchange_name in [SOLIDLY_V2_NAME, UNISWAP_V2_NAME, UNISWAP_V3_NAME]: - exchange.factory_contract = self.w3_async.eth.contract( + exchange.factory_contract = cfg.w3_async.eth.contract( address=cfg.FACTORY_MAPPING[key], abi=exchange.factory_abi, ) diff --git a/fastlane_bot/tests/test_073_TestPoolFinder.py b/fastlane_bot/tests/test_073_TestPoolFinder.py index e6bbe1262..bfd1611c9 100644 --- a/fastlane_bot/tests/test_073_TestPoolFinder.py +++ b/fastlane_bot/tests/test_073_TestPoolFinder.py @@ -37,9 +37,7 @@ def test_find_unsupported_triangles(): def test_extract_pairs(): # Sample data for testing - uni_v2_exchanges = ["bob_ex"] uni_v3_exchanges = ["fred_ex"] - solidly_v2_exchanges = ["george_ex", "moose_ex"] flashloan_tokens = ["BNT"] pools = [ {"exchange_name": "CarbonX", "tkn0_address": "WBTC", "tkn1_address": "BNT"}, @@ -54,10 +52,17 @@ def test_extract_pairs(): expected_carbon_pairs = {frozenset(('WBTC', 'BNT')), frozenset(('WETH', 'USDC'))} expected_other_pairs = {frozenset(('WETH', 'USDT')), frozenset(('USDC', 'WBTC'))} #expected_carbon_pairs = [('WBTC', 'BNT'), ('WETH', 'USDC')] - pool_finder = PoolFinder(uni_v2_forks=uni_v2_exchanges, uni_v3_forks=uni_v3_exchanges, solidly_v2_forks=solidly_v2_exchanges, carbon_forks=carbon_forks, flashloan_tokens=flashloan_tokens) + pool_finder = PoolFinder( + uni_v3_forks=uni_v3_exchanges, + carbon_forks=carbon_forks, + flashloan_tokens=flashloan_tokens, + exchanges={}, + web3=None, + multicall_address="" + ) # Call the function with test data - carbon_pairs, other_pairs = pool_finder._extract_pairs(pools, carbon_forks) + carbon_pairs, other_pairs = pool_finder._extract_pairs(pools) # Assert the results are as expected assert frozenset(carbon_pairs[0]) in expected_carbon_pairs @@ -67,31 +72,3 @@ def test_extract_pairs(): #assert other_pairs == expected_other_pairs assert len(carbon_pairs) == 2 assert len(other_pairs) == 2 - -def test_sort_exchanges(): - exchange_pools = { - "bob_ex": ["1", "2", "3"], - "fred_ex": ["4", "5"], - "george_ex": ["6", "7", "8"], - "moose_ex": ["9", "10", "11", "12"] - } - - uni_v2_exchanges = ["bob_ex"] - uni_v3_exchanges = ["fred_ex"] - solidly_v2_exchanges = ["george_ex", "moose_ex"] - uni_v2_pools, uni_v3_pools, solidly_v2_pools = PoolFinder._sort_exchange_pools(ex_pools=exchange_pools, uni_v2_forks=uni_v2_exchanges, uni_v3_forks=uni_v3_exchanges, solidly_v2_forks=solidly_v2_exchanges) - - - assert len(uni_v2_pools.keys()) == 3 - assert len(uni_v3_pools.keys()) == 2 - assert len(solidly_v2_pools.keys()) == 7 - - assert uni_v2_pools["1"] == "bob_ex" - assert uni_v3_pools["5"] == "fred_ex" - assert solidly_v2_pools["7"] == "george_ex" - assert solidly_v2_pools["9"] == "moose_ex" - - - - - From 7c9df8f1eee0dd89a596f364e016ce42bdc6b279 Mon Sep 17 00:00:00 2001 From: NIXBNT <88088888+NIXBNT@users.noreply.github.com> Date: Thu, 2 May 2024 19:44:27 +1000 Subject: [PATCH 087/131] expand combo scope --- fastlane_bot/modes/base_pairwise.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fastlane_bot/modes/base_pairwise.py b/fastlane_bot/modes/base_pairwise.py index d5df65ef9..7be12a719 100644 --- a/fastlane_bot/modes/base_pairwise.py +++ b/fastlane_bot/modes/base_pairwise.py @@ -49,10 +49,10 @@ def get_combos( """ all_tokens = CCm.tokens() - flashloan_tokens_intersect = all_tokens.intersection(set(flashloan_tokens)) + # flashloan_tokens_intersect = all_tokens.intersection(set(flashloan_tokens)) combos = [ (tkn0, tkn1) - for tkn0, tkn1 in itertools.product(all_tokens, flashloan_tokens_intersect) + for tkn0, tkn1 in itertools.product(all_tokens, flashloan_tokens) # tkn1 is always the token being flash loaned # note that the pair is tkn0/tkn1, ie tkn1 is the quote token if tkn0 != tkn1 From cc0dc5eea5854b3ed5f4f44ba68fb46a39159f45 Mon Sep 17 00:00:00 2001 From: NIXBNT <88088888+NIXBNT@users.noreply.github.com> Date: Thu, 2 May 2024 19:45:05 +1000 Subject: [PATCH 088/131] add carbon curves pairwise --- fastlane_bot/modes/pairwise_multi_all.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fastlane_bot/modes/pairwise_multi_all.py b/fastlane_bot/modes/pairwise_multi_all.py index 924bdb702..07fdd8237 100644 --- a/fastlane_bot/modes/pairwise_multi_all.py +++ b/fastlane_bot/modes/pairwise_multi_all.py @@ -67,6 +67,9 @@ def find_arbitrage(self, candidates: List[Any] = None, ops: Tuple = None, best_p if len(base_direction_two) > 0: curve_combos += [[curve] + base_direction_two for curve in not_carbon_curves] + if len(carbon_curves) >= 2: + curve_combos += [carbon_curves] + for curve_combo in curve_combos: src_token = tkn1 if len(curve_combo) < 2: From 5cbbf5da3390f42d5be7d9d438cda9cc950db5c6 Mon Sep 17 00:00:00 2001 From: NIXBNT <88088888+NIXBNT@users.noreply.github.com> Date: Mon, 6 May 2024 22:03:35 +1000 Subject: [PATCH 089/131] multi_triangle_complete mode added Increases the breadth and speed of carbon focused triangles --- fastlane_bot/bot.py | 2 + fastlane_bot/modes/base_triangle.py | 135 ++++++++++++++++++ fastlane_bot/modes/triangle_multi_complete.py | 114 +++++++++++++++ main.py | 1 + 4 files changed, 252 insertions(+) create mode 100644 fastlane_bot/modes/triangle_multi_complete.py diff --git a/fastlane_bot/bot.py b/fastlane_bot/bot.py index 5fe5800d5..31090b8c5 100644 --- a/fastlane_bot/bot.py +++ b/fastlane_bot/bot.py @@ -74,6 +74,7 @@ from .modes.pairwise_multi_pol import FindArbitrageMultiPairwisePol from .modes.pairwise_single import FindArbitrageSinglePairwise from .modes.triangle_multi import ArbitrageFinderTriangleMulti +from .modes.triangle_multi_complete import ArbitrageFinderTriangleMultiComplete from .modes.triangle_single import ArbitrageFinderTriangleSingle from .modes.triangle_bancor_v3_two_hop import ArbitrageFinderTriangleBancor3TwoHop from .utils import num_format @@ -109,6 +110,7 @@ class CarbonBot: "b3_two_hop": ArbitrageFinderTriangleBancor3TwoHop, "multi_pairwise_pol": FindArbitrageMultiPairwisePol, "multi_pairwise_all": FindArbitrageMultiPairwiseAll, + "multi_triangle_complete": ArbitrageFinderTriangleMultiComplete, } class NoArbAvailable(Exception): diff --git a/fastlane_bot/modes/base_triangle.py b/fastlane_bot/modes/base_triangle.py index bf5f0c6a4..d804ab24d 100644 --- a/fastlane_bot/modes/base_triangle.py +++ b/fastlane_bot/modes/base_triangle.py @@ -174,6 +174,141 @@ def get_combos( combos, ) return combos + + def sort_pairs(self, pairs): + # Clean up the pairs alphabetically + return ["/".join(sorted(pair.split('/'))) for pair in pairs] + + def flatten_nested_items_in_list(self, nested_list): + # unpack nested items + flattened_list = [] + for items in nested_list: + flat_list = [] + for item in items: + if isinstance(item, list): + flat_list.extend(item) + else: + flat_list.append(item) + flattened_list.append(flat_list) + return flattened_list + + def get_triangle_groups(self, flt, x_y_pairs): + # Get groups of triangles that conform to (flt/x , x/y, y/flt) where x!=y + triangle_groups = [] + for pair in x_y_pairs: + x,y = pair.split('/') + triangle_groups += [("/".join(sorted([flt,x])), pair, "/".join(sorted([flt,y])))] + return triangle_groups + + def get_all_relevant_pairs_info(self, CCm, all_relevant_pairs): + # Get pair info for the cohort to allow decision making at the triangle level + all_relevant_pairs_info = {} + for pair in all_relevant_pairs: + all_relevant_pairs_info[pair] = {} + pair_curves = CCm.bypair(pair) + carbon_curves = [] + non_carbon_curves = [] + for x in pair_curves: + if x.params.exchange in self.ConfigObj.CARBON_V1_FORKS: + carbon_curves += [x] + else: + non_carbon_curves += [x] + all_relevant_pairs_info[pair]['non_carbon_curves'] = non_carbon_curves + all_relevant_pairs_info[pair]['carbon_curves'] = carbon_curves + all_relevant_pairs_info[pair]['curves'] = non_carbon_curves + [carbon_curves] if len(carbon_curves) >0 else non_carbon_curves # condense carbon curves into a single list + all_relevant_pairs_info[pair]['all_counts'] = len(pair_curves) + all_relevant_pairs_info[pair]['carbon_counts'] = len(carbon_curves) + return all_relevant_pairs_info + + def get_triangle_groups_stats(self, triangle_groups, all_relevant_pairs_info, arb_mode=None): + # Get the stats on the triangle group cohort for decision making + triangle_group_stats = {} + for i,triangle in enumerate(triangle_groups): + triangle_group_stats[i] = {} + triangle_group_stats[i]['path'] = [] + triangle_group_stats[i]['has_path'] = False + triangle_group_stats[i]['has_carbon'] = False + for pair in triangle: + if all_relevant_pairs_info[pair]['all_counts'] > 0: + triangle_group_stats[i]['path'] += [1] + else: + triangle_group_stats[i]['path'] += [0] + if all_relevant_pairs_info[pair]['carbon_counts'] > 0: + triangle_group_stats[i]['has_carbon'] = True + if sum(triangle_group_stats[i]['path']) == 3: + triangle_group_stats[i]['has_path'] = True + + # identify valid paths for the given mode + valid_carbon_triangles = [triangle_groups[i] for i in triangle_group_stats.keys() if (triangle_group_stats[i]['has_path'] == True) and (triangle_group_stats[i]['has_carbon'] == True)] + return valid_carbon_triangles + + def get_analysis_set_per_flt(self, flt, valid_triangles, all_relevant_pairs_info): + flt_triangle_analysis_set = [] + for triangle in valid_triangles: + multiverse = [all_relevant_pairs_info[pair]['curves'] for pair in triangle] + product_of_triangle = list(itertools.product(multiverse[0], multiverse[1], multiverse[2])) + triangles_to_run = self.flatten_nested_items_in_list(product_of_triangle) + flt_triangle_analysis_set += list(zip([flt] * len(triangles_to_run), triangles_to_run)) + + self.ConfigObj.logger.debug(f"[base_triangle.get_analysis_set_per_flt] Length of flt_triangle_analysis_set: {flt, len(flt_triangle_analysis_set)}") + return flt_triangle_analysis_set + + def get_comprehensive_triangles( + self, flashloan_tokens: List[str], CCm: Any, arb_mode: str + ) -> Tuple[List[str], List[Any]]: + """ + Get comprehensive combos for triangular arbitrage + + Parameters + ---------- + flashloan_tokens : list + List of flashloan tokens + CCm : object + CCm object + arb_mode : str + Arbitrage mode + + Returns + ------- + combos : list + List of combos + + """ + combos = [] + for flt in flashloan_tokens: + + # Get the Carbon pairs + carbon_pairs = self.sort_pairs(set([x.pair for x in CCm.curves if x.params.exchange in self.ConfigObj.CARBON_V1_FORKS])) + + # Create a set of unique tokens, excluding 'flt' + x_tokens = {token for pair in carbon_pairs for token in pair.split('/') if token != flt} + + # Get relevant pairs containing the flashloan token + flt_x_pairs = self.sort_pairs([f"{x}/{flt}" for x in x_tokens]) + + # Generate all possible 2-item combinations from the unique tokens that arent the flashloan token + x_y_pairs = self.sort_pairs(["{}/{}".format(x, y) for x, y in itertools.combinations(x_tokens, 2)]) + + # Note the relevant pairs + all_relevant_pairs = flt_x_pairs + x_y_pairs + self.ConfigObj.logger.debug(f"len(all_relevant_pairs) {len(all_relevant_pairs)}") + + # Generate triangle groups + triangle_groups = self.get_triangle_groups(flt, x_y_pairs) + self.ConfigObj.logger.debug(f"len(triangle_groups) {len(triangle_groups)}") + + # Get pair info for the cohort + all_relevant_pairs_info = self.get_all_relevant_pairs_info(CCm, all_relevant_pairs) + + # Generate valid triangles for the groups base on arb_mode + valid_triangles = self.get_triangle_groups_stats(triangle_groups, all_relevant_pairs_info, arb_mode) + + # Get [(flt,curves)] analysis set for the flt + flt_triangle_analysis_set = self.get_analysis_set_per_flt(flt, valid_triangles, all_relevant_pairs_info) + + # The entire analysis set for all flts + combos.extend(flt_triangle_analysis_set) + return combos @staticmethod def get_mono_direction_carbon_curves( diff --git a/fastlane_bot/modes/triangle_multi_complete.py b/fastlane_bot/modes/triangle_multi_complete.py new file mode 100644 index 000000000..a03096d61 --- /dev/null +++ b/fastlane_bot/modes/triangle_multi_complete.py @@ -0,0 +1,114 @@ +""" +Defines the Triangular arbitrage finder class + +[DOC-TODO-OPTIONAL-longer description in rst format] + +--- +(c) Copyright Bprotocol foundation 2023-24. +All rights reserved. +Licensed under MIT. +""" +from typing import List, Any, Tuple, Union + +from fastlane_bot.modes.base_triangle import ArbitrageFinderTriangleBase +from fastlane_bot.tools.cpc import CPCContainer +from fastlane_bot.tools.optimizer import MargPOptimizer + + +class ArbitrageFinderTriangleMultiComplete(ArbitrageFinderTriangleBase): + """ + Triangular arbitrage finder mode + """ + + arb_mode = "multi_triangle_complete" + + def find_arbitrage(self, candidates: List[Any] = None, ops: Tuple = None, best_profit: float = 0, profit_src: float = 0) -> Union[List, Tuple]: + """ + see base.py + """ + + if candidates is None: + candidates = [] + + combos = self.get_comprehensive_triangles( + self.flashloan_tokens, self.CCm, arb_mode=self.arb_mode + ) + + for src_token, miniverse in combos: + # print(miniverse) + self.ConfigObj.logger.debug(f"{[x.cid for x in miniverse]}") + try: + r = None + CC_cc = CPCContainer(miniverse) + O = MargPOptimizer(CC_cc) + #try: + pstart = self.build_pstart(CC_cc, CC_cc.tokens(), src_token) + # print(pstart) + r = O.optimize(src_token, params=dict(pstart=pstart)) #debug=True, debug2=True, verbose=True + trade_instructions_dic = r.trade_instructions(O.TIF_DICTS) + # trade_instructions_df = r.trade_instructions(O.TIF_DFAGGR) + # print(trade_instructions_df) + if len(trade_instructions_dic) < 3: + # Failed to converge + continue + trade_instructions_df = r.trade_instructions(O.TIF_DFAGGR) + trade_instructions = r.trade_instructions() + + except Exception as e: + self.ConfigObj.logger.debug(f"[triangle multi] {str(e)}") + continue + if trade_instructions_dic is None: + continue + if len(trade_instructions_dic) < 2: + continue + profit_src = -r.result + + # Get the cids + cids = [ti["cid"] for ti in trade_instructions_dic] + + # Calculate the profit + profit = self.calculate_profit(src_token, profit_src, self.CCm, cids) + if str(profit) == "nan": + self.ConfigObj.logger.debug("profit is nan, skipping") + continue + + # Handle candidates based on conditions + candidates += self.handle_candidates( + best_profit, + profit, + trade_instructions_df, + trade_instructions_dic, + src_token, + trade_instructions, + ) + + # Find the best operations + best_profit, ops = self.find_best_operations( + best_profit, + ops, + profit, + trade_instructions_df, + trade_instructions_dic, + src_token, + trade_instructions, + ) + + return candidates if self.result == self.AO_CANDIDATES else ops + + def build_pstart(self, CCm, tkn0list, tkn1): + tkn0list = [x for x in tkn0list if x not in [tkn1]] + pstart = {} + for tkn0 in tkn0list: + try: + price = CCm.bytknx(tkn0).bytkny(tkn1)[0].p + except: + try: + price = 1/CCm.bytknx(tkn1).bytkny(tkn0)[0].p + except Exception as e: + print(str(e)) + self.ConfigObj.logger.debug(f"[pstart build] {tkn0} not supported. w {tkn1} {str(e)}") + pstart[tkn0]=price + pstart[tkn1] = 1 + return pstart + + diff --git a/main.py b/main.py index d926d5614..cdff59ead 100644 --- a/main.py +++ b/main.py @@ -588,6 +588,7 @@ def run(mgr, args, tenderly_uri=None) -> None: "b3_two_hop", "multi_pairwise_pol", "multi_pairwise_all", + "multi_triangle_complete" ], ) parser.add_argument( From 5766f970733f6fc532952b335f260097231e5d2c Mon Sep 17 00:00:00 2001 From: NIXBNT <88088888+NIXBNT@users.noreply.github.com> Date: Tue, 7 May 2024 14:05:37 +1000 Subject: [PATCH 090/131] updates following comments --- fastlane_bot/modes/base_triangle.py | 104 +++++++++++------------ fastlane_bot/modes/pairwise_multi_all.py | 4 +- 2 files changed, 52 insertions(+), 56 deletions(-) diff --git a/fastlane_bot/modes/base_triangle.py b/fastlane_bot/modes/base_triangle.py index d804ab24d..5da54b134 100644 --- a/fastlane_bot/modes/base_triangle.py +++ b/fastlane_bot/modes/base_triangle.py @@ -17,6 +17,49 @@ from fastlane_bot.modes.base import ArbitrageFinderBase from fastlane_bot.tools.cpc import T +@staticmethod +def sort_pairs(pairs): + # Clean up the pairs alphabetically + return ["/".join(sorted(pair.split('/'))) for pair in pairs] + +@staticmethod +def flatten_nested_items_in_list(nested_list): + # unpack nested items + flattened_list = [] + for items in nested_list: + flat_list = [] + for item in items: + if isinstance(item, list): + flat_list.extend(item) + else: + flat_list.append(item) + flattened_list.append(flat_list) + return flattened_list + +@staticmethod +def get_triangle_groups(flt, x_y_pairs): + # Get groups of triangles that conform to (flt/x , x/y, y/flt) where x!=y + triangle_groups = [] + for pair in x_y_pairs: + x,y = pair.split('/') + triangle_groups += [("/".join(sorted([flt,x])), pair, "/".join(sorted([flt,y])))] + return triangle_groups + +@staticmethod +def get_triangle_groups_stats(triangle_groups, all_relevant_pairs_info): + # Get the stats on the triangle group cohort for decision making + valid_carbon_triangles = [] + for triangle in triangle_groups: + path_len = 0 + has_carbon = False + for pair in triangle: + if all_relevant_pairs_info[pair]['all_counts'] > 0: + path_len += 1 + if all_relevant_pairs_info[pair]['carbon_counts'] > 0: + has_carbon = True + if path_len == 3 and has_carbon == True: + valid_carbon_triangles.append(triangle) + return valid_carbon_triangles class ArbitrageFinderTriangleBase(ArbitrageFinderBase): """ @@ -175,31 +218,6 @@ def get_combos( ) return combos - def sort_pairs(self, pairs): - # Clean up the pairs alphabetically - return ["/".join(sorted(pair.split('/'))) for pair in pairs] - - def flatten_nested_items_in_list(self, nested_list): - # unpack nested items - flattened_list = [] - for items in nested_list: - flat_list = [] - for item in items: - if isinstance(item, list): - flat_list.extend(item) - else: - flat_list.append(item) - flattened_list.append(flat_list) - return flattened_list - - def get_triangle_groups(self, flt, x_y_pairs): - # Get groups of triangles that conform to (flt/x , x/y, y/flt) where x!=y - triangle_groups = [] - for pair in x_y_pairs: - x,y = pair.split('/') - triangle_groups += [("/".join(sorted([flt,x])), pair, "/".join(sorted([flt,y])))] - return triangle_groups - def get_all_relevant_pairs_info(self, CCm, all_relevant_pairs): # Get pair info for the cohort to allow decision making at the triangle level all_relevant_pairs_info = {} @@ -215,39 +233,17 @@ def get_all_relevant_pairs_info(self, CCm, all_relevant_pairs): non_carbon_curves += [x] all_relevant_pairs_info[pair]['non_carbon_curves'] = non_carbon_curves all_relevant_pairs_info[pair]['carbon_curves'] = carbon_curves - all_relevant_pairs_info[pair]['curves'] = non_carbon_curves + [carbon_curves] if len(carbon_curves) >0 else non_carbon_curves # condense carbon curves into a single list + all_relevant_pairs_info[pair]['curves'] = non_carbon_curves + [carbon_curves] if len(carbon_curves) > 0 else non_carbon_curves # condense carbon curves into a single list all_relevant_pairs_info[pair]['all_counts'] = len(pair_curves) all_relevant_pairs_info[pair]['carbon_counts'] = len(carbon_curves) return all_relevant_pairs_info - def get_triangle_groups_stats(self, triangle_groups, all_relevant_pairs_info, arb_mode=None): - # Get the stats on the triangle group cohort for decision making - triangle_group_stats = {} - for i,triangle in enumerate(triangle_groups): - triangle_group_stats[i] = {} - triangle_group_stats[i]['path'] = [] - triangle_group_stats[i]['has_path'] = False - triangle_group_stats[i]['has_carbon'] = False - for pair in triangle: - if all_relevant_pairs_info[pair]['all_counts'] > 0: - triangle_group_stats[i]['path'] += [1] - else: - triangle_group_stats[i]['path'] += [0] - if all_relevant_pairs_info[pair]['carbon_counts'] > 0: - triangle_group_stats[i]['has_carbon'] = True - if sum(triangle_group_stats[i]['path']) == 3: - triangle_group_stats[i]['has_path'] = True - - # identify valid paths for the given mode - valid_carbon_triangles = [triangle_groups[i] for i in triangle_group_stats.keys() if (triangle_group_stats[i]['has_path'] == True) and (triangle_group_stats[i]['has_carbon'] == True)] - return valid_carbon_triangles - def get_analysis_set_per_flt(self, flt, valid_triangles, all_relevant_pairs_info): flt_triangle_analysis_set = [] for triangle in valid_triangles: multiverse = [all_relevant_pairs_info[pair]['curves'] for pair in triangle] product_of_triangle = list(itertools.product(multiverse[0], multiverse[1], multiverse[2])) - triangles_to_run = self.flatten_nested_items_in_list(product_of_triangle) + triangles_to_run = flatten_nested_items_in_list(product_of_triangle) flt_triangle_analysis_set += list(zip([flt] * len(triangles_to_run), triangles_to_run)) self.ConfigObj.logger.debug(f"[base_triangle.get_analysis_set_per_flt] Length of flt_triangle_analysis_set: {flt, len(flt_triangle_analysis_set)}") @@ -278,30 +274,30 @@ def get_comprehensive_triangles( for flt in flashloan_tokens: # Get the Carbon pairs - carbon_pairs = self.sort_pairs(set([x.pair for x in CCm.curves if x.params.exchange in self.ConfigObj.CARBON_V1_FORKS])) + carbon_pairs = sort_pairs(set([x.pair for x in CCm.curves if x.params.exchange in self.ConfigObj.CARBON_V1_FORKS])) # Create a set of unique tokens, excluding 'flt' x_tokens = {token for pair in carbon_pairs for token in pair.split('/') if token != flt} # Get relevant pairs containing the flashloan token - flt_x_pairs = self.sort_pairs([f"{x}/{flt}" for x in x_tokens]) + flt_x_pairs = sort_pairs([f"{x}/{flt}" for x in x_tokens]) # Generate all possible 2-item combinations from the unique tokens that arent the flashloan token - x_y_pairs = self.sort_pairs(["{}/{}".format(x, y) for x, y in itertools.combinations(x_tokens, 2)]) + x_y_pairs = sort_pairs(["{}/{}".format(x, y) for x, y in itertools.combinations(x_tokens, 2)]) # Note the relevant pairs all_relevant_pairs = flt_x_pairs + x_y_pairs self.ConfigObj.logger.debug(f"len(all_relevant_pairs) {len(all_relevant_pairs)}") # Generate triangle groups - triangle_groups = self.get_triangle_groups(flt, x_y_pairs) + triangle_groups = get_triangle_groups(flt, x_y_pairs) self.ConfigObj.logger.debug(f"len(triangle_groups) {len(triangle_groups)}") # Get pair info for the cohort all_relevant_pairs_info = self.get_all_relevant_pairs_info(CCm, all_relevant_pairs) # Generate valid triangles for the groups base on arb_mode - valid_triangles = self.get_triangle_groups_stats(triangle_groups, all_relevant_pairs_info, arb_mode) + valid_triangles = get_triangle_groups_stats(triangle_groups, all_relevant_pairs_info) # Get [(flt,curves)] analysis set for the flt flt_triangle_analysis_set = self.get_analysis_set_per_flt(flt, valid_triangles, all_relevant_pairs_info) diff --git a/fastlane_bot/modes/pairwise_multi_all.py b/fastlane_bot/modes/pairwise_multi_all.py index 07fdd8237..20cdbb46f 100644 --- a/fastlane_bot/modes/pairwise_multi_all.py +++ b/fastlane_bot/modes/pairwise_multi_all.py @@ -67,8 +67,8 @@ def find_arbitrage(self, candidates: List[Any] = None, ops: Tuple = None, best_p if len(base_direction_two) > 0: curve_combos += [[curve] + base_direction_two for curve in not_carbon_curves] - if len(carbon_curves) >= 2: - curve_combos += [carbon_curves] + if len(carbon_curves) >= 2: + curve_combos += [carbon_curves] for curve_combo in curve_combos: src_token = tkn1 From 1c9f5a02625aa1260f7221de33a6d9f36de6eeec Mon Sep 17 00:00:00 2001 From: NIXBNT <88088888+NIXBNT@users.noreply.github.com> Date: Tue, 7 May 2024 14:17:47 +1000 Subject: [PATCH 091/131] cleanup pstart and error messanges --- fastlane_bot/modes/triangle_multi_complete.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/fastlane_bot/modes/triangle_multi_complete.py b/fastlane_bot/modes/triangle_multi_complete.py index a03096d61..eb16e655c 100644 --- a/fastlane_bot/modes/triangle_multi_complete.py +++ b/fastlane_bot/modes/triangle_multi_complete.py @@ -35,19 +35,13 @@ def find_arbitrage(self, candidates: List[Any] = None, ops: Tuple = None, best_p ) for src_token, miniverse in combos: - # print(miniverse) - self.ConfigObj.logger.debug(f"{[x.cid for x in miniverse]}") try: r = None CC_cc = CPCContainer(miniverse) O = MargPOptimizer(CC_cc) - #try: pstart = self.build_pstart(CC_cc, CC_cc.tokens(), src_token) - # print(pstart) r = O.optimize(src_token, params=dict(pstart=pstart)) #debug=True, debug2=True, verbose=True trade_instructions_dic = r.trade_instructions(O.TIF_DICTS) - # trade_instructions_df = r.trade_instructions(O.TIF_DFAGGR) - # print(trade_instructions_df) if len(trade_instructions_dic) < 3: # Failed to converge continue @@ -100,14 +94,12 @@ def build_pstart(self, CCm, tkn0list, tkn1): pstart = {} for tkn0 in tkn0list: try: - price = CCm.bytknx(tkn0).bytkny(tkn1)[0].p + pstart[tkn0] = CCm.bytknx(tkn0).bytkny(tkn1)[0].p except: try: - price = 1/CCm.bytknx(tkn1).bytkny(tkn0)[0].p + pstart[tkn0] = 1/CCm.bytknx(tkn1).bytkny(tkn0)[0].p except Exception as e: - print(str(e)) - self.ConfigObj.logger.debug(f"[pstart build] {tkn0} not supported. w {tkn1} {str(e)}") - pstart[tkn0]=price + self.ConfigObj.logger.info(f"[pstart build] {tkn0} not supported. w {tkn1} {e}") pstart[tkn1] = 1 return pstart From 0dbb4dd75816ec230b093a112f76a57f0d773a64 Mon Sep 17 00:00:00 2001 From: Nicholas Welch Date: Wed, 8 May 2024 08:49:46 +1000 Subject: [PATCH 092/131] carbon<>carbon can support mixing directions --- fastlane_bot/tests/test_064_TestMultiAllMode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane_bot/tests/test_064_TestMultiAllMode.py b/fastlane_bot/tests/test_064_TestMultiAllMode.py index 8af2f4b8c..033818012 100644 --- a/fastlane_bot/tests/test_064_TestMultiAllMode.py +++ b/fastlane_bot/tests/test_064_TestMultiAllMode.py @@ -224,7 +224,7 @@ def test_test_expected_output(): assert len(r) >= 25, f"[NBTest64 TestMultiPairwiseAll Mode] Expected at least 25 arbs, found {len(r)}" assert multi_carbon_count > 0, f"[NBTest64 TestMultiPairwiseAll Mode] Not finding arbs with multiple Carbon curves." - assert carbon_wrong_direction_count == 0, f"[NBTest64 TestMultiPairwiseAll Mode] Expected all Carbon curves to have the same tkn in and tkn out. Mixing is currently not supported." + # assert carbon_wrong_direction_count == 0, f"[NBTest64 TestMultiPairwiseAll Mode] Expected all Carbon curves to have the same tkn in and tkn out. Mixing is currently not supported." # - \ No newline at end of file From 293ba785b40ee5aa0df4198da0e43ac64ae8206a Mon Sep 17 00:00:00 2001 From: Nicholas Welch Date: Thu, 9 May 2024 09:45:51 +1000 Subject: [PATCH 093/131] Revert "expand combo scope" This reverts commit 3dd85f279df065048b7a9eaf58c4b06beda59896. --- fastlane_bot/modes/base_pairwise.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fastlane_bot/modes/base_pairwise.py b/fastlane_bot/modes/base_pairwise.py index 7be12a719..d5df65ef9 100644 --- a/fastlane_bot/modes/base_pairwise.py +++ b/fastlane_bot/modes/base_pairwise.py @@ -49,10 +49,10 @@ def get_combos( """ all_tokens = CCm.tokens() - # flashloan_tokens_intersect = all_tokens.intersection(set(flashloan_tokens)) + flashloan_tokens_intersect = all_tokens.intersection(set(flashloan_tokens)) combos = [ (tkn0, tkn1) - for tkn0, tkn1 in itertools.product(all_tokens, flashloan_tokens) + for tkn0, tkn1 in itertools.product(all_tokens, flashloan_tokens_intersect) # tkn1 is always the token being flash loaned # note that the pair is tkn0/tkn1, ie tkn1 is the quote token if tkn0 != tkn1 From 8afeacc0aa9aef77f29704425212e5254a0263f7 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Fri, 10 May 2024 20:48:09 +0300 Subject: [PATCH 094/131] fix: tests --- fastlane_bot/events/event_gatherer.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fastlane_bot/events/event_gatherer.py b/fastlane_bot/events/event_gatherer.py index 29eb78cc6..5f70913b2 100644 --- a/fastlane_bot/events/event_gatherer.py +++ b/fastlane_bot/events/event_gatherer.py @@ -1,4 +1,5 @@ from itertools import chain +from typing import Dict import asyncio import nest_asyncio @@ -21,8 +22,8 @@ class EventGatherer: def __init__( self, w3: AsyncWeb3, - exchanges: dict[str, Exchange], - event_contracts: dict[str, Contract], + exchanges: Dict[str, Exchange], + event_contracts: Dict[str, Contract], ): """ Initializes the EventManager. Args: From fa25f931900d4407424133a22142b9ca925767fb Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Mon, 13 May 2024 10:32:44 +0300 Subject: [PATCH 095/131] Fix several issue in the triangle-mode implementation --- fastlane_bot/modes/base_triangle.py | 8 +------- fastlane_bot/modes/triangle_multi_complete.py | 13 +++---------- fastlane_bot/tests/test_064_TestMultiAllMode.py | 2 +- 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/fastlane_bot/modes/base_triangle.py b/fastlane_bot/modes/base_triangle.py index 5da54b134..8ce78a7d1 100644 --- a/fastlane_bot/modes/base_triangle.py +++ b/fastlane_bot/modes/base_triangle.py @@ -17,12 +17,10 @@ from fastlane_bot.modes.base import ArbitrageFinderBase from fastlane_bot.tools.cpc import T -@staticmethod def sort_pairs(pairs): # Clean up the pairs alphabetically return ["/".join(sorted(pair.split('/'))) for pair in pairs] -@staticmethod def flatten_nested_items_in_list(nested_list): # unpack nested items flattened_list = [] @@ -36,7 +34,6 @@ def flatten_nested_items_in_list(nested_list): flattened_list.append(flat_list) return flattened_list -@staticmethod def get_triangle_groups(flt, x_y_pairs): # Get groups of triangles that conform to (flt/x , x/y, y/flt) where x!=y triangle_groups = [] @@ -45,7 +42,6 @@ def get_triangle_groups(flt, x_y_pairs): triangle_groups += [("/".join(sorted([flt,x])), pair, "/".join(sorted([flt,y])))] return triangle_groups -@staticmethod def get_triangle_groups_stats(triangle_groups, all_relevant_pairs_info): # Get the stats on the triangle group cohort for decision making valid_carbon_triangles = [] @@ -250,7 +246,7 @@ def get_analysis_set_per_flt(self, flt, valid_triangles, all_relevant_pairs_info return flt_triangle_analysis_set def get_comprehensive_triangles( - self, flashloan_tokens: List[str], CCm: Any, arb_mode: str + self, flashloan_tokens: List[str], CCm: Any ) -> Tuple[List[str], List[Any]]: """ Get comprehensive combos for triangular arbitrage @@ -261,8 +257,6 @@ def get_comprehensive_triangles( List of flashloan tokens CCm : object CCm object - arb_mode : str - Arbitrage mode Returns ------- diff --git a/fastlane_bot/modes/triangle_multi_complete.py b/fastlane_bot/modes/triangle_multi_complete.py index eb16e655c..e2ee8c947 100644 --- a/fastlane_bot/modes/triangle_multi_complete.py +++ b/fastlane_bot/modes/triangle_multi_complete.py @@ -30,30 +30,23 @@ def find_arbitrage(self, candidates: List[Any] = None, ops: Tuple = None, best_p if candidates is None: candidates = [] - combos = self.get_comprehensive_triangles( - self.flashloan_tokens, self.CCm, arb_mode=self.arb_mode - ) + combos = self.get_comprehensive_triangles(self.flashloan_tokens, self.CCm) for src_token, miniverse in combos: try: - r = None CC_cc = CPCContainer(miniverse) O = MargPOptimizer(CC_cc) pstart = self.build_pstart(CC_cc, CC_cc.tokens(), src_token) r = O.optimize(src_token, params=dict(pstart=pstart)) #debug=True, debug2=True, verbose=True trade_instructions_dic = r.trade_instructions(O.TIF_DICTS) - if len(trade_instructions_dic) < 3: + if trade_instructions_dic is None or len(trade_instructions_dic) < 3: # Failed to converge continue trade_instructions_df = r.trade_instructions(O.TIF_DFAGGR) trade_instructions = r.trade_instructions() except Exception as e: - self.ConfigObj.logger.debug(f"[triangle multi] {str(e)}") - continue - if trade_instructions_dic is None: - continue - if len(trade_instructions_dic) < 2: + self.ConfigObj.logger.info(f"[triangle multi] {e}") continue profit_src = -r.result diff --git a/fastlane_bot/tests/test_064_TestMultiAllMode.py b/fastlane_bot/tests/test_064_TestMultiAllMode.py index 033818012..6d7ff45be 100644 --- a/fastlane_bot/tests/test_064_TestMultiAllMode.py +++ b/fastlane_bot/tests/test_064_TestMultiAllMode.py @@ -224,7 +224,7 @@ def test_test_expected_output(): assert len(r) >= 25, f"[NBTest64 TestMultiPairwiseAll Mode] Expected at least 25 arbs, found {len(r)}" assert multi_carbon_count > 0, f"[NBTest64 TestMultiPairwiseAll Mode] Not finding arbs with multiple Carbon curves." - # assert carbon_wrong_direction_count == 0, f"[NBTest64 TestMultiPairwiseAll Mode] Expected all Carbon curves to have the same tkn in and tkn out. Mixing is currently not supported." + assert carbon_wrong_direction_count == 6, f"[NBTest64 TestMultiPairwiseAll Mode] Expected 6 Carbon curves to be in the opposite direction." # - \ No newline at end of file From 7e667e49ea0c30e66c3477023534eb5383c99b6d Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Mon, 13 May 2024 11:09:33 +0300 Subject: [PATCH 096/131] Fix function `build_pstart` in class `ArbitrageFinderTriangleBase`, and remove that function in each one of the classes which inherits that class --- fastlane_bot/modes/base_triangle.py | 11 +++++------ fastlane_bot/modes/triangle_multi.py | 18 ------------------ fastlane_bot/modes/triangle_multi_complete.py | 16 ---------------- 3 files changed, 5 insertions(+), 40 deletions(-) diff --git a/fastlane_bot/modes/base_triangle.py b/fastlane_bot/modes/base_triangle.py index 8ce78a7d1..ce07df8bc 100644 --- a/fastlane_bot/modes/base_triangle.py +++ b/fastlane_bot/modes/base_triangle.py @@ -345,18 +345,17 @@ def get_mono_direction_carbon_curves( wrong_direction_cids.append(idx) return [curve for curve in miniverse if curve.cid not in wrong_direction_cids] + def build_pstart(self, CCm, tkn0list, tkn1): tkn0list = [x for x in tkn0list if x not in [tkn1]] pstart = {} for tkn0 in tkn0list: try: - price = CCm.bytknx(tkn0).bytkny(tkn1)[0].p + pstart[tkn0] = CCm.bytknx(tkn0).bytkny(tkn1)[0].p except: try: - price = 1/CCm.bytknx(tkn1).bytkny(tkn0)[0].p + pstart[tkn0] = 1/CCm.bytknx(tkn1).bytkny(tkn0)[0].p except Exception as e: - print(str(e)) - self.ConfigObj.logger.debug(f"[pstart build] {tkn0} not supported. w {tkn1} {str(e)}") - pstart[tkn0]=price + self.ConfigObj.logger.info(f"[pstart build] {tkn0}/{tkn1} price error {e}") pstart[tkn1] = 1 - return pstart \ No newline at end of file + return pstart diff --git a/fastlane_bot/modes/triangle_multi.py b/fastlane_bot/modes/triangle_multi.py index 50e335880..6a0e2d926 100644 --- a/fastlane_bot/modes/triangle_multi.py +++ b/fastlane_bot/modes/triangle_multi.py @@ -92,21 +92,3 @@ def find_arbitrage(self, candidates: List[Any] = None, ops: Tuple = None, best_p ) return candidates if self.result == self.AO_CANDIDATES else ops - - def build_pstart(self, CCm, tkn0list, tkn1): - tkn0list = [x for x in tkn0list if x not in [tkn1]] - pstart = {} - for tkn0 in tkn0list: - try: - price = CCm.bytknx(tkn0).bytkny(tkn1)[0].p - except: - try: - price = 1/CCm.bytknx(tkn1).bytkny(tkn0)[0].p - except Exception as e: - print(str(e)) - self.ConfigObj.logger.debug(f"[pstart build] {tkn0} not supported. w {tkn1} {str(e)}") - pstart[tkn0]=price - pstart[tkn1] = 1 - return pstart - - diff --git a/fastlane_bot/modes/triangle_multi_complete.py b/fastlane_bot/modes/triangle_multi_complete.py index e2ee8c947..171fe032f 100644 --- a/fastlane_bot/modes/triangle_multi_complete.py +++ b/fastlane_bot/modes/triangle_multi_complete.py @@ -81,19 +81,3 @@ def find_arbitrage(self, candidates: List[Any] = None, ops: Tuple = None, best_p ) return candidates if self.result == self.AO_CANDIDATES else ops - - def build_pstart(self, CCm, tkn0list, tkn1): - tkn0list = [x for x in tkn0list if x not in [tkn1]] - pstart = {} - for tkn0 in tkn0list: - try: - pstart[tkn0] = CCm.bytknx(tkn0).bytkny(tkn1)[0].p - except: - try: - pstart[tkn0] = 1/CCm.bytknx(tkn1).bytkny(tkn0)[0].p - except Exception as e: - self.ConfigObj.logger.info(f"[pstart build] {tkn0} not supported. w {tkn1} {e}") - pstart[tkn1] = 1 - return pstart - - From 16efe4e7bc17e1b845777b72d5ccbee16b61905c Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Mon, 13 May 2024 11:57:21 +0300 Subject: [PATCH 097/131] Fix the handling of trade instructions in function ArbitrageFinderTriangleMulti.find_arbitrage --- fastlane_bot/modes/triangle_multi.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/fastlane_bot/modes/triangle_multi.py b/fastlane_bot/modes/triangle_multi.py index 6a0e2d926..f3a7c5289 100644 --- a/fastlane_bot/modes/triangle_multi.py +++ b/fastlane_bot/modes/triangle_multi.py @@ -42,22 +42,17 @@ def find_arbitrage(self, candidates: List[Any] = None, ops: Tuple = None, best_p r = None CC_cc = CPCContainer(miniverse) O = MargPOptimizer(CC_cc) - #try: pstart = self.build_pstart(CC_cc, CC_cc.tokens(), src_token) r = O.optimize(src_token, params=dict(pstart=pstart)) #debug=True, debug2=True trade_instructions_dic = r.trade_instructions(O.TIF_DICTS) - if len(trade_instructions_dic) < 3: + if trade_instructions_dic is None or len(trade_instructions_dic) < 3: # Failed to converge continue trade_instructions_df = r.trade_instructions(O.TIF_DFAGGR) trade_instructions = r.trade_instructions() except Exception as e: - self.ConfigObj.logger.debug(f"[triangle multi] {str(e)}") - continue - if trade_instructions_dic is None: - continue - if len(trade_instructions_dic) < 2: + self.ConfigObj.logger.info(f"[triangle multi] {e}") continue profit_src = -r.result From e9c19598d0ae3b4b53b5349bbd58e3b980b5171b Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Mon, 13 May 2024 12:00:52 +0300 Subject: [PATCH 098/131] Remove unused code --- fastlane_bot/modes/triangle_multi.py | 1 - 1 file changed, 1 deletion(-) diff --git a/fastlane_bot/modes/triangle_multi.py b/fastlane_bot/modes/triangle_multi.py index f3a7c5289..917260f49 100644 --- a/fastlane_bot/modes/triangle_multi.py +++ b/fastlane_bot/modes/triangle_multi.py @@ -39,7 +39,6 @@ def find_arbitrage(self, candidates: List[Any] = None, ops: Tuple = None, best_p for src_token, miniverse in combos: try: - r = None CC_cc = CPCContainer(miniverse) O = MargPOptimizer(CC_cc) pstart = self.build_pstart(CC_cc, CC_cc.tokens(), src_token) From 4dfd33654a01c8ea460c3dbc66f562d675f33dbb Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Mon, 13 May 2024 13:10:26 +0300 Subject: [PATCH 099/131] Remove unused code --- fastlane_bot/modes/base_triangle.py | 46 ----------------------------- 1 file changed, 46 deletions(-) diff --git a/fastlane_bot/modes/base_triangle.py b/fastlane_bot/modes/base_triangle.py index ce07df8bc..522283b36 100644 --- a/fastlane_bot/modes/base_triangle.py +++ b/fastlane_bot/modes/base_triangle.py @@ -300,52 +300,6 @@ def get_comprehensive_triangles( combos.extend(flt_triangle_analysis_set) return combos - @staticmethod - def get_mono_direction_carbon_curves( - miniverse: List[Any], trade_instructions_df: pd.DataFrame, token_in: str=None - ) -> List[Any]: - """ - Get mono direction carbon curves for triangular arbitrage - - Parameters - ---------- - miniverse : list - List of miniverses - token_in : str - Token in - trade_instructions_df : DataFrame - Trade instructions dataframe - - Returns - ------- - mono_direction_carbon_curves : list - List of mono direction carbon curves - - """ - - if token_in is None: - columns = trade_instructions_df.columns - check_nan = trade_instructions_df.copy().fillna(0) - first_bancor_v3_pool = check_nan.iloc[0] - second_bancor_v3_pool = check_nan.iloc[1] - - for idx, token in enumerate(columns): - if token == T.BNT: - continue - if first_bancor_v3_pool[token] < 0: - token_in = token - break - if second_bancor_v3_pool[token] < 0: - token_in = token - break - - wrong_direction_cids = [] - for idx, row in trade_instructions_df.iterrows(): - if (row[token_in] < 0) and ("-0" in idx or "-1" in idx): - wrong_direction_cids.append(idx) - - return [curve for curve in miniverse if curve.cid not in wrong_direction_cids] - def build_pstart(self, CCm, tkn0list, tkn1): tkn0list = [x for x in tkn0list if x not in [tkn1]] pstart = {} From c2c4f02e20c4323a75dad272f8df48cc461df398 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Mon, 13 May 2024 13:12:14 +0300 Subject: [PATCH 100/131] Cosmetic --- fastlane_bot/modes/triangle_multi.py | 6 ++---- fastlane_bot/modes/triangle_multi_complete.py | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/fastlane_bot/modes/triangle_multi.py b/fastlane_bot/modes/triangle_multi.py index 917260f49..e6d1f6672 100644 --- a/fastlane_bot/modes/triangle_multi.py +++ b/fastlane_bot/modes/triangle_multi.py @@ -33,16 +33,14 @@ def find_arbitrage(self, candidates: List[Any] = None, ops: Tuple = None, best_p if candidates is None: candidates = [] - combos = self.get_combos( - self.flashloan_tokens, self.CCm, arb_mode=self.arb_mode - ) + combos = self.get_combos(self.flashloan_tokens, self.CCm, arb_mode=self.arb_mode) for src_token, miniverse in combos: try: CC_cc = CPCContainer(miniverse) O = MargPOptimizer(CC_cc) pstart = self.build_pstart(CC_cc, CC_cc.tokens(), src_token) - r = O.optimize(src_token, params=dict(pstart=pstart)) #debug=True, debug2=True + r = O.optimize(src_token, params=dict(pstart=pstart)) trade_instructions_dic = r.trade_instructions(O.TIF_DICTS) if trade_instructions_dic is None or len(trade_instructions_dic) < 3: # Failed to converge diff --git a/fastlane_bot/modes/triangle_multi_complete.py b/fastlane_bot/modes/triangle_multi_complete.py index 171fe032f..d053ae0fc 100644 --- a/fastlane_bot/modes/triangle_multi_complete.py +++ b/fastlane_bot/modes/triangle_multi_complete.py @@ -37,7 +37,7 @@ def find_arbitrage(self, candidates: List[Any] = None, ops: Tuple = None, best_p CC_cc = CPCContainer(miniverse) O = MargPOptimizer(CC_cc) pstart = self.build_pstart(CC_cc, CC_cc.tokens(), src_token) - r = O.optimize(src_token, params=dict(pstart=pstart)) #debug=True, debug2=True, verbose=True + r = O.optimize(src_token, params=dict(pstart=pstart)) trade_instructions_dic = r.trade_instructions(O.TIF_DICTS) if trade_instructions_dic is None or len(trade_instructions_dic) < 3: # Failed to converge From 03b1ef8fb70f40b84b958765eaa292202e6aa026 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Mon, 13 May 2024 11:26:43 +0300 Subject: [PATCH 101/131] fix: type annotation --- fastlane_bot/config/multicaller.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fastlane_bot/config/multicaller.py b/fastlane_bot/config/multicaller.py index d68760942..76b031bf6 100644 --- a/fastlane_bot/config/multicaller.py +++ b/fastlane_bot/config/multicaller.py @@ -6,9 +6,10 @@ All rights reserved. Licensed under MIT. """ -from typing import Callable, Any, List, Dict +from typing import Any, List, Dict from eth_abi import decode +from web3.contract.contract import ContractFunction from fastlane_bot.data.abi import MULTICALL_ABI @@ -45,10 +46,10 @@ class MultiCaller: def __init__(self, web3: Any, multicall_contract_address: str): self.multicall_contract = web3.eth.contract(abi=MULTICALL_ABI, address=multicall_contract_address) - self.contract_calls: List[Callable] = [] + self.contract_calls: List[ContractFunction] = [] self.output_types_list: List[List[str]] = [] - def add_call(self, call: Callable): + def add_call(self, call: ContractFunction): self.contract_calls.append({'target': call.address, 'callData': call._encode_transaction_data()}) self.output_types_list.append([collapse_if_tuple(item) for item in call.abi['outputs']]) From ec9ca60ae78f2fc7a48c0e60352088f8701e02ba Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sun, 12 May 2024 12:58:56 +0300 Subject: [PATCH 102/131] Fix the pool-finder-period handling --- main.py | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/main.py b/main.py index cdff59ead..ae475d7db 100644 --- a/main.py +++ b/main.py @@ -94,6 +94,7 @@ def int_or_none(x): "self_fund": is_true, "read_only": is_true, "is_args_test": is_true, + "pool_finder_period": int, } # Apply the transformations @@ -225,7 +226,7 @@ def main(args: argparse.Namespace) -> None: prefix_path: {args.prefix_path} self_fund: {args.self_fund} read_only: {args.read_only} - pool_finder: {args.pool_finder} + pool_finder_period: {args.pool_finder_period} +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -306,17 +307,14 @@ def run(mgr, args, tenderly_uri=None) -> None: event_gatherer = EventGatherer(w3=mgr.w3_async, exchanges=mgr.exchanges, event_contracts=mgr.event_contracts) - if args.pool_finder != -1: - pool_finder = PoolFinder( - carbon_forks=mgr.cfg.network.CARBON_V1_FORKS, - uni_v3_forks=mgr.cfg.network.UNI_V3_FORKS, - flashloan_tokens=args.flashloan_tokens, - exchanges=mgr.exchanges, - web3=mgr.web3, - multicall_address=mgr.cfg.network.MULTICALL_CONTRACT_ADDRESS - ) - else: - pool_finder = None + pool_finder = PoolFinder( + carbon_forks=mgr.cfg.network.CARBON_V1_FORKS, + uni_v3_forks=mgr.cfg.network.UNI_V3_FORKS, + flashloan_tokens=args.flashloan_tokens, + exchanges=mgr.exchanges, + web3=mgr.web3, + multicall_address=mgr.cfg.network.MULTICALL_CONTRACT_ADDRESS + ) while True: try: @@ -527,7 +525,7 @@ def run(mgr, args, tenderly_uri=None) -> None: mgr.solidly_v2_event_mappings = dict( solidly_v2_event_mappings[["address", "exchange"]].values ) - if pool_finder is not None and (loop_idx % args.pool_finder == 0 or loop_idx == 1): + if args.pool_finder_period > 0 and loop_idx % args.pool_finder_period == 0: mgr.cfg.logger.info(f"Searching for unsupported Carbon pairs.") uni_v2, uni_v3, solidly_v2 = pool_finder.get_pools_for_unsupported_pairs(mgr.pool_data, arb_mode=args.arb_mode) result = f"Added {len(uni_v2) + len(uni_v3) + len(solidly_v2)} pools." if (uni_v2 or uni_v3 or solidly_v2) else f"No pools added." @@ -734,9 +732,9 @@ def run(mgr, args, tenderly_uri=None) -> None: help="Custom RPC URL. If not set, the bot will use the default Alchemy RPC URL for the blockchain (if available).", ) parser.add_argument( - "--pool_finder", + "--pool_finder_period", default=100, - help="If not -1, searches for pools that can service Carbon strategies that do not have viable routes.", + help="Searches for pools that can service Carbon strategies that do not have viable routes.", ) # Process the arguments From d13af71971e658741bee5702e2870fb712213034 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sun, 12 May 2024 15:32:50 +0300 Subject: [PATCH 103/131] Remove the multicall dependency from all Exchange classes --- fastlane_bot/events/exchanges/balancer.py | 7 ------- fastlane_bot/events/exchanges/bancor_pol.py | 7 ------- fastlane_bot/events/exchanges/bancor_v2.py | 10 +--------- fastlane_bot/events/exchanges/bancor_v3.py | 9 +-------- fastlane_bot/events/exchanges/base.py | 8 -------- fastlane_bot/events/exchanges/carbon_v1.py | 7 ------- .../events/exchanges/solidly_v2/base.py | 5 ++--- .../events/exchanges/solidly_v2/velodrome_v2.py | 5 ++--- .../events/exchanges/solidly_v2/xfai_v0.py | 5 ++--- fastlane_bot/events/exchanges/uniswap_v2.py | 5 ++--- fastlane_bot/events/exchanges/uniswap_v3.py | 7 +++---- fastlane_bot/pool_finder.py | 17 +++++------------ main.py | 3 +-- 13 files changed, 19 insertions(+), 76 deletions(-) diff --git a/fastlane_bot/events/exchanges/balancer.py b/fastlane_bot/events/exchanges/balancer.py index 2f9f99fc9..2ec32119b 100644 --- a/fastlane_bot/events/exchanges/balancer.py +++ b/fastlane_bot/events/exchanges/balancer.py @@ -16,7 +16,6 @@ from web3.contract import Contract -from fastlane_bot.config.multicaller import MultiCaller from fastlane_bot.data.abi import BALANCER_VAULT_ABI, BALANCER_POOL_ABI_V1 from ..exchanges.base import Exchange from ..pools.base import Pool @@ -89,9 +88,3 @@ async def get_tkn_n(self, address: str, contract: Contract, event: Any, index: i tokens = pool_balances[0] token_balances = pool_balances[1] return token_balances[index] - - def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2): - """ - This function is unused for Carbon. - """ - raise NotImplementedError \ No newline at end of file diff --git a/fastlane_bot/events/exchanges/bancor_pol.py b/fastlane_bot/events/exchanges/bancor_pol.py index 3fbb0fbb0..bc66bb7c5 100644 --- a/fastlane_bot/events/exchanges/bancor_pol.py +++ b/fastlane_bot/events/exchanges/bancor_pol.py @@ -16,7 +16,6 @@ from web3.contract import Contract -from fastlane_bot.config.multicaller import MultiCaller from fastlane_bot.data.abi import BANCOR_POL_ABI from fastlane_bot import Config from ..exchanges.base import Exchange @@ -64,12 +63,6 @@ async def get_tkn0(self, address: str, contract: Contract, event: Event) -> str: async def get_tkn1(self, address: str, contract: Contract, event: Event) -> str: return self.ETH_ADDRESS if event.args["token"] not in self.ETH_ADDRESS else self.BNT_ADDRESS - def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2): - """ - This function is unused for Carbon. - """ - raise NotImplementedError - def save_strategy( self, token: str, diff --git a/fastlane_bot/events/exchanges/bancor_v2.py b/fastlane_bot/events/exchanges/bancor_v2.py index 41ff63860..8da7d1745 100644 --- a/fastlane_bot/events/exchanges/bancor_v2.py +++ b/fastlane_bot/events/exchanges/bancor_v2.py @@ -12,12 +12,10 @@ Licensed under MIT. """ from dataclasses import dataclass -from typing import List, Type, Tuple, Any +from typing import List, Type, Tuple -from web3 import AsyncWeb3 from web3.contract import Contract, AsyncContract -from fastlane_bot.config.multicaller import MultiCaller from fastlane_bot.data.abi import BANCOR_V2_CONVERTER_ABI from ..exchanges.base import Exchange from ..pools.base import Pool @@ -78,9 +76,3 @@ async def get_tkn1(self, address: str, contract: Contract, event: Event) -> str: async def get_anchor(self, contract: Contract) -> str: return await contract.caller.anchor() - - def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2): - """ - This function is unused for Carbon. - """ - raise NotImplementedError \ No newline at end of file diff --git a/fastlane_bot/events/exchanges/bancor_v3.py b/fastlane_bot/events/exchanges/bancor_v3.py index b21c6f7bb..2af08a103 100644 --- a/fastlane_bot/events/exchanges/bancor_v3.py +++ b/fastlane_bot/events/exchanges/bancor_v3.py @@ -12,11 +12,10 @@ Licensed under MIT. """ from dataclasses import dataclass -from typing import List, Type, Tuple, Any +from typing import List, Type, Tuple from web3.contract import Contract -from fastlane_bot.config.multicaller import MultiCaller from fastlane_bot.data.abi import BANCOR_V3_POOL_COLLECTION_ABI from ..exchanges.base import Exchange from ..pools.base import Pool @@ -65,9 +64,3 @@ async def get_tkn1(self, address: str, contract: Contract, event: Event) -> str: if event.args["pool"] != self.BNT_ADDRESS else event.args["tkn_address"] ) - - def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2): - """ - This function is unused for Carbon. - """ - raise NotImplementedError \ No newline at end of file diff --git a/fastlane_bot/events/exchanges/base.py b/fastlane_bot/events/exchanges/base.py index 93020c3b5..bf450ff12 100644 --- a/fastlane_bot/events/exchanges/base.py +++ b/fastlane_bot/events/exchanges/base.py @@ -17,7 +17,6 @@ from web3.contract import Contract, AsyncContract from fastlane_bot.config.constants import CARBON_V1_NAME -from fastlane_bot.config.multicaller import MultiCaller from ..pools.base import Pool from ..interfaces.subscription import Subscription @@ -124,13 +123,6 @@ async def get_fee(address: str, contract: AsyncContract) -> float: """ pass - @abstractmethod - def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2, *args): - """ - Returns the Factory contract function used to fetch liquidity pools. - """ - ... - @staticmethod @abstractmethod async def get_tkn0(address: str, contract: AsyncContract, event: Any) -> str: diff --git a/fastlane_bot/events/exchanges/carbon_v1.py b/fastlane_bot/events/exchanges/carbon_v1.py index b3708c822..df0540661 100644 --- a/fastlane_bot/events/exchanges/carbon_v1.py +++ b/fastlane_bot/events/exchanges/carbon_v1.py @@ -17,7 +17,6 @@ from fastlane_bot import Config from web3.contract import Contract -from fastlane_bot.config.multicaller import MultiCaller from fastlane_bot.data.abi import CARBON_CONTROLLER_ABI from ..exchanges.base import Exchange from ..pools.base import Pool @@ -245,9 +244,3 @@ def save_strategy( ), block_number=block_number, ) - - def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2): - """ - This function is unused for Carbon. - """ - raise NotImplementedError \ No newline at end of file diff --git a/fastlane_bot/events/exchanges/solidly_v2/base.py b/fastlane_bot/events/exchanges/solidly_v2/base.py index 52a971e7e..e58a474ff 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/base.py +++ b/fastlane_bot/events/exchanges/solidly_v2/base.py @@ -17,7 +17,6 @@ from web3.contract import Contract, AsyncContract -from fastlane_bot.config.multicaller import MultiCaller from fastlane_bot.data.abi import SOLIDLY_V2_POOL_ABI from fastlane_bot.events.exchanges.base import Exchange from ...exchanges.base import Exchange @@ -63,8 +62,8 @@ async def get_tkn0(self, address: str, contract: Contract, event: Any) -> str: async def get_tkn1(self, address: str, contract: Contract, event: Any) -> str: return await contract.caller.token1() - def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2): - mc.add_call(self.factory_contract.functions.getPair, addr1, addr2, True) + def get_pool(self, addr1, addr2): + return self.factory_contract.functions.getPair(addr1, addr2, False) @property @abstractmethod diff --git a/fastlane_bot/events/exchanges/solidly_v2/velodrome_v2.py b/fastlane_bot/events/exchanges/solidly_v2/velodrome_v2.py index 1224c6df6..e15d17bf2 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/velodrome_v2.py +++ b/fastlane_bot/events/exchanges/solidly_v2/velodrome_v2.py @@ -3,7 +3,6 @@ from web3.contract import AsyncContract -from fastlane_bot.config.multicaller import MultiCaller from fastlane_bot.data.abi import SOLIDLY_V2_FACTORY_ABI from .base import SolidlyV2 @@ -19,5 +18,5 @@ async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, flo fee_float = float(fee) / 10 ** 4 return str(fee_float), fee_float - def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2): - mc.add_call(self.factory_contract.functions.getPool, addr1, addr2, True) + def get_pool(self, addr1, addr2): + return self.factory_contract.functions.getPool(addr1, addr2, False) diff --git a/fastlane_bot/events/exchanges/solidly_v2/xfai_v0.py b/fastlane_bot/events/exchanges/solidly_v2/xfai_v0.py index e8d7eb55e..75cc7cb00 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/xfai_v0.py +++ b/fastlane_bot/events/exchanges/solidly_v2/xfai_v0.py @@ -3,7 +3,6 @@ from web3.contract import Contract, AsyncContract -from fastlane_bot.config.multicaller import MultiCaller from fastlane_bot.data.abi import XFAI_V0_POOL_ABI, XFAI_V0_FACTORY_ABI from .base import SolidlyV2 @@ -30,5 +29,5 @@ async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, flo fee_float = float(fee) / 10 ** 4 return str(fee_float), fee_float - def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2): - mc.add_call(self.factory_contract.functions.getPool, addr1) + def get_pool(self, addr1, addr2): + return self.factory_contract.functions.getPool(addr1) diff --git a/fastlane_bot/events/exchanges/uniswap_v2.py b/fastlane_bot/events/exchanges/uniswap_v2.py index c7ed2615f..1043f7afe 100644 --- a/fastlane_bot/events/exchanges/uniswap_v2.py +++ b/fastlane_bot/events/exchanges/uniswap_v2.py @@ -16,7 +16,6 @@ from web3.contract import Contract, AsyncContract -from fastlane_bot.config.multicaller import MultiCaller from fastlane_bot.data.abi import UNISWAP_V2_POOL_ABI, UNISWAP_V2_FACTORY_ABI from ..exchanges.base import Exchange from ..pools.base import Pool @@ -64,5 +63,5 @@ async def get_tkn0(address: str, contract: AsyncContract, event: Any) -> str: async def get_tkn1(address: str, contract: AsyncContract, event: Any) -> str: return await contract.caller.token1() - def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2): - mc.add_call(self.factory_contract.functions.getPair, addr1, addr2) + def get_pool(self, addr1, addr2): + return self.factory_contract.functions.getPair(addr1, addr2) diff --git a/fastlane_bot/events/exchanges/uniswap_v3.py b/fastlane_bot/events/exchanges/uniswap_v3.py index 604ba5af9..569fd6bee 100644 --- a/fastlane_bot/events/exchanges/uniswap_v3.py +++ b/fastlane_bot/events/exchanges/uniswap_v3.py @@ -14,10 +14,9 @@ from dataclasses import dataclass from typing import List, Type, Tuple, Any -from web3.contract import Contract, AsyncContract +from web3.contract import Contract from fastlane_bot.config.constants import AGNI_V3_NAME, PANCAKESWAP_V3_NAME, FUSIONX_V3_NAME, ECHODEX_V3_NAME, SECTA_V3_NAME -from fastlane_bot.config.multicaller import MultiCaller from fastlane_bot.data.abi import UNISWAP_V3_POOL_ABI, UNISWAP_V3_FACTORY_ABI, PANCAKESWAP_V3_POOL_ABI from ..exchanges.base import Exchange from ..pools.base import Pool @@ -61,5 +60,5 @@ async def get_tkn0(self, address: str, contract: Contract, event: Any) -> str: async def get_tkn1(self, address: str, contract: Contract, event: Any) -> str: return await contract.caller.token1() - def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2, fee): - mc.add_call(self.factory_contract.functions.getPool, addr1, addr2, fee) + def get_pool(self, addr1, addr2, fee): + return self.factory_contract.functions.getPool(addr1, addr2, fee) diff --git a/fastlane_bot/pool_finder.py b/fastlane_bot/pool_finder.py index 8f56436e4..988e2e7da 100644 --- a/fastlane_bot/pool_finder.py +++ b/fastlane_bot/pool_finder.py @@ -91,11 +91,6 @@ def _find_pools(self, unsupported_pairs: List[Tuple]) -> Dict[str, List[str]]: Dict[str, List[str]]: A list of dictionaries, where each dictionary maps an exchange's name to a list of valid pool addresses (i.e., non-zero addresses) obtained from the multicall across all generated pairs. - - Raises: - Exception: An exception could be raised from the multicall operation depending on the - implementation specifics of the multicall context manager or the exchange's - get_pool_with_multicall method if it encounters a problem. """ pairs = [(tkn, token) for pair in unsupported_pairs for tkn in pair for token in self._flashloan_tokens] chunk_size = 400 @@ -108,17 +103,15 @@ def _find_pools(self, unsupported_pairs: List[Tuple]) -> Dict[str, List[str]]: mc = MultiCaller(contract=exchange.factory_contract, web3=self._web3, multicall_address=self._multicall_address) for pair in pair_chunk: if exchange.base_exchange_name in [UNISWAP_V2_NAME, SOLIDLY_V2_NAME]: - exchange.get_pool_with_multicall(mc, pair[0], pair[1]) + mc.add_call(exchange.get_pool(pair[0], pair[1])) elif exchange.base_exchange_name == UNISWAP_V3_NAME: for fee in self._uni_v3_fee_tiers[exchange.exchange_name]: - exchange.get_pool_with_multicall(mc, pair[0], pair[1], fee) + mc.add_call(exchange.get_pool(pair[0], pair[1], fee)) response = mc.multicall() - result[exchange.base_exchange_name] = { + result[exchange.base_exchange_name].update({ mc.web3.to_checksum_address(addr): exchange.exchange_name - for addr - in response - if addr != ZERO_ADDRESS - } + for addr in response if addr != ZERO_ADDRESS + }) return result diff --git a/main.py b/main.py index ae475d7db..c1d2adc90 100644 --- a/main.py +++ b/main.py @@ -528,8 +528,7 @@ def run(mgr, args, tenderly_uri=None) -> None: if args.pool_finder_period > 0 and loop_idx % args.pool_finder_period == 0: mgr.cfg.logger.info(f"Searching for unsupported Carbon pairs.") uni_v2, uni_v3, solidly_v2 = pool_finder.get_pools_for_unsupported_pairs(mgr.pool_data, arb_mode=args.arb_mode) - result = f"Added {len(uni_v2) + len(uni_v3) + len(solidly_v2)} pools." if (uni_v2 or uni_v3 or solidly_v2) else f"No pools added." - mgr.cfg.logger.info(result) + mgr.cfg.logger.info(f"Number of pools added: {len(uni_v2) + len(uni_v3) + len(solidly_v2)}") mgr.uniswap_v2_event_mappings.update(uni_v2) mgr.uniswap_v3_event_mappings.update(uni_v3) mgr.solidly_v2_event_mappings.update(solidly_v2) From 7be89e57519bff29faebe09f81834f9a8c5ce382 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sun, 12 May 2024 15:39:08 +0300 Subject: [PATCH 104/131] Minor --- fastlane_bot/pool_finder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane_bot/pool_finder.py b/fastlane_bot/pool_finder.py index 988e2e7da..fa71809ba 100644 --- a/fastlane_bot/pool_finder.py +++ b/fastlane_bot/pool_finder.py @@ -109,7 +109,7 @@ def _find_pools(self, unsupported_pairs: List[Tuple]) -> Dict[str, List[str]]: mc.add_call(exchange.get_pool(pair[0], pair[1], fee)) response = mc.multicall() result[exchange.base_exchange_name].update({ - mc.web3.to_checksum_address(addr): exchange.exchange_name + self._web3.to_checksum_address(addr): exchange.exchange_name for addr in response if addr != ZERO_ADDRESS }) return result From c400d4a7a85df84da157a688a30c6a72dc780a21 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sun, 12 May 2024 15:47:28 +0300 Subject: [PATCH 105/131] Simplify the code --- fastlane_bot/pool_finder.py | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/fastlane_bot/pool_finder.py b/fastlane_bot/pool_finder.py index fa71809ba..606c12ef5 100644 --- a/fastlane_bot/pool_finder.py +++ b/fastlane_bot/pool_finder.py @@ -61,7 +61,7 @@ def get_pools_for_unsupported_pairs(self, pools: List[Dict[str, Any]], arb_mode: _find_unsupported_pairs, and _find_unsupported_triangles methods. Returns: - Dict: Returns a dictionary with pools sorted into different exchange types (Uni V2 forks, Uni V3 forks, + Dict: Returns a list of dictionaries with pools sorted into different exchange types (Uni V2 forks, Uni V3 forks, and Solidly V2 forks), each associated with their specific supporting pools based on the unsupported configurations identified. """ @@ -73,25 +73,7 @@ def get_pools_for_unsupported_pairs(self, pools: List[Dict[str, Any]], arb_mode: unsupported_pairs = PoolFinder._find_unsupported_triangles(self._flashloan_tokens, carbon_pairs=carbon_pairs, external_pairs=other_pairs) else: unsupported_pairs = PoolFinder._find_unsupported_pairs(self._flashloan_tokens, carbon_pairs=carbon_pairs, external_pairs=other_pairs) - missing_pools = self._find_pools(unsupported_pairs) - return missing_pools[UNISWAP_V2_NAME], missing_pools[UNISWAP_V3_NAME], missing_pools[SOLIDLY_V2_NAME] - - def _find_pools(self, unsupported_pairs: List[Tuple]) -> Dict[str, List[str]]: - """ - Collects pool addresses for each exchange, based on a set of unsupported token pairs - and flashloan tokens. The function constructs pairs of tokens from unsupported_pairs with each - flashloan token and retrieves pool data via multicall. It filters out invalid addresses. - - Args: - unsupported_pairs (List[Tuple]): A list of tuples, where each tuple contains two token addresses. - flashloan_tokens (List[str]): A list of token addresses available for flashloans. - - Returns: - Dict[str, List[str]]: A list of dictionaries, where each dictionary maps an exchange's name - to a list of valid pool addresses (i.e., non-zero addresses) obtained - from the multicall across all generated pairs. - """ pairs = [(tkn, token) for pair in unsupported_pairs for tkn in pair for token in self._flashloan_tokens] chunk_size = 400 # Create the list of chunks @@ -112,7 +94,8 @@ def _find_pools(self, unsupported_pairs: List[Tuple]) -> Dict[str, List[str]]: self._web3.to_checksum_address(addr): exchange.exchange_name for addr in response if addr != ZERO_ADDRESS }) - return result + + return result[UNISWAP_V2_NAME], result[UNISWAP_V3_NAME], result[SOLIDLY_V2_NAME] def _extract_pairs(self, pools: List[Dict[str, Any]]) -> Tuple[List, set]: From f28f181572deee0f5ad2a307ac6fe4fce31952f7 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sun, 12 May 2024 15:54:34 +0300 Subject: [PATCH 106/131] Rename `get_pool` to `get_pool_func_call` --- fastlane_bot/events/exchanges/solidly_v2/base.py | 2 +- fastlane_bot/events/exchanges/solidly_v2/velodrome_v2.py | 2 +- fastlane_bot/events/exchanges/solidly_v2/xfai_v0.py | 2 +- fastlane_bot/events/exchanges/uniswap_v2.py | 2 +- fastlane_bot/events/exchanges/uniswap_v3.py | 2 +- fastlane_bot/pool_finder.py | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/fastlane_bot/events/exchanges/solidly_v2/base.py b/fastlane_bot/events/exchanges/solidly_v2/base.py index e58a474ff..7bffef541 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/base.py +++ b/fastlane_bot/events/exchanges/solidly_v2/base.py @@ -62,7 +62,7 @@ async def get_tkn0(self, address: str, contract: Contract, event: Any) -> str: async def get_tkn1(self, address: str, contract: Contract, event: Any) -> str: return await contract.caller.token1() - def get_pool(self, addr1, addr2): + def get_pool_func_call(self, addr1, addr2): return self.factory_contract.functions.getPair(addr1, addr2, False) @property diff --git a/fastlane_bot/events/exchanges/solidly_v2/velodrome_v2.py b/fastlane_bot/events/exchanges/solidly_v2/velodrome_v2.py index e15d17bf2..27dc61bd4 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/velodrome_v2.py +++ b/fastlane_bot/events/exchanges/solidly_v2/velodrome_v2.py @@ -18,5 +18,5 @@ async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, flo fee_float = float(fee) / 10 ** 4 return str(fee_float), fee_float - def get_pool(self, addr1, addr2): + def get_pool_func_call(self, addr1, addr2): return self.factory_contract.functions.getPool(addr1, addr2, False) diff --git a/fastlane_bot/events/exchanges/solidly_v2/xfai_v0.py b/fastlane_bot/events/exchanges/solidly_v2/xfai_v0.py index 75cc7cb00..2b40d98d3 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/xfai_v0.py +++ b/fastlane_bot/events/exchanges/solidly_v2/xfai_v0.py @@ -29,5 +29,5 @@ async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, flo fee_float = float(fee) / 10 ** 4 return str(fee_float), fee_float - def get_pool(self, addr1, addr2): + def get_pool_func_call(self, addr1, addr2): return self.factory_contract.functions.getPool(addr1) diff --git a/fastlane_bot/events/exchanges/uniswap_v2.py b/fastlane_bot/events/exchanges/uniswap_v2.py index 1043f7afe..ce1e209cc 100644 --- a/fastlane_bot/events/exchanges/uniswap_v2.py +++ b/fastlane_bot/events/exchanges/uniswap_v2.py @@ -63,5 +63,5 @@ async def get_tkn0(address: str, contract: AsyncContract, event: Any) -> str: async def get_tkn1(address: str, contract: AsyncContract, event: Any) -> str: return await contract.caller.token1() - def get_pool(self, addr1, addr2): + def get_pool_func_call(self, addr1, addr2): return self.factory_contract.functions.getPair(addr1, addr2) diff --git a/fastlane_bot/events/exchanges/uniswap_v3.py b/fastlane_bot/events/exchanges/uniswap_v3.py index 569fd6bee..76d8a93d5 100644 --- a/fastlane_bot/events/exchanges/uniswap_v3.py +++ b/fastlane_bot/events/exchanges/uniswap_v3.py @@ -60,5 +60,5 @@ async def get_tkn0(self, address: str, contract: Contract, event: Any) -> str: async def get_tkn1(self, address: str, contract: Contract, event: Any) -> str: return await contract.caller.token1() - def get_pool(self, addr1, addr2, fee): + def get_pool_func_call(self, addr1, addr2, fee): return self.factory_contract.functions.getPool(addr1, addr2, fee) diff --git a/fastlane_bot/pool_finder.py b/fastlane_bot/pool_finder.py index 606c12ef5..2cdb8df7f 100644 --- a/fastlane_bot/pool_finder.py +++ b/fastlane_bot/pool_finder.py @@ -85,10 +85,10 @@ def get_pools_for_unsupported_pairs(self, pools: List[Dict[str, Any]], arb_mode: mc = MultiCaller(contract=exchange.factory_contract, web3=self._web3, multicall_address=self._multicall_address) for pair in pair_chunk: if exchange.base_exchange_name in [UNISWAP_V2_NAME, SOLIDLY_V2_NAME]: - mc.add_call(exchange.get_pool(pair[0], pair[1])) + mc.add_call(exchange.get_pool_func_call(pair[0], pair[1])) elif exchange.base_exchange_name == UNISWAP_V3_NAME: for fee in self._uni_v3_fee_tiers[exchange.exchange_name]: - mc.add_call(exchange.get_pool(pair[0], pair[1], fee)) + mc.add_call(exchange.get_pool_func_call(pair[0], pair[1], fee)) response = mc.multicall() result[exchange.base_exchange_name].update({ self._web3.to_checksum_address(addr): exchange.exchange_name From 600809c0debe7d36d3e2698504bedd8da3fe4807 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sun, 12 May 2024 15:57:48 +0300 Subject: [PATCH 107/131] Semantic --- fastlane_bot/pool_finder.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fastlane_bot/pool_finder.py b/fastlane_bot/pool_finder.py index 2cdb8df7f..5e047a026 100644 --- a/fastlane_bot/pool_finder.py +++ b/fastlane_bot/pool_finder.py @@ -89,10 +89,10 @@ def get_pools_for_unsupported_pairs(self, pools: List[Dict[str, Any]], arb_mode: elif exchange.base_exchange_name == UNISWAP_V3_NAME: for fee in self._uni_v3_fee_tiers[exchange.exchange_name]: mc.add_call(exchange.get_pool_func_call(pair[0], pair[1], fee)) - response = mc.multicall() + response = mc.multicall() # TODO: Handle failures gracefully once supported in class `MultiCaller` result[exchange.base_exchange_name].update({ - self._web3.to_checksum_address(addr): exchange.exchange_name - for addr in response if addr != ZERO_ADDRESS + self._web3.to_checksum_address(address): exchange.exchange_name + for address in response if address != ZERO_ADDRESS }) return result[UNISWAP_V2_NAME], result[UNISWAP_V3_NAME], result[SOLIDLY_V2_NAME] From 1ec14972d2acd7538567a97a9c8c10c6eff62d8a Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sun, 12 May 2024 19:06:44 +0300 Subject: [PATCH 108/131] Cleanup --- fastlane_bot/data/abi.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/fastlane_bot/data/abi.py b/fastlane_bot/data/abi.py index daaa04a03..ffdcf65c5 100644 --- a/fastlane_bot/data/abi.py +++ b/fastlane_bot/data/abi.py @@ -169,10 +169,8 @@ "type": "function", "name": "getPair", "stateMutability": "view", - "constant": True, "inputs": [{"internalType": "address", "name": "", "type": "address"}, {"internalType": "address", "name": "", "type": "address"}], - "outputs": [{"internalType": "address", "name": "", "type": "address"}], - "payable": False, + "outputs": [{"internalType": "address", "name": "", "type": "address"}] } ] @@ -256,9 +254,7 @@ "type": "function", "name": "getPair", "stateMutability": "view", - "inputs": [{"internalType": "address", "name": "", "type": "address"}, - {"internalType": "address", "name": "", "type": "address"}, - {"internalType": "bool", "name": "", "type": "bool"}], + "inputs": [{"internalType": "address", "name": "", "type": "address"}, {"internalType": "address", "name": "", "type": "address"}, {"internalType": "bool", "name": "", "type": "bool"}], "outputs": [{"internalType": "address", "name": "", "type": "address"}] } ] From 9590ffb8b30c3ab7fc7ec024b134afd6d0eba6b4 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sun, 12 May 2024 19:37:33 +0300 Subject: [PATCH 109/131] Minor --- fastlane_bot/data/abi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane_bot/data/abi.py b/fastlane_bot/data/abi.py index ffdcf65c5..3c98f7000 100644 --- a/fastlane_bot/data/abi.py +++ b/fastlane_bot/data/abi.py @@ -205,9 +205,9 @@ "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}] }, { + "type": "function", "name": "getPool", "stateMutability": "view", - "type": "function", "inputs": [{"internalType": "address", "name": "tokenA", "type": "address"}, {"internalType": "address", "name": "tokenB", "type": "address"}, {"internalType": "bool", "name": "stable", "type": "bool"}], "outputs": [{"internalType": "address", "name": "", "type": "address"}], } From 6761c2ed42f20084dbf7a7ec3221c6775b2dde98 Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Sun, 12 May 2024 23:22:08 +0300 Subject: [PATCH 110/131] Fix usage of `MultiCall` in `PoolFinder` --- fastlane_bot/pool_finder.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fastlane_bot/pool_finder.py b/fastlane_bot/pool_finder.py index 5e047a026..15ff0584f 100644 --- a/fastlane_bot/pool_finder.py +++ b/fastlane_bot/pool_finder.py @@ -82,17 +82,17 @@ def get_pools_for_unsupported_pairs(self, pools: List[Dict[str, Any]], arb_mode: for exchange in self._exchanges: for pair_chunk in chunked_pairs: - mc = MultiCaller(contract=exchange.factory_contract, web3=self._web3, multicall_address=self._multicall_address) + mc = MultiCaller(self._web3, self._multicall_address) for pair in pair_chunk: if exchange.base_exchange_name in [UNISWAP_V2_NAME, SOLIDLY_V2_NAME]: mc.add_call(exchange.get_pool_func_call(pair[0], pair[1])) elif exchange.base_exchange_name == UNISWAP_V3_NAME: for fee in self._uni_v3_fee_tiers[exchange.exchange_name]: mc.add_call(exchange.get_pool_func_call(pair[0], pair[1], fee)) - response = mc.multicall() # TODO: Handle failures gracefully once supported in class `MultiCaller` + addresses = mc.run_calls() result[exchange.base_exchange_name].update({ self._web3.to_checksum_address(address): exchange.exchange_name - for address in response if address != ZERO_ADDRESS + for address in addresses if address not in [None, ZERO_ADDRESS] }) return result[UNISWAP_V2_NAME], result[UNISWAP_V3_NAME], result[SOLIDLY_V2_NAME] From 705a78c180604d45ff650b733d15fc16a7cb8c1f Mon Sep 17 00:00:00 2001 From: barak manos <> Date: Mon, 13 May 2024 11:14:02 +0300 Subject: [PATCH 111/131] Ensure that the pool-finder runs on the first iteration when enabled (i.e., when its period is larger than 0) --- main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.py b/main.py index c1d2adc90..71a5ca8d7 100644 --- a/main.py +++ b/main.py @@ -525,7 +525,7 @@ def run(mgr, args, tenderly_uri=None) -> None: mgr.solidly_v2_event_mappings = dict( solidly_v2_event_mappings[["address", "exchange"]].values ) - if args.pool_finder_period > 0 and loop_idx % args.pool_finder_period == 0: + if args.pool_finder_period > 0 and (loop_idx - 1) % args.pool_finder_period == 0: mgr.cfg.logger.info(f"Searching for unsupported Carbon pairs.") uni_v2, uni_v3, solidly_v2 = pool_finder.get_pools_for_unsupported_pairs(mgr.pool_data, arb_mode=args.arb_mode) mgr.cfg.logger.info(f"Number of pools added: {len(uni_v2) + len(uni_v3) + len(solidly_v2)}") From 3acf35485152b3b1e51f307efb32d19b5b5a8070 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Mon, 13 May 2024 14:45:38 +0300 Subject: [PATCH 112/131] chore: added get_pool_func_call to the interface --- fastlane_bot/events/exchanges/balancer.py | 3 +++ fastlane_bot/events/exchanges/bancor_pol.py | 3 +++ fastlane_bot/events/exchanges/bancor_v2.py | 3 +++ fastlane_bot/events/exchanges/bancor_v3.py | 3 +++ fastlane_bot/events/exchanges/base.py | 4 ++++ fastlane_bot/events/exchanges/carbon_v1.py | 3 +++ 6 files changed, 19 insertions(+) diff --git a/fastlane_bot/events/exchanges/balancer.py b/fastlane_bot/events/exchanges/balancer.py index 2ec32119b..384ee5fda 100644 --- a/fastlane_bot/events/exchanges/balancer.py +++ b/fastlane_bot/events/exchanges/balancer.py @@ -88,3 +88,6 @@ async def get_tkn_n(self, address: str, contract: Contract, event: Any, index: i tokens = pool_balances[0] token_balances = pool_balances[1] return token_balances[index] + + def get_pool_func_call(self, addr1, addr2): + raise NotImplementedError diff --git a/fastlane_bot/events/exchanges/bancor_pol.py b/fastlane_bot/events/exchanges/bancor_pol.py index bc66bb7c5..1dab4c8fe 100644 --- a/fastlane_bot/events/exchanges/bancor_pol.py +++ b/fastlane_bot/events/exchanges/bancor_pol.py @@ -105,3 +105,6 @@ def save_strategy( cid=cid, block_number=block_number, ) + + def get_pool_func_call(self, addr1, addr2): + raise NotImplementedError diff --git a/fastlane_bot/events/exchanges/bancor_v2.py b/fastlane_bot/events/exchanges/bancor_v2.py index 8da7d1745..a4ab5db4a 100644 --- a/fastlane_bot/events/exchanges/bancor_v2.py +++ b/fastlane_bot/events/exchanges/bancor_v2.py @@ -76,3 +76,6 @@ async def get_tkn1(self, address: str, contract: Contract, event: Event) -> str: async def get_anchor(self, contract: Contract) -> str: return await contract.caller.anchor() + + def get_pool_func_call(self, addr1, addr2): + raise NotImplementedError diff --git a/fastlane_bot/events/exchanges/bancor_v3.py b/fastlane_bot/events/exchanges/bancor_v3.py index 2af08a103..2b14afe0d 100644 --- a/fastlane_bot/events/exchanges/bancor_v3.py +++ b/fastlane_bot/events/exchanges/bancor_v3.py @@ -64,3 +64,6 @@ async def get_tkn1(self, address: str, contract: Contract, event: Event) -> str: if event.args["pool"] != self.BNT_ADDRESS else event.args["tkn_address"] ) + + def get_pool_func_call(self, addr1, addr2): + raise NotImplementedError diff --git a/fastlane_bot/events/exchanges/base.py b/fastlane_bot/events/exchanges/base.py index bf450ff12..8ff438a1b 100644 --- a/fastlane_bot/events/exchanges/base.py +++ b/fastlane_bot/events/exchanges/base.py @@ -123,6 +123,10 @@ async def get_fee(address: str, contract: AsyncContract) -> float: """ pass + @abstractmethod + def get_pool_func_call(self, addr1, addr2, *args, **kwargs): + ... + @staticmethod @abstractmethod async def get_tkn0(address: str, contract: AsyncContract, event: Any) -> str: diff --git a/fastlane_bot/events/exchanges/carbon_v1.py b/fastlane_bot/events/exchanges/carbon_v1.py index df0540661..fa4a40107 100644 --- a/fastlane_bot/events/exchanges/carbon_v1.py +++ b/fastlane_bot/events/exchanges/carbon_v1.py @@ -244,3 +244,6 @@ def save_strategy( ), block_number=block_number, ) + + def get_pool_func_call(self, addr1, addr2): + raise NotImplementedError From 99bdb50a3d2c5aaa88df38b0c42373df69112b17 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Tue, 14 May 2024 00:32:52 +0300 Subject: [PATCH 113/131] feat: add event topic test --- .../events/exchanges/solidly_v2/__init__.py | 4 +- fastlane_bot/tests/conftest.py | 36 +++++++++++++ fastlane_bot/tests/test_event_topics.py | 50 +++++++++++++++++++ 3 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 fastlane_bot/tests/conftest.py create mode 100644 fastlane_bot/tests/test_event_topics.py diff --git a/fastlane_bot/events/exchanges/solidly_v2/__init__.py b/fastlane_bot/events/exchanges/solidly_v2/__init__.py index c81f0bca4..7411376aa 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/__init__.py +++ b/fastlane_bot/events/exchanges/solidly_v2/__init__.py @@ -1,4 +1,4 @@ -from ..base import Exchange +from .base import SolidlyV2 as SolidlyV2Base from .velocimeter_v2 import VelocimeterV2 from .equalizer_v2 import EqualizerV2 from .velodrome_v2 import VelodromeV2 @@ -9,7 +9,7 @@ from .xfai_v0 import XFaiV2 -class SolidlyV2(Exchange): +class SolidlyV2(SolidlyV2Base): def __new__(cls, **kwargs): return { "velocimeter_v2": VelocimeterV2, diff --git a/fastlane_bot/tests/conftest.py b/fastlane_bot/tests/conftest.py new file mode 100644 index 000000000..e1bd98a8a --- /dev/null +++ b/fastlane_bot/tests/conftest.py @@ -0,0 +1,36 @@ +import pytest + +import pandas as pd + +from fastlane_bot import Config +from fastlane_bot.events.managers.manager import Manager + + +@pytest.fixture +def config(): + return Config.new(config=Config.CONFIG_MAINNET) + + +@pytest.fixture +def manager(config): + static_pool_data_filename = "static_pool_data" + static_pool_data = pd.read_csv(f"fastlane_bot/data/{static_pool_data_filename}.csv", low_memory=False) + uniswap_v2_event_mappings = pd.read_csv("fastlane_bot/data/uniswap_v2_event_mappings.csv", low_memory=False) + + exchanges = "carbon_v1,bancor_v3,uniswap_v3,uniswap_v2,sushiswap_v2,bancor_pol,bancor_v2,balancer" + exchanges = exchanges.split(",") + + alchemy_max_block_fetch = 20 + + tokens = pd.read_csv("fastlane_bot/data/tokens.csv", low_memory=False) + + return Manager( + web3=config.w3, + w3_async=config.w3_async, + cfg=config, + pool_data=static_pool_data.to_dict(orient="records"), + SUPPORTED_EXCHANGES=exchanges, + alchemy_max_block_fetch=alchemy_max_block_fetch, + uniswap_v2_event_mappings=uniswap_v2_event_mappings, + tokens=tokens.to_dict(orient="records"), + ) diff --git a/fastlane_bot/tests/test_event_topics.py b/fastlane_bot/tests/test_event_topics.py new file mode 100644 index 000000000..bd7c9692c --- /dev/null +++ b/fastlane_bot/tests/test_event_topics.py @@ -0,0 +1,50 @@ +from fastlane_bot.events.exchanges.carbon_v1 import CarbonV1 +from fastlane_bot.events.exchanges.bancor_pol import BancorPol +from fastlane_bot.events.exchanges.bancor_v2 import BancorV2 +from fastlane_bot.events.exchanges.bancor_v3 import BancorV3 +from fastlane_bot.events.exchanges.uniswap_v2 import UniswapV2 +from fastlane_bot.events.exchanges.uniswap_v3 import UniswapV3 +from fastlane_bot.events.exchanges.solidly_v2 import SolidlyV2 + + +def test_event_topics(manager): + for exchange_name, exchange in manager.exchanges.items(): + contract = manager.event_contracts[exchange_name] + for subscription in exchange.get_subscriptions(contract): + if isinstance(exchange, CarbonV1): + if subscription._event == contract.events.StrategyCreated: + assert subscription.topic == "0xff24554f8ccfe540435cfc8854831f8dcf1cf2068708cfaf46e8b52a4ccc4c8d" + elif subscription._event == contract.events.StrategyUpdated: + assert subscription.topic == "0x720da23a5c920b1d8827ec83c4d3c4d90d9419eadb0036b88cb4c2ffa91aef7d" + elif subscription._event == contract.events.StrategyDeleted: + assert subscription.topic == "0x4d5b6e0627ea711d8e9312b6ba56f50e0b51d41816fd6fd38643495ac81d38b6" + elif subscription._event == contract.events.PairTradingFeePPMUpdated: + assert subscription.topic == "0x831434d05f3ad5f63be733ea463b2933c70d2162697fd200a22b5d56f5c454b6" + elif subscription._event == contract.events.TradingFeePPMUpdated: + assert subscription.topic == "0x66db0986e1156e2e747795714bf0301c7e1c695c149a738cb01bcf5cfead8465" + elif subscription._event == contract.events.PairCreated: + assert subscription.topic == "0x6365c594f5448f79c1cc1e6f661bdbf1d16f2e8f85747e13f8e80f1fd168b7c3" + elif isinstance(exchange, BancorPol): + if subscription._event == contract.events.TokenTraded: + assert subscription.topic == "0x16ddee9b3f1b2e6f797172fe2cd10a214e749294074e075e451f95aecd0b958c" + if subscription._event == contract.events.TradingEnabled: + assert subscription.topic == "0xe695080c3c54317994bff9c7069120ba78f950937caeb98bf02d395abf2a2867" + elif isinstance(exchange, BancorV2): + if subscription._event == contract.events.TokenRateUpdate: + assert subscription.topic == "0x77f29993cf2c084e726f7e802da0719d6a0ade3e204badc7a3ffd57ecb768c24" + elif isinstance(exchange, BancorV3): + if subscription._event == contract.events.TradingLiquidityUpdated: + assert subscription.topic == "0x6e96dc5343d067ec486a9920e0304c3610ed05c65e45cc029d9b9fe7ecfa7620" + elif isinstance(exchange, UniswapV2): + if subscription._event == contract.events.Sync: + assert subscription.topic == "0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1" + elif isinstance(exchange, UniswapV3): + if subscription._event == contract.events.Swap: + assert subscription.topic == "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67" + elif isinstance(exchange, SolidlyV2): + if subscription._event == contract.events.Sync: + assert subscription.topic == "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67" + else: + print(exchange_name) + print(subscription) + assert False From e9c994b0aefbbfbf05fbe1d6b30552456628cde7 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Tue, 14 May 2024 15:50:10 +0300 Subject: [PATCH 114/131] fix: bancor_pol event topic --- fastlane_bot/events/exchanges/bancor_pol.py | 2 +- fastlane_bot/events/exchanges/bancor_v3.py | 8 +- fastlane_bot/tests/conftest.py | 28 ------- fastlane_bot/tests/test_event_topics.py | 84 +++++++++++---------- 4 files changed, 50 insertions(+), 72 deletions(-) diff --git a/fastlane_bot/events/exchanges/bancor_pol.py b/fastlane_bot/events/exchanges/bancor_pol.py index 1dab4c8fe..23176a714 100644 --- a/fastlane_bot/events/exchanges/bancor_pol.py +++ b/fastlane_bot/events/exchanges/bancor_pol.py @@ -51,7 +51,7 @@ def get_events(self, contract: Contract) -> List[Type[Contract]]: def get_subscriptions(self, contract: Contract) -> List[Subscription]: return [ Subscription(contract.events.TokenTraded), - Subscription(contract.events.TradingEnabled), + Subscription(contract.events.TradingEnabled, "0xae3f48c001771f8e9868e24d47b9e4295b06b1d78072acf96f167074aa3fab64"), ] async def get_fee(self, address: str, contract: Contract) -> Tuple[str, float]: diff --git a/fastlane_bot/events/exchanges/bancor_v3.py b/fastlane_bot/events/exchanges/bancor_v3.py index 2b14afe0d..b9ea312b7 100644 --- a/fastlane_bot/events/exchanges/bancor_v3.py +++ b/fastlane_bot/events/exchanges/bancor_v3.py @@ -23,7 +23,8 @@ from ..interfaces.subscription import Subscription -LIQUIDITY_UPDATED_TOPIC = "0x6e96dc5343d067ec486a9920e0304c3610ed05c65e45cc029d9b9fe7ecfa7620" +TRADING_LIQUIDITY_UPDATED_TOPIC = "0x6e96dc5343d067ec486a9920e0304c3610ed05c65e45cc029d9b9fe7ecfa7620" +TOTAL_LIQUIDITY_UPDATED_TOPIC = "0x85a03952f50b8c00b32a521c32094023b64ef0b6d4511f423d44c480a62cb145" @dataclass @@ -50,7 +51,10 @@ def get_events(self, contract: Contract) -> List[Type[Contract]]: return [contract.events.TradingLiquidityUpdated] def get_subscriptions(self, contract: Contract) -> List[Subscription]: - return [Subscription(contract.events.TradingLiquidityUpdated, LIQUIDITY_UPDATED_TOPIC)] + return [ + Subscription(contract.events.TradingLiquidityUpdated, TRADING_LIQUIDITY_UPDATED_TOPIC), + # Subscription(contract.events.TotalLiquidityUpdated, TOTAL_LIQUIDITY_UPDATED_TOPIC), # Unused + ] async def get_fee(self, address: str, contract: Contract) -> Tuple[str, float]: return "0.000", 0.000 diff --git a/fastlane_bot/tests/conftest.py b/fastlane_bot/tests/conftest.py index e1bd98a8a..fa3fc27a7 100644 --- a/fastlane_bot/tests/conftest.py +++ b/fastlane_bot/tests/conftest.py @@ -1,36 +1,8 @@ import pytest -import pandas as pd - from fastlane_bot import Config -from fastlane_bot.events.managers.manager import Manager @pytest.fixture def config(): return Config.new(config=Config.CONFIG_MAINNET) - - -@pytest.fixture -def manager(config): - static_pool_data_filename = "static_pool_data" - static_pool_data = pd.read_csv(f"fastlane_bot/data/{static_pool_data_filename}.csv", low_memory=False) - uniswap_v2_event_mappings = pd.read_csv("fastlane_bot/data/uniswap_v2_event_mappings.csv", low_memory=False) - - exchanges = "carbon_v1,bancor_v3,uniswap_v3,uniswap_v2,sushiswap_v2,bancor_pol,bancor_v2,balancer" - exchanges = exchanges.split(",") - - alchemy_max_block_fetch = 20 - - tokens = pd.read_csv("fastlane_bot/data/tokens.csv", low_memory=False) - - return Manager( - web3=config.w3, - w3_async=config.w3_async, - cfg=config, - pool_data=static_pool_data.to_dict(orient="records"), - SUPPORTED_EXCHANGES=exchanges, - alchemy_max_block_fetch=alchemy_max_block_fetch, - uniswap_v2_event_mappings=uniswap_v2_event_mappings, - tokens=tokens.to_dict(orient="records"), - ) diff --git a/fastlane_bot/tests/test_event_topics.py b/fastlane_bot/tests/test_event_topics.py index bd7c9692c..67e456f71 100644 --- a/fastlane_bot/tests/test_event_topics.py +++ b/fastlane_bot/tests/test_event_topics.py @@ -1,50 +1,52 @@ +import pytest + from fastlane_bot.events.exchanges.carbon_v1 import CarbonV1 from fastlane_bot.events.exchanges.bancor_pol import BancorPol from fastlane_bot.events.exchanges.bancor_v2 import BancorV2 from fastlane_bot.events.exchanges.bancor_v3 import BancorV3 from fastlane_bot.events.exchanges.uniswap_v2 import UniswapV2 from fastlane_bot.events.exchanges.uniswap_v3 import UniswapV3 +from fastlane_bot.events.exchanges.balancer import Balancer from fastlane_bot.events.exchanges.solidly_v2 import SolidlyV2 -def test_event_topics(manager): - for exchange_name, exchange in manager.exchanges.items(): - contract = manager.event_contracts[exchange_name] - for subscription in exchange.get_subscriptions(contract): - if isinstance(exchange, CarbonV1): - if subscription._event == contract.events.StrategyCreated: - assert subscription.topic == "0xff24554f8ccfe540435cfc8854831f8dcf1cf2068708cfaf46e8b52a4ccc4c8d" - elif subscription._event == contract.events.StrategyUpdated: - assert subscription.topic == "0x720da23a5c920b1d8827ec83c4d3c4d90d9419eadb0036b88cb4c2ffa91aef7d" - elif subscription._event == contract.events.StrategyDeleted: - assert subscription.topic == "0x4d5b6e0627ea711d8e9312b6ba56f50e0b51d41816fd6fd38643495ac81d38b6" - elif subscription._event == contract.events.PairTradingFeePPMUpdated: - assert subscription.topic == "0x831434d05f3ad5f63be733ea463b2933c70d2162697fd200a22b5d56f5c454b6" - elif subscription._event == contract.events.TradingFeePPMUpdated: - assert subscription.topic == "0x66db0986e1156e2e747795714bf0301c7e1c695c149a738cb01bcf5cfead8465" - elif subscription._event == contract.events.PairCreated: - assert subscription.topic == "0x6365c594f5448f79c1cc1e6f661bdbf1d16f2e8f85747e13f8e80f1fd168b7c3" - elif isinstance(exchange, BancorPol): - if subscription._event == contract.events.TokenTraded: - assert subscription.topic == "0x16ddee9b3f1b2e6f797172fe2cd10a214e749294074e075e451f95aecd0b958c" - if subscription._event == contract.events.TradingEnabled: - assert subscription.topic == "0xe695080c3c54317994bff9c7069120ba78f950937caeb98bf02d395abf2a2867" - elif isinstance(exchange, BancorV2): - if subscription._event == contract.events.TokenRateUpdate: - assert subscription.topic == "0x77f29993cf2c084e726f7e802da0719d6a0ade3e204badc7a3ffd57ecb768c24" - elif isinstance(exchange, BancorV3): - if subscription._event == contract.events.TradingLiquidityUpdated: - assert subscription.topic == "0x6e96dc5343d067ec486a9920e0304c3610ed05c65e45cc029d9b9fe7ecfa7620" - elif isinstance(exchange, UniswapV2): - if subscription._event == contract.events.Sync: - assert subscription.topic == "0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1" - elif isinstance(exchange, UniswapV3): - if subscription._event == contract.events.Swap: - assert subscription.topic == "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67" - elif isinstance(exchange, SolidlyV2): - if subscription._event == contract.events.Sync: - assert subscription.topic == "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67" - else: - print(exchange_name) - print(subscription) - assert False +@pytest.mark.parametrize("cls,exchange_name,event_topics", [ + (CarbonV1, "carbon_v1", { + "StrategyCreated": "0xff24554f8ccfe540435cfc8854831f8dcf1cf2068708cfaf46e8b52a4ccc4c8d", + "StrategyUpdated": "0x720da23a5c920b1d8827ec83c4d3c4d90d9419eadb0036b88cb4c2ffa91aef7d", + "StrategyDeleted": "0x4d5b6e0627ea711d8e9312b6ba56f50e0b51d41816fd6fd38643495ac81d38b6", + "PairTradingFeePPMUpdated": "0x831434d05f3ad5f63be733ea463b2933c70d2162697fd200a22b5d56f5c454b6", + "TradingFeePPMUpdated": "0x66db0986e1156e2e747795714bf0301c7e1c695c149a738cb01bcf5cfead8465", + "PairCreated": "0x6365c594f5448f79c1cc1e6f661bdbf1d16f2e8f85747e13f8e80f1fd168b7c3", + }), + (BancorPol, "bancor_pol", { + "TokenTraded": "0x16ddee9b3f1b2e6f797172fe2cd10a214e749294074e075e451f95aecd0b958c", + "TradingEnabled": "0xae3f48c001771f8e9868e24d47b9e4295b06b1d78072acf96f167074aa3fab64", + }), + (BancorV2, "bancor_v2", { + "TokenRateUpdate": "0x77f29993cf2c084e726f7e802da0719d6a0ade3e204badc7a3ffd57ecb768c24", + }), + (BancorV3, "bancor_v3", { + "TradingLiquidityUpdated": "0x6e96dc5343d067ec486a9920e0304c3610ed05c65e45cc029d9b9fe7ecfa7620", + # "TotalLiquidityUpdated": "0x85a03952f50b8c00b32a521c32094023b64ef0b6d4511f423d44c480a62cb145", + }), + (UniswapV2, "uniswap_v2", { + "Sync": "0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1", + }), + (UniswapV3, "uniswap_v3", { + "Swap": "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67", + }), + (UniswapV3, "pancakeswap_v3", { + "Swap": "0x19b47279256b2a23a1665c810c8d55a1758940ee09377d4f8d26497a3577dc83", + }), + (Balancer, "balancer", {}), + (SolidlyV2, "velocimeter_v2", { + "Sync": "0xcf2aa50876cdfbb541206f89af0ee78d44a2abf8d328e37fa4917f982149848a", + }), +]) +def test_event_topic(config, cls, exchange_name, event_topics): + exchange = cls(exchange_name=exchange_name) + contract = config.w3.eth.contract(abi=exchange.get_abi()) + for subscription in exchange.get_subscriptions(contract): + assert event_topics.pop(subscription._event.event_name) == subscription.topic + assert event_topics == {} From bf607176448f917853cc0b1d7addf845b653bd96 Mon Sep 17 00:00:00 2001 From: Nicholas Welch Date: Fri, 17 May 2024 15:36:38 +1000 Subject: [PATCH 115/131] update and save new pool_finder pools --- main.py | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/main.py b/main.py index 71a5ca8d7..f2a9c125e 100644 --- a/main.py +++ b/main.py @@ -529,9 +529,26 @@ def run(mgr, args, tenderly_uri=None) -> None: mgr.cfg.logger.info(f"Searching for unsupported Carbon pairs.") uni_v2, uni_v3, solidly_v2 = pool_finder.get_pools_for_unsupported_pairs(mgr.pool_data, arb_mode=args.arb_mode) mgr.cfg.logger.info(f"Number of pools added: {len(uni_v2) + len(uni_v3) + len(solidly_v2)}") - mgr.uniswap_v2_event_mappings.update(uni_v2) - mgr.uniswap_v3_event_mappings.update(uni_v3) - mgr.solidly_v2_event_mappings.update(solidly_v2) + + event_mappings = { + 'uniswap_v2': uni_v2, + 'uniswap_v3': uni_v3, + 'solidly_v2': solidly_v2, + } + for exchange_name, event_mapping_dict in event_mappings.items(): + # Update the manager's event mappings + getattr(mgr, f'{exchange_name}_event_mappings').update(event_mapping_dict) + + # Update the local event_mappings csvs + df = pd.DataFrame.from_dict(getattr(mgr, f'{exchange_name}_event_mappings'), orient='index').reset_index() + if len(df)>0: + df.columns = ['address', 'exchange'] + # if the csvs are always sorted then the diffs will be readable + df.sort_values(by=['exchange','address'], inplace=True) + df.to_csv(f"fastlane_bot/data/blockchain_data/{args.blockchain}/{exchange_name}_event_mappings.csv", index=False) + + # Update the static_pools data for later event filtering + handle_static_pools_update(mgr) last_block_queried = current_block From f7070f943ec2dcafda77d5799ceca5be3d9e4f88 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Fri, 17 May 2024 16:40:34 +0800 Subject: [PATCH 116/131] refactor --- fastlane_bot/events/utils.py | 13 +++++++++++++ main.py | 25 +++++-------------------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/fastlane_bot/events/utils.py b/fastlane_bot/events/utils.py index 2577ba460..87e378456 100644 --- a/fastlane_bot/events/utils.py +++ b/fastlane_bot/events/utils.py @@ -793,6 +793,19 @@ def save_events_to_json( mgr.cfg.logger.debug(f"[events.utils.save_events_to_json] Saved events to {path}") +def process_new_events(new_event_mappings, event_mappings, filename): + # Update the manager's event mappings + event_mappings.update(new_event_mappings) + + # Update the local event_mappings csvs + df = pd.DataFrame.from_dict(event_mappings, orient='index').reset_index() + if len(df)>0: + df.columns = ['address', 'exchange'] + # if the csvs are always sorted then the diffs will be readable + df.sort_values(by=['exchange','address'], inplace=True) + df.to_csv(filename, index=False) + + def update_pools_from_events(n_jobs: int, mgr: Any, latest_events: List[Event]): """ Updates the pools with the given events. diff --git a/main.py b/main.py index f2a9c125e..fcc722efe 100644 --- a/main.py +++ b/main.py @@ -39,6 +39,7 @@ get_config, get_loglevel, update_pools_from_events, + process_new_events, write_pool_data_to_disk, init_bot, get_cached_events, @@ -528,27 +529,11 @@ def run(mgr, args, tenderly_uri=None) -> None: if args.pool_finder_period > 0 and (loop_idx - 1) % args.pool_finder_period == 0: mgr.cfg.logger.info(f"Searching for unsupported Carbon pairs.") uni_v2, uni_v3, solidly_v2 = pool_finder.get_pools_for_unsupported_pairs(mgr.pool_data, arb_mode=args.arb_mode) - mgr.cfg.logger.info(f"Number of pools added: {len(uni_v2) + len(uni_v3) + len(solidly_v2)}") - - event_mappings = { - 'uniswap_v2': uni_v2, - 'uniswap_v3': uni_v3, - 'solidly_v2': solidly_v2, - } - for exchange_name, event_mapping_dict in event_mappings.items(): - # Update the manager's event mappings - getattr(mgr, f'{exchange_name}_event_mappings').update(event_mapping_dict) - - # Update the local event_mappings csvs - df = pd.DataFrame.from_dict(getattr(mgr, f'{exchange_name}_event_mappings'), orient='index').reset_index() - if len(df)>0: - df.columns = ['address', 'exchange'] - # if the csvs are always sorted then the diffs will be readable - df.sort_values(by=['exchange','address'], inplace=True) - df.to_csv(f"fastlane_bot/data/blockchain_data/{args.blockchain}/{exchange_name}_event_mappings.csv", index=False) - - # Update the static_pools data for later event filtering + process_new_events(uni_v2, mgr.uniswap_v2_event_mappings, f"fastlane_bot/data/blockchain_data/{args.blockchain}/uniswap_v2_event_mappings.csv") + process_new_events(uni_v3, mgr.uniswap_v3_event_mappings, f"fastlane_bot/data/blockchain_data/{args.blockchain}/uniswap_v3_event_mappings.csv") + process_new_events(solidly_v2, mgr.solidly_v2_event_mappings, f"fastlane_bot/data/blockchain_data/{args.blockchain}/solidly_v2_event_mappings.csv") handle_static_pools_update(mgr) + mgr.cfg.logger.info(f"Number of pools added: {len(uni_v2) + len(uni_v3) + len(solidly_v2)}") last_block_queried = current_block From b1538c14c6b431a059ff98b4d33ce61d701ade1c Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Fri, 17 May 2024 20:25:35 +0800 Subject: [PATCH 117/131] feat: collect bancor_pol events from block 0 --- fastlane_bot/events/event_gatherer.py | 9 ++++++++- fastlane_bot/events/exchanges/bancor_pol.py | 4 ++-- fastlane_bot/events/interfaces/subscription.py | 7 ++++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/fastlane_bot/events/event_gatherer.py b/fastlane_bot/events/event_gatherer.py index 5f70913b2..1659f5807 100644 --- a/fastlane_bot/events/event_gatherer.py +++ b/fastlane_bot/events/event_gatherer.py @@ -42,7 +42,14 @@ def __init__( self._subscriptions.append(sub) def get_all_events(self, from_block: int, to_block: int): - results = asyncio.get_event_loop().run_until_complete(asyncio.gather(*[self._get_events_for_topic(from_block, to_block, sub) for sub in self._subscriptions])) + coroutines = [] + for sub in self._subscriptions: + if sub.collect_all: + from_block_ = 0 + else: + from_block_ = from_block + coroutines.append(self._get_events_for_topic(from_block_, to_block, sub)) + results = asyncio.get_event_loop().run_until_complete(asyncio.gather(*coroutines)) return list(chain.from_iterable(results)) async def _get_events_for_topic(self, from_block: int, to_block: int, subscription: Subscription): diff --git a/fastlane_bot/events/exchanges/bancor_pol.py b/fastlane_bot/events/exchanges/bancor_pol.py index 23176a714..25ba9be5f 100644 --- a/fastlane_bot/events/exchanges/bancor_pol.py +++ b/fastlane_bot/events/exchanges/bancor_pol.py @@ -50,8 +50,8 @@ def get_events(self, contract: Contract) -> List[Type[Contract]]: def get_subscriptions(self, contract: Contract) -> List[Subscription]: return [ - Subscription(contract.events.TokenTraded), - Subscription(contract.events.TradingEnabled, "0xae3f48c001771f8e9868e24d47b9e4295b06b1d78072acf96f167074aa3fab64"), + Subscription(contract.events.TokenTraded, collect_all=True), + Subscription(contract.events.TradingEnabled, "0xae3f48c001771f8e9868e24d47b9e4295b06b1d78072acf96f167074aa3fab64", collect_all=True), ] async def get_fee(self, address: str, contract: Contract) -> Tuple[str, float]: diff --git a/fastlane_bot/events/interfaces/subscription.py b/fastlane_bot/events/interfaces/subscription.py index b1165f757..7a178fe20 100644 --- a/fastlane_bot/events/interfaces/subscription.py +++ b/fastlane_bot/events/interfaces/subscription.py @@ -14,9 +14,10 @@ def _get_event_topic(event): class Subscription: - def __init__(self, event: ContractEvent, topic: Optional[str] = None): + def __init__(self, event: ContractEvent, topic: Optional[str] = None, collect_all: bool = False): self._event = event self._topic = _get_event_topic(event) if topic is None else topic + self._collect_all = collect_all self._subscription_id = None self._latest_event_index = (-1, -1) # (block_number, block_index) @@ -30,6 +31,10 @@ def subscription_id(self): @property def topic(self): return self._topic + + @property + def collect_all(self): + return self._collect_all def parse_log(self, log) -> Event: try: From a614db83443ebaebd770fed7ab6a923fc584b907 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Mon, 20 May 2024 19:23:11 +0800 Subject: [PATCH 118/131] feat: get logs batching --- fastlane_bot/config/constants.py | 13 +++++++ fastlane_bot/events/event_gatherer.py | 51 ++++++++++++++++++++++----- main.py | 7 +++- 3 files changed, 61 insertions(+), 10 deletions(-) diff --git a/fastlane_bot/config/constants.py b/fastlane_bot/config/constants.py index ad6641ac0..ad855d546 100644 --- a/fastlane_bot/config/constants.py +++ b/fastlane_bot/config/constants.py @@ -34,3 +34,16 @@ SECTA_V3_NAME = "secta_v3" METAVAULT_V3_NAME = "metavault_v3" ZERO_ADDRESS = "0x0000000000000000000000000000000000000000" + +BLOCK_CHUNK_SIZE_MAP = { + "ethereum": 0, + "polygon": 0, + "polygon_zkevm": 0, + "arbitrum_one": 0, + "optimism": 0, + "coinbase_base": 0, + "fantom": 5000, + "mantle": 0, + "linea": 0, + "sei": 0, +} diff --git a/fastlane_bot/events/event_gatherer.py b/fastlane_bot/events/event_gatherer.py index 1659f5807..382343ee2 100644 --- a/fastlane_bot/events/event_gatherer.py +++ b/fastlane_bot/events/event_gatherer.py @@ -1,5 +1,5 @@ from itertools import chain -from typing import Dict +from typing import Dict, List import asyncio import nest_asyncio @@ -7,6 +7,7 @@ from web3 import AsyncWeb3 from web3.contract import Contract +from fastlane_bot.config.constants import BLOCK_CHUNK_SIZE_MAP from .interfaces.subscription import Subscription from .exchanges.base import Exchange @@ -21,6 +22,7 @@ class EventGatherer: def __init__( self, + blockchain: str, w3: AsyncWeb3, exchanges: Dict[str, Exchange], event_contracts: Dict[str, Contract], @@ -30,6 +32,7 @@ def __init__( manager: The Manager object w3: The connected AsyncWeb3 object. """ + self._blockchain = blockchain self._w3 = w3 self._subscriptions = [] unique_topics = set() @@ -48,16 +51,46 @@ def get_all_events(self, from_block: int, to_block: int): from_block_ = 0 else: from_block_ = from_block - coroutines.append(self._get_events_for_topic(from_block_, to_block, sub)) + coroutines.append(self._get_events_for_subscription(from_block_, to_block, sub)) results = asyncio.get_event_loop().run_until_complete(asyncio.gather(*coroutines)) return list(chain.from_iterable(results)) - async def _get_events_for_topic(self, from_block: int, to_block: int, subscription: Subscription): - events = await self._w3.eth.get_logs(filter_params={ - "fromBlock": from_block, - "toBlock": to_block, - "topics": [subscription.topic] - }) - return [subscription.parse_log(event) for event in events] + async def _get_events_for_subscription(self, from_block: int, to_block: int, subscription: Subscription): + return [subscription.parse_log(log) for log in await self._get_logs_for_topics(from_block, to_block, [subscription.topic])] + async def _get_logs_for_topics(self, from_block: int, to_block: int, topics: List[str]): + chunk_size = BLOCK_CHUNK_SIZE_MAP[self._blockchain] + if chunk_size > 0: + return await self._get_logs_iterative(from_block, to_block, topics, chunk_size) + else: + return await self._get_logs_recursive(from_block, to_block, topics) + async def _get_logs_iterative(self, from_block: int, to_block: int, topics: List[str], chunk_size: int) -> list: + block_numbers = list(range(from_block, to_block + 1, chunk_size)) + [to_block + 1] + log_lists = await asyncio.gather([ + self._w3.eth.get_logs(filter_params={ + "fromBlock": r[0], + "toBlock": r[1], + "topics": topics + }) + for r in zip(block_numbers, map(lambda n: n - 1, block_numbers[1:])) + ]) + return [log for log_list in log_lists for log in log_list] + + async def _get_logs_recursive(self, from_block: int, to_block: int, topics: List[str]) -> list: + if from_block <= to_block: + try: + return await self._w3.eth.get_logs(filter_params={ + "fromBlock": from_block, + "toBlock": to_block, + "topics": topics + }) + except Exception as e: + assert "eth_getLogs" in str(e), str(e) + mid_block = (from_block + to_block) // 2 + log_lists = await asyncio.gather( + self._get_logs_recursive(from_block, mid_block, topics), + self._get_logs_recursive(mid_block + 1, to_block, topics) + ) + return [log for log_list in log_lists for log in log_list] + return [] diff --git a/main.py b/main.py index fcc722efe..37a8d7490 100644 --- a/main.py +++ b/main.py @@ -306,7 +306,12 @@ def run(mgr, args, tenderly_uri=None) -> None: mainnet_uri = mgr.cfg.w3.provider.endpoint_uri handle_static_pools_update(mgr) - event_gatherer = EventGatherer(w3=mgr.w3_async, exchanges=mgr.exchanges, event_contracts=mgr.event_contracts) + event_gatherer = EventGatherer( + blockchain=args.blockchain, + w3=mgr.w3_async, + exchanges=mgr.exchanges, + event_contracts=mgr.event_contracts + ) pool_finder = PoolFinder( carbon_forks=mgr.cfg.network.CARBON_V1_FORKS, From 504ae10e5cb4529f9164619b8fa807a867766de6 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Tue, 21 May 2024 16:33:54 +0800 Subject: [PATCH 119/131] fix: infinite recursion when fetching logs --- fastlane_bot/events/event_gatherer.py | 13 +++++++------ run_blockchain_terraformer.py | 9 +++++---- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/fastlane_bot/events/event_gatherer.py b/fastlane_bot/events/event_gatherer.py index 382343ee2..e2016ffa0 100644 --- a/fastlane_bot/events/event_gatherer.py +++ b/fastlane_bot/events/event_gatherer.py @@ -87,10 +87,11 @@ async def _get_logs_recursive(self, from_block: int, to_block: int, topics: List }) except Exception as e: assert "eth_getLogs" in str(e), str(e) - mid_block = (from_block + to_block) // 2 - log_lists = await asyncio.gather( - self._get_logs_recursive(from_block, mid_block, topics), - self._get_logs_recursive(mid_block + 1, to_block, topics) - ) - return [log for log_list in log_lists for log in log_list] + if from_block < to_block: + mid_block = (from_block + to_block) // 2 + log_lists = await asyncio.gather( + self._get_logs_recursive(from_block, mid_block, topics), + self._get_logs_recursive(mid_block + 1, to_block, topics) + ) + return [log for log_list in log_lists for log in log_list] return [] diff --git a/run_blockchain_terraformer.py b/run_blockchain_terraformer.py index 854119d40..350affee0 100644 --- a/run_blockchain_terraformer.py +++ b/run_blockchain_terraformer.py @@ -680,10 +680,11 @@ def get_events_recursive(get_logs: any, start_block: int, end_block: int) -> lis return get_logs(fromBlock=start_block, toBlock=end_block) except Exception as e: assert "eth_getLogs" in str(e), str(e) - mid_block = (start_block + end_block) // 2 - event_list_1 = get_events_recursive(get_logs, start_block, mid_block) - event_list_2 = get_events_recursive(get_logs, mid_block + 1, end_block) - return event_list_1 + event_list_2 + if start_block < end_block: + mid_block = (start_block + end_block) // 2 + event_list_1 = get_events_recursive(get_logs, start_block, mid_block) + event_list_2 = get_events_recursive(get_logs, mid_block + 1, end_block) + return event_list_1 + event_list_2 return [] From bf3fca821670b26d64fe4de09eac43b2be298aab Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Tue, 21 May 2024 17:53:36 +0800 Subject: [PATCH 120/131] fix: print exception when failed to collect logs from blocks --- fastlane_bot/events/event_gatherer.py | 5 ++++- run_blockchain_terraformer.py | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/fastlane_bot/events/event_gatherer.py b/fastlane_bot/events/event_gatherer.py index e2016ffa0..9c7b67a33 100644 --- a/fastlane_bot/events/event_gatherer.py +++ b/fastlane_bot/events/event_gatherer.py @@ -1,7 +1,8 @@ +import asyncio +import traceback from itertools import chain from typing import Dict, List -import asyncio import nest_asyncio from web3 import AsyncWeb3 @@ -94,4 +95,6 @@ async def _get_logs_recursive(self, from_block: int, to_block: int, topics: List self._get_logs_recursive(mid_block + 1, to_block, topics) ) return [log for log_list in log_lists for log in log_list] + else: + traceback.print_exc(e) return [] diff --git a/run_blockchain_terraformer.py b/run_blockchain_terraformer.py index 350affee0..259c93532 100644 --- a/run_blockchain_terraformer.py +++ b/run_blockchain_terraformer.py @@ -1,4 +1,5 @@ import math +import traceback from typing import Tuple, List, Dict import pandas as pd @@ -685,6 +686,8 @@ def get_events_recursive(get_logs: any, start_block: int, end_block: int) -> lis event_list_1 = get_events_recursive(get_logs, start_block, mid_block) event_list_2 = get_events_recursive(get_logs, mid_block + 1, end_block) return event_list_1 + event_list_2 + else: + traceback.print_exc(e) return [] From 0a1d33e352dfe020f9ac4d07bd2c3b599db59e4d Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Tue, 21 May 2024 18:26:36 +0800 Subject: [PATCH 121/131] fix: error handling --- fastlane_bot/events/event_gatherer.py | 5 ++--- run_blockchain_terraformer.py | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/fastlane_bot/events/event_gatherer.py b/fastlane_bot/events/event_gatherer.py index 9c7b67a33..30b7bf7f3 100644 --- a/fastlane_bot/events/event_gatherer.py +++ b/fastlane_bot/events/event_gatherer.py @@ -1,5 +1,4 @@ import asyncio -import traceback from itertools import chain from typing import Dict, List @@ -96,5 +95,5 @@ async def _get_logs_recursive(self, from_block: int, to_block: int, topics: List ) return [log for log_list in log_lists for log in log_list] else: - traceback.print_exc(e) - return [] + raise e + raise Exception(f"Illegal log query range: {from_block} -> {to_block}") diff --git a/run_blockchain_terraformer.py b/run_blockchain_terraformer.py index 259c93532..df514dbee 100644 --- a/run_blockchain_terraformer.py +++ b/run_blockchain_terraformer.py @@ -1,5 +1,4 @@ import math -import traceback from typing import Tuple, List, Dict import pandas as pd @@ -687,8 +686,8 @@ def get_events_recursive(get_logs: any, start_block: int, end_block: int) -> lis event_list_2 = get_events_recursive(get_logs, mid_block + 1, end_block) return event_list_1 + event_list_2 else: - traceback.print_exc(e) - return [] + raise e + raise Exception(f"Illegal log query range: {start_block} -> {end_block}") def get_uni_v3_pools( From 7444e5e0df3b01372b2bee441f85d8718d77e59d Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Tue, 21 May 2024 20:02:23 +0800 Subject: [PATCH 122/131] fix: take network name from config --- main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.py b/main.py index 37a8d7490..722539278 100644 --- a/main.py +++ b/main.py @@ -307,7 +307,7 @@ def run(mgr, args, tenderly_uri=None) -> None: handle_static_pools_update(mgr) event_gatherer = EventGatherer( - blockchain=args.blockchain, + blockchain=mgr.cfg.network.NETWORK, w3=mgr.w3_async, exchanges=mgr.exchanges, event_contracts=mgr.event_contracts From caf15672435f73d54b3e176bb51ea6178b128b9e Mon Sep 17 00:00:00 2001 From: Doron Zavelevsky Date: Tue, 21 May 2024 16:59:01 +0100 Subject: [PATCH 123/131] removed Sei and multi_triangle_complete - temporarily --- .env.example | 1 - fastlane_bot/bot.py | 1 - fastlane_bot/config/constants.py | 1 - fastlane_bot/config/network.py | 41 +-------- fastlane_bot/config/selectors.py | 1 - .../sei/solidly_v2_event_mappings.csv | 1 - .../blockchain_data/sei/static_pool_data.csv | 4 - .../data/blockchain_data/sei/tokens.csv | 9 -- .../sei/uniswap_v2_event_mappings.csv | 5 -- .../sei/uniswap_v3_event_mappings.csv | 1 - fastlane_bot/data/multichain_addresses.csv | 4 - fastlane_bot/modes/triangle_multi_complete.py | 83 ------------------- main.py | 5 +- run_blockchain_terraformer.py | 10 +-- 14 files changed, 4 insertions(+), 163 deletions(-) delete mode 100644 fastlane_bot/data/blockchain_data/sei/solidly_v2_event_mappings.csv delete mode 100644 fastlane_bot/data/blockchain_data/sei/static_pool_data.csv delete mode 100644 fastlane_bot/data/blockchain_data/sei/tokens.csv delete mode 100644 fastlane_bot/data/blockchain_data/sei/uniswap_v2_event_mappings.csv delete mode 100644 fastlane_bot/data/blockchain_data/sei/uniswap_v3_event_mappings.csv delete mode 100644 fastlane_bot/modes/triangle_multi_complete.py diff --git a/.env.example b/.env.example index 5cb8f2b48..5f1f4a5ae 100644 --- a/.env.example +++ b/.env.example @@ -3,7 +3,6 @@ export ETH_PRIVATE_KEY_BE_CAREFUL="0x123-USE-YOUR-OWN-PRIVATE-KEY-HERE" export WEB3_FANTOM="FANTOM-API-KEY-HERE" // "public" can be used in place of a paid API key export WEB3_MANTLE="MANTLE-API-KEY-HERE" export WEB3_LINEA="LINEA-API-KEY-HERE" // -export WEB3_SEI="SEI-API-KEY-HERE" // #******** For Development - not required to run bot ********# export ETHERSCAN_TOKEN="ONLY_REQUIRED_IN_DEV" diff --git a/fastlane_bot/bot.py b/fastlane_bot/bot.py index 31090b8c5..34fb56ba9 100644 --- a/fastlane_bot/bot.py +++ b/fastlane_bot/bot.py @@ -110,7 +110,6 @@ class CarbonBot: "b3_two_hop": ArbitrageFinderTriangleBancor3TwoHop, "multi_pairwise_pol": FindArbitrageMultiPairwisePol, "multi_pairwise_all": FindArbitrageMultiPairwiseAll, - "multi_triangle_complete": ArbitrageFinderTriangleMultiComplete, } class NoArbAvailable(Exception): diff --git a/fastlane_bot/config/constants.py b/fastlane_bot/config/constants.py index ad855d546..787129492 100644 --- a/fastlane_bot/config/constants.py +++ b/fastlane_bot/config/constants.py @@ -45,5 +45,4 @@ "fantom": 5000, "mantle": 0, "linea": 0, - "sei": 0, } diff --git a/fastlane_bot/config/network.py b/fastlane_bot/config/network.py index e144ffdac..90ddc59cc 100644 --- a/fastlane_bot/config/network.py +++ b/fastlane_bot/config/network.py @@ -276,7 +276,6 @@ class ConfigNetwork(ConfigBase): NETWORK_FANTOM = S.NETWORK_FANTOM NETWORK_MANTLE = S.NETWORK_MANTLE NETWORK_LINEA = S.NETWORK_LINEA - NETWORK_SEI = S.NETWORK_SEI # FLAGS ####################################################################################### @@ -317,9 +316,7 @@ def new(cls, network=None): elif network == cls.NETWORK_MANTLE: return _ConfigNetworkMantle(_direct=False) elif network == cls.NETWORK_LINEA: - return _ConfigNetworkLinea(_direct=False) - elif network == cls.NETWORK_SEI: - return _ConfigNetworkSei(_direct=False) + return _ConfigNetworkLinea(_direct=False) elif network == cls.NETWORK_TENDERLY: return _ConfigNetworkTenderly(_direct=False) else: @@ -785,42 +782,6 @@ class _ConfigNetworkLinea(ConfigNetwork): # Add any exchanges unique to the chain here CHAIN_SPECIFIC_EXCHANGES = [] -class _ConfigNetworkSei(ConfigNetwork): - """ - Fastlane bot config -- network [Base Mainnet] - """ - - NETWORK = S.NETWORK_SEI - NETWORK_ID = "1" # TODO - NETWORK_NAME = "sei" - DEFAULT_PROVIDER = S.PROVIDER_ALCHEMY - RPC_ENDPOINT = "https://evm-rpc.arctic-1.seinetwork.io/" # TODO currently Sei devnet - WEB3_ALCHEMY_PROJECT_ID = os.environ.get("WEB3_SEI") - - network_df = get_multichain_addresses(network=NETWORK_NAME) - FASTLANE_CONTRACT_ADDRESS = "0xC7Dd38e64822108446872c5C2105308058c5C55C" #TODO - UPDATE WITH Mainnet - MULTICALL_CONTRACT_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11" - - CARBON_CONTROLLER_ADDRESS = "0x59f21012B2E9BA67ce6a7605E74F945D0D4C84EA" #TODO - UPDATE WITH Mainnet - CARBON_CONTROLLER_VOUCHER = "0xe4816658ad10bF215053C533cceAe3f59e1f1087" #TODO - UPDATE WITH Mainnet - - NATIVE_GAS_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" - WRAPPED_GAS_TOKEN_ADDRESS = "0x57eE725BEeB991c70c53f9642f36755EC6eb2139" # TODO confirm for Mainnet - NATIVE_GAS_TOKEN_SYMBOL = "SEI" - WRAPPED_GAS_TOKEN_SYMBOL = "WSEI" - STABLECOIN_ADDRESS = "0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C" #TODO USDC on devnet - - IS_INJECT_POA_MIDDLEWARE = False - # Balancer - BALANCER_VAULT_ADDRESS = "0x7ccBebeb88696f9c8b061f1112Bb970158e29cA5" # # TODO Jellyswap on devnet - - CHAIN_FLASHLOAN_TOKENS = { - "0x57eE725BEeB991c70c53f9642f36755EC6eb2139": "WSEI", #TODO confirm for Mainnet - "0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C": "USDC", #TODO confirm for Mainnet - } - # Add any exchanges unique to the chain here - CHAIN_SPECIFIC_EXCHANGES = [] - class _ConfigNetworkTenderly(ConfigNetwork): """ Fastlane bot config -- network [Ethereum Tenderly] diff --git a/fastlane_bot/config/selectors.py b/fastlane_bot/config/selectors.py index 791810fea..d910f52be 100644 --- a/fastlane_bot/config/selectors.py +++ b/fastlane_bot/config/selectors.py @@ -18,7 +18,6 @@ NETWORK_CANTO = "canto" NETWORK_FANTOM = "fantom" NETWORK_LINEA = "linea" -NETWORK_SEI = "sei" NETWORK_MANTLE = "mantle" NETWORK_SCROLL = "scroll" NETWORK_BSC = "binance_smart_chain" diff --git a/fastlane_bot/data/blockchain_data/sei/solidly_v2_event_mappings.csv b/fastlane_bot/data/blockchain_data/sei/solidly_v2_event_mappings.csv deleted file mode 100644 index 2785f2805..000000000 --- a/fastlane_bot/data/blockchain_data/sei/solidly_v2_event_mappings.csv +++ /dev/null @@ -1 +0,0 @@ -exchange,address diff --git a/fastlane_bot/data/blockchain_data/sei/static_pool_data.csv b/fastlane_bot/data/blockchain_data/sei/static_pool_data.csv deleted file mode 100644 index 54e89f03e..000000000 --- a/fastlane_bot/data/blockchain_data/sei/static_pool_data.csv +++ /dev/null @@ -1,4 +0,0 @@ -cid,strategy_id,last_updated,last_updated_block,descr,pair_name,exchange_name,fee,fee_float,address,anchor,tkn0_address,tkn1_address,tkn0_decimals,tkn1_decimals,exchange_id,tkn0_symbol,tkn1_symbol,timestamp,tkn0_balance,tkn1_balance,liquidity,sqrt_price_q96,tick,tick_spacing,exchange,pool_type,tkn0_weight,tkn1_weight,tkn2_address,tkn2_decimals,tkn2_symbol,tkn2_balance,tkn2_weight,tkn3_address,tkn3_decimals,tkn3_symbol,tkn3_balance,tkn3_weight,tkn4_address,tkn4_decimals,tkn4_symbol,tkn4_balance,tkn4_weight,tkn5_address,tkn5_decimals,tkn5_symbol,tkn5_balance,tkn5_weight,tkn6_address,tkn6_decimals,tkn6_symbol,tkn6_balance,tkn6_weight,tkn7_address,tkn7_decimals,tkn7_symbol,tkn7_balance,tkn7_weight -0x1422169ab760ea6994358267b7d3783e8e7fa55c6a74b365b3fd3d17cbf4c6f1,0,,2354,dragonswap 0x027D2E627209f1cebA52ADc8A5aFE9318459b44B/0x7b75109369ACb528d9fa989E227812a6589712b9,0x027D2E627209f1cebA52ADc8A5aFE9318459b44B/0x7b75109369ACb528d9fa989E227812a6589712b9,dragonswap,0.003,0.003,0x01A34Dfa104F020FEE739268679338169945D5B1,,0x027D2E627209f1cebA52ADc8A5aFE9318459b44B,0x7b75109369ACb528d9fa989E227812a6589712b9,18,18,3,WSEI,DSWAP,0,0,0,,,,,dragonswap,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -0xbfd9612b2cb8035908dff18c040f64de75999cefd1020b5ce8a2e533c2ecd5dc,0,,2354,dragonswap 0x027D2E627209f1cebA52ADc8A5aFE9318459b44B/0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C,0x027D2E627209f1cebA52ADc8A5aFE9318459b44B/0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C,dragonswap,0.003,0.003,0x85CB6BFd781e1f42f4E79Efb6bf1F1fEfE4E9732,,0x027D2E627209f1cebA52ADc8A5aFE9318459b44B,0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C,18,6,3,WSEI,USDC,0,0,0,,,,,dragonswap,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -0xe3aead757d877a15316e4896d5c5ab7639adbcba1ff76e3434b4e0af90f6225e,0,,2354,dragonswap 0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C/0xF983afa393199D6902a1Dd04f8E93465915ffD8B,0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C/0xF983afa393199D6902a1Dd04f8E93465915ffD8B,dragonswap,0.003,0.003,0x72A788B0A83e18ce1757171321E82c03e4351498,,0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C,0xF983afa393199D6902a1Dd04f8E93465915ffD8B,6,6,3,USDC,USDT,0,0,0,,,,,dragonswap,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, diff --git a/fastlane_bot/data/blockchain_data/sei/tokens.csv b/fastlane_bot/data/blockchain_data/sei/tokens.csv deleted file mode 100644 index e79bf6c3b..000000000 --- a/fastlane_bot/data/blockchain_data/sei/tokens.csv +++ /dev/null @@ -1,9 +0,0 @@ -address,decimals,symbol -0x26841a0A5D958B128209F4ea9a1DD7E61558c330,18,WSEI -0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C,6,USDC -0x027D2E627209f1cebA52ADc8A5aFE9318459b44B,18,WSEI -0x7b75109369ACb528d9fa989E227812a6589712b9,18,DSWAP -0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE,18,SEI -0x9e7A8e558Ce582511f4104465a886b7bEfBC146b,18,JLY -0x57eE725BEeB991c70c53f9642f36755EC6eb2139,18,WSEI -0xF983afa393199D6902a1Dd04f8E93465915ffD8B,6,USDT diff --git a/fastlane_bot/data/blockchain_data/sei/uniswap_v2_event_mappings.csv b/fastlane_bot/data/blockchain_data/sei/uniswap_v2_event_mappings.csv deleted file mode 100644 index c23f7b0da..000000000 --- a/fastlane_bot/data/blockchain_data/sei/uniswap_v2_event_mappings.csv +++ /dev/null @@ -1,5 +0,0 @@ -exchange,address -dragonswap,0x01A34Dfa104F020FEE739268679338169945D5B1 -dragonswap,0x85CB6BFd781e1f42f4E79Efb6bf1F1fEfE4E9732 -dragonswap,0x38BcEBb9A3fbF05B0Ab7ce9b485c9669578409fE -dragonswap,0x72A788B0A83e18ce1757171321E82c03e4351498 diff --git a/fastlane_bot/data/blockchain_data/sei/uniswap_v3_event_mappings.csv b/fastlane_bot/data/blockchain_data/sei/uniswap_v3_event_mappings.csv deleted file mode 100644 index 2785f2805..000000000 --- a/fastlane_bot/data/blockchain_data/sei/uniswap_v3_event_mappings.csv +++ /dev/null @@ -1 +0,0 @@ -exchange,address diff --git a/fastlane_bot/data/multichain_addresses.csv b/fastlane_bot/data/multichain_addresses.csv index 0650447ea..c1ba30702 100644 --- a/fastlane_bot/data/multichain_addresses.csv +++ b/fastlane_bot/data/multichain_addresses.csv @@ -135,7 +135,3 @@ sushiswap_v3,thundercore,uniswap_v3,0xc35DADB65012eC5796536bD9864eD8773aBc74C4,0 pancakeswap_v3,zkevm,uniswap_v3,0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865,0x1b81D678ffb9C0263b24A97847620C99d213eB14,,, pancakeswap_v3,zksync,uniswap_v3,0x1BB72E0CbbEA93c08f535fc7856E0338D7F7a8aB,0xD70C70AD87aa8D45b8D59600342FB3AEe76E3c68,,, xfai_v0,linea,solidly_v2,0xa5136eAd459F0E61C99Cec70fe8F5C24cF3ecA26,0xD538be6e9026C13D130C9e17d509E69C8Bb0eF33,,222864, -carbon_v1,sei,carbon_v1,0x59f21012B2E9BA67ce6a7605E74F945D0D4C84EA,0x59f21012B2E9BA67ce6a7605E74F945D0D4C84EA,,17658678, -dragonswap,sei,uniswap_v2,0x5D370a6189F89603FaB67e9C68383e63F7B6A262,0x2346d3A6fb18Ff3ae590Ea31d9e41E6AB8c9f5EB,0.003,1008775, -jellyswap,sei,balancer,BALANCER_VAULT_ADDRESS,0x7ccBebeb88696f9c8b061f1112Bb970158e29cA5,0,222832, -uniswap_v3,sei,uniswap_v3,0x0000000000000000000000000000000000000000,0x0000000000000000000000000000000000000000,,1, diff --git a/fastlane_bot/modes/triangle_multi_complete.py b/fastlane_bot/modes/triangle_multi_complete.py deleted file mode 100644 index d053ae0fc..000000000 --- a/fastlane_bot/modes/triangle_multi_complete.py +++ /dev/null @@ -1,83 +0,0 @@ -""" -Defines the Triangular arbitrage finder class - -[DOC-TODO-OPTIONAL-longer description in rst format] - ---- -(c) Copyright Bprotocol foundation 2023-24. -All rights reserved. -Licensed under MIT. -""" -from typing import List, Any, Tuple, Union - -from fastlane_bot.modes.base_triangle import ArbitrageFinderTriangleBase -from fastlane_bot.tools.cpc import CPCContainer -from fastlane_bot.tools.optimizer import MargPOptimizer - - -class ArbitrageFinderTriangleMultiComplete(ArbitrageFinderTriangleBase): - """ - Triangular arbitrage finder mode - """ - - arb_mode = "multi_triangle_complete" - - def find_arbitrage(self, candidates: List[Any] = None, ops: Tuple = None, best_profit: float = 0, profit_src: float = 0) -> Union[List, Tuple]: - """ - see base.py - """ - - if candidates is None: - candidates = [] - - combos = self.get_comprehensive_triangles(self.flashloan_tokens, self.CCm) - - for src_token, miniverse in combos: - try: - CC_cc = CPCContainer(miniverse) - O = MargPOptimizer(CC_cc) - pstart = self.build_pstart(CC_cc, CC_cc.tokens(), src_token) - r = O.optimize(src_token, params=dict(pstart=pstart)) - trade_instructions_dic = r.trade_instructions(O.TIF_DICTS) - if trade_instructions_dic is None or len(trade_instructions_dic) < 3: - # Failed to converge - continue - trade_instructions_df = r.trade_instructions(O.TIF_DFAGGR) - trade_instructions = r.trade_instructions() - - except Exception as e: - self.ConfigObj.logger.info(f"[triangle multi] {e}") - continue - profit_src = -r.result - - # Get the cids - cids = [ti["cid"] for ti in trade_instructions_dic] - - # Calculate the profit - profit = self.calculate_profit(src_token, profit_src, self.CCm, cids) - if str(profit) == "nan": - self.ConfigObj.logger.debug("profit is nan, skipping") - continue - - # Handle candidates based on conditions - candidates += self.handle_candidates( - best_profit, - profit, - trade_instructions_df, - trade_instructions_dic, - src_token, - trade_instructions, - ) - - # Find the best operations - best_profit, ops = self.find_best_operations( - best_profit, - ops, - profit, - trade_instructions_df, - trade_instructions_dic, - src_token, - trade_instructions, - ) - - return candidates if self.result == self.AO_CANDIDATES else ops diff --git a/main.py b/main.py index 722539278..d71488178 100644 --- a/main.py +++ b/main.py @@ -591,8 +591,7 @@ def run(mgr, args, tenderly_uri=None) -> None: "multi_triangle", "b3_two_hop", "multi_pairwise_pol", - "multi_pairwise_all", - "multi_triangle_complete" + "multi_pairwise_all" ], ) parser.add_argument( @@ -698,7 +697,7 @@ def run(mgr, args, tenderly_uri=None) -> None: "--blockchain", default="ethereum", help="A blockchain from the list. Blockchains not in this list do not have a deployed Fast Lane contract and are not supported.", - choices=["ethereum", "coinbase_base", "fantom", "mantle", "linea", "sei"], + choices=["ethereum", "coinbase_base", "fantom", "mantle", "linea"], ) parser.add_argument( "--pool_data_update_frequency", diff --git a/run_blockchain_terraformer.py b/run_blockchain_terraformer.py index df514dbee..8435d393b 100644 --- a/run_blockchain_terraformer.py +++ b/run_blockchain_terraformer.py @@ -48,7 +48,6 @@ async def gather(): FANTOM = "fantom" MANTLE = "mantle" LINEA = "linea" -SEI = "sei" coingecko_network_map = { "ethereum": "ethereum", @@ -67,7 +66,6 @@ async def gather(): "cosmos": "cosmos", "kava": "kava", "mantle": "mantle", - "sei": "sei", } BLOCK_CHUNK_SIZE_MAP = { @@ -80,7 +78,6 @@ async def gather(): "fantom": 5000, "mantle": 0, "linea": 0, - "sei": 0, } ALCHEMY_KEY_DICT = { @@ -93,7 +90,6 @@ async def gather(): "fantom": "WEB3_FANTOM", "mantle": "WEB3_MANTLE", "linea": "WEB3_LINEA", - "sei": "WEB3_SEI", } ALCHEMY_RPC_LIST = { @@ -106,7 +102,6 @@ async def gather(): "fantom": "https://fantom.blockpi.network/v1/rpc/", "mantle": "https://rpc.mantle.xyz/", "linea": "https://rpc.linea.build/", - "sei": "https://evm-rpc.arctic-1.seinetwork.io/", # TODO update with mainnet } BALANCER_SUBGRAPH_CHAIN_URL = { @@ -117,9 +112,7 @@ async def gather(): "optimism": "https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-optimism-v2", "coinbase_base": "https://api.studio.thegraph.com/query/24660/balancer-base-v2/version/latest", "avalanche": "https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-avalanche-v2", - "fantom": "https://api.thegraph.com/subgraphs/name/beethovenxfi/beethovenx", - "sei": "https://thegraph.dev.mvpworkshop.co/subgraphs/name/jelly" # TODO verify this for mainnet - + "fantom": "https://api.thegraph.com/subgraphs/name/beethovenxfi/beethovenx" } BANCOR_V2_NAME = "bancor_v2" @@ -1082,4 +1075,3 @@ def terraform_blockchain(network_name: str): #terraform_blockchain(network_name=FANTOM) #terraform_blockchain(network_name=MANTLE) #terraform_blockchain(network_name=LINEA) -#terraform_blockchain(network_name=SEI) From 05b102b949978bc16aa163d2164ce454557daf28 Mon Sep 17 00:00:00 2001 From: Doron Zavelevsky Date: Tue, 21 May 2024 17:02:22 +0100 Subject: [PATCH 124/131] small miss --- fastlane_bot/bot.py | 1 - 1 file changed, 1 deletion(-) diff --git a/fastlane_bot/bot.py b/fastlane_bot/bot.py index 34fb56ba9..5fe5800d5 100644 --- a/fastlane_bot/bot.py +++ b/fastlane_bot/bot.py @@ -74,7 +74,6 @@ from .modes.pairwise_multi_pol import FindArbitrageMultiPairwisePol from .modes.pairwise_single import FindArbitrageSinglePairwise from .modes.triangle_multi import ArbitrageFinderTriangleMulti -from .modes.triangle_multi_complete import ArbitrageFinderTriangleMultiComplete from .modes.triangle_single import ArbitrageFinderTriangleSingle from .modes.triangle_bancor_v3_two_hop import ArbitrageFinderTriangleBancor3TwoHop from .utils import num_format From ce16ee7aec9e2370c0a56c0c9cc33e78be70387b Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Wed, 22 May 2024 12:46:06 +0800 Subject: [PATCH 125/131] fix: get logs iterative --- fastlane_bot/events/event_gatherer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane_bot/events/event_gatherer.py b/fastlane_bot/events/event_gatherer.py index 30b7bf7f3..16061aeb1 100644 --- a/fastlane_bot/events/event_gatherer.py +++ b/fastlane_bot/events/event_gatherer.py @@ -67,7 +67,7 @@ async def _get_logs_for_topics(self, from_block: int, to_block: int, topics: Lis async def _get_logs_iterative(self, from_block: int, to_block: int, topics: List[str], chunk_size: int) -> list: block_numbers = list(range(from_block, to_block + 1, chunk_size)) + [to_block + 1] - log_lists = await asyncio.gather([ + log_lists = await asyncio.gather(*[ self._w3.eth.get_logs(filter_params={ "fromBlock": r[0], "toBlock": r[1], From eef8c6cc9b1835d4e8f4d4b701e363e629cc297b Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Wed, 22 May 2024 15:17:21 +0800 Subject: [PATCH 126/131] fix: do not update event mappings in read_only mode --- fastlane_bot/events/utils.py | 17 +++++++++-------- main.py | 6 +++--- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/fastlane_bot/events/utils.py b/fastlane_bot/events/utils.py index 87e378456..f6b97b1b3 100644 --- a/fastlane_bot/events/utils.py +++ b/fastlane_bot/events/utils.py @@ -793,17 +793,18 @@ def save_events_to_json( mgr.cfg.logger.debug(f"[events.utils.save_events_to_json] Saved events to {path}") -def process_new_events(new_event_mappings, event_mappings, filename): +def process_new_events(new_event_mappings, event_mappings, filename, read_only): # Update the manager's event mappings event_mappings.update(new_event_mappings) - # Update the local event_mappings csvs - df = pd.DataFrame.from_dict(event_mappings, orient='index').reset_index() - if len(df)>0: - df.columns = ['address', 'exchange'] - # if the csvs are always sorted then the diffs will be readable - df.sort_values(by=['exchange','address'], inplace=True) - df.to_csv(filename, index=False) + if not read_only: + # Update the local event_mappings csvs + df = pd.DataFrame.from_dict(event_mappings, orient='index').reset_index() + if len(df)>0: + df.columns = ['address', 'exchange'] + # if the csvs are always sorted then the diffs will be readable + df.sort_values(by=['exchange','address'], inplace=True) + df.to_csv(filename, index=False) def update_pools_from_events(n_jobs: int, mgr: Any, latest_events: List[Event]): diff --git a/main.py b/main.py index 722539278..4c3dffe51 100644 --- a/main.py +++ b/main.py @@ -534,9 +534,9 @@ def run(mgr, args, tenderly_uri=None) -> None: if args.pool_finder_period > 0 and (loop_idx - 1) % args.pool_finder_period == 0: mgr.cfg.logger.info(f"Searching for unsupported Carbon pairs.") uni_v2, uni_v3, solidly_v2 = pool_finder.get_pools_for_unsupported_pairs(mgr.pool_data, arb_mode=args.arb_mode) - process_new_events(uni_v2, mgr.uniswap_v2_event_mappings, f"fastlane_bot/data/blockchain_data/{args.blockchain}/uniswap_v2_event_mappings.csv") - process_new_events(uni_v3, mgr.uniswap_v3_event_mappings, f"fastlane_bot/data/blockchain_data/{args.blockchain}/uniswap_v3_event_mappings.csv") - process_new_events(solidly_v2, mgr.solidly_v2_event_mappings, f"fastlane_bot/data/blockchain_data/{args.blockchain}/solidly_v2_event_mappings.csv") + process_new_events(uni_v2, mgr.uniswap_v2_event_mappings, f"fastlane_bot/data/blockchain_data/{args.blockchain}/uniswap_v2_event_mappings.csv", args.read_only) + process_new_events(uni_v3, mgr.uniswap_v3_event_mappings, f"fastlane_bot/data/blockchain_data/{args.blockchain}/uniswap_v3_event_mappings.csv", args.read_only) + process_new_events(solidly_v2, mgr.solidly_v2_event_mappings, f"fastlane_bot/data/blockchain_data/{args.blockchain}/solidly_v2_event_mappings.csv", args.read_only) handle_static_pools_update(mgr) mgr.cfg.logger.info(f"Number of pools added: {len(uni_v2) + len(uni_v3) + len(solidly_v2)}") From 8733c8bef6390e984e23e33a0de5a6c008c0f559 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Wed, 22 May 2024 17:13:34 +0800 Subject: [PATCH 127/131] fix: handle timeout exception correctly --- fastlane_bot/events/event_gatherer.py | 1 - run_blockchain_terraformer.py | 1 - 2 files changed, 2 deletions(-) diff --git a/fastlane_bot/events/event_gatherer.py b/fastlane_bot/events/event_gatherer.py index 16061aeb1..6694135f5 100644 --- a/fastlane_bot/events/event_gatherer.py +++ b/fastlane_bot/events/event_gatherer.py @@ -86,7 +86,6 @@ async def _get_logs_recursive(self, from_block: int, to_block: int, topics: List "topics": topics }) except Exception as e: - assert "eth_getLogs" in str(e), str(e) if from_block < to_block: mid_block = (from_block + to_block) // 2 log_lists = await asyncio.gather( diff --git a/run_blockchain_terraformer.py b/run_blockchain_terraformer.py index df514dbee..ee35ceb99 100644 --- a/run_blockchain_terraformer.py +++ b/run_blockchain_terraformer.py @@ -679,7 +679,6 @@ def get_events_recursive(get_logs: any, start_block: int, end_block: int) -> lis try: return get_logs(fromBlock=start_block, toBlock=end_block) except Exception as e: - assert "eth_getLogs" in str(e), str(e) if start_block < end_block: mid_block = (start_block + end_block) // 2 event_list_1 = get_events_recursive(get_logs, start_block, mid_block) From ccbda7178fda89b326d4d4abf1a99a3da040b932 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Wed, 22 May 2024 19:46:50 +0800 Subject: [PATCH 128/131] fix: improved error logging . . --- fastlane_bot/events/event_gatherer.py | 10 +++++++--- main.py | 2 +- run_blockchain_terraformer.py | 1 + 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/fastlane_bot/events/event_gatherer.py b/fastlane_bot/events/event_gatherer.py index 6694135f5..fa6b9bb4b 100644 --- a/fastlane_bot/events/event_gatherer.py +++ b/fastlane_bot/events/event_gatherer.py @@ -1,12 +1,14 @@ import asyncio from itertools import chain from typing import Dict, List +from traceback import format_exc import nest_asyncio from web3 import AsyncWeb3 from web3.contract import Contract +from fastlane_bot.config import Config from fastlane_bot.config.constants import BLOCK_CHUNK_SIZE_MAP from .interfaces.subscription import Subscription from .exchanges.base import Exchange @@ -22,7 +24,7 @@ class EventGatherer: def __init__( self, - blockchain: str, + config: Config, w3: AsyncWeb3, exchanges: Dict[str, Exchange], event_contracts: Dict[str, Contract], @@ -32,7 +34,7 @@ def __init__( manager: The Manager object w3: The connected AsyncWeb3 object. """ - self._blockchain = blockchain + self._config = config self._w3 = w3 self._subscriptions = [] unique_topics = set() @@ -59,7 +61,7 @@ async def _get_events_for_subscription(self, from_block: int, to_block: int, sub return [subscription.parse_log(log) for log in await self._get_logs_for_topics(from_block, to_block, [subscription.topic])] async def _get_logs_for_topics(self, from_block: int, to_block: int, topics: List[str]): - chunk_size = BLOCK_CHUNK_SIZE_MAP[self._blockchain] + chunk_size = BLOCK_CHUNK_SIZE_MAP[self._config.network.NETWORK] if chunk_size > 0: return await self._get_logs_iterative(from_block, to_block, topics, chunk_size) else: @@ -86,6 +88,8 @@ async def _get_logs_recursive(self, from_block: int, to_block: int, topics: List "topics": topics }) except Exception as e: + if "eth_getLogs" not in str(e): + self._config.logger.error(f"Unexpected exception in EventGatherer: {format_exc()}") if from_block < to_block: mid_block = (from_block + to_block) // 2 log_lists = await asyncio.gather( diff --git a/main.py b/main.py index 4c3dffe51..dc402b112 100644 --- a/main.py +++ b/main.py @@ -307,7 +307,7 @@ def run(mgr, args, tenderly_uri=None) -> None: handle_static_pools_update(mgr) event_gatherer = EventGatherer( - blockchain=mgr.cfg.network.NETWORK, + config=mgr.cfg, w3=mgr.w3_async, exchanges=mgr.exchanges, event_contracts=mgr.event_contracts diff --git a/run_blockchain_terraformer.py b/run_blockchain_terraformer.py index ee35ceb99..df514dbee 100644 --- a/run_blockchain_terraformer.py +++ b/run_blockchain_terraformer.py @@ -679,6 +679,7 @@ def get_events_recursive(get_logs: any, start_block: int, end_block: int) -> lis try: return get_logs(fromBlock=start_block, toBlock=end_block) except Exception as e: + assert "eth_getLogs" in str(e), str(e) if start_block < end_block: mid_block = (start_block + end_block) // 2 event_list_1 = get_events_recursive(get_logs, start_block, mid_block) From 7469fe957ba526109676267723f905e0785b3206 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Wed, 22 May 2024 22:09:15 +0800 Subject: [PATCH 129/131] chore: log unsupported carbon pools --- fastlane_bot/pool_finder.py | 6 +++++- main.py | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/fastlane_bot/pool_finder.py b/fastlane_bot/pool_finder.py index 15ff0584f..f61b5c660 100644 --- a/fastlane_bot/pool_finder.py +++ b/fastlane_bot/pool_finder.py @@ -10,6 +10,7 @@ from typing import List, Tuple, Dict, Any +from fastlane_bot.config import Config from fastlane_bot.config.constants import ZERO_ADDRESS, UNISWAP_V2_NAME, UNISWAP_V3_NAME, SOLIDLY_V2_NAME from fastlane_bot.config.multicaller import MultiCaller from fastlane_bot.events.exchanges.base import Exchange @@ -51,7 +52,7 @@ def extract_univ3_fee_tiers(self, pools: List[Dict[str, Any]]): self._uni_v3_fee_tiers[pool["exchange_name"]].add(int(pool["fee"])) - def get_pools_for_unsupported_pairs(self, pools: List[Dict[str, Any]], arb_mode: str): + def get_pools_for_unsupported_pairs(self, config: Config, pools: List[Dict[str, Any]], arb_mode: str): """ Main flow for Poolfinder. @@ -73,6 +74,9 @@ def get_pools_for_unsupported_pairs(self, pools: List[Dict[str, Any]], arb_mode: unsupported_pairs = PoolFinder._find_unsupported_triangles(self._flashloan_tokens, carbon_pairs=carbon_pairs, external_pairs=other_pairs) else: unsupported_pairs = PoolFinder._find_unsupported_pairs(self._flashloan_tokens, carbon_pairs=carbon_pairs, external_pairs=other_pairs) + config.logger.info(f"Searching pools to support the following carbon pairs:") + for pair in unsupported_pairs: + config.logger.info(pair) pairs = [(tkn, token) for pair in unsupported_pairs for tkn in pair for token in self._flashloan_tokens] chunk_size = 400 diff --git a/main.py b/main.py index dc402b112..e335f3fa8 100644 --- a/main.py +++ b/main.py @@ -531,9 +531,10 @@ def run(mgr, args, tenderly_uri=None) -> None: mgr.solidly_v2_event_mappings = dict( solidly_v2_event_mappings[["address", "exchange"]].values ) + if args.pool_finder_period > 0 and (loop_idx - 1) % args.pool_finder_period == 0: mgr.cfg.logger.info(f"Searching for unsupported Carbon pairs.") - uni_v2, uni_v3, solidly_v2 = pool_finder.get_pools_for_unsupported_pairs(mgr.pool_data, arb_mode=args.arb_mode) + uni_v2, uni_v3, solidly_v2 = pool_finder.get_pools_for_unsupported_pairs(mgr.cfg, mgr.pool_data, arb_mode=args.arb_mode) process_new_events(uni_v2, mgr.uniswap_v2_event_mappings, f"fastlane_bot/data/blockchain_data/{args.blockchain}/uniswap_v2_event_mappings.csv", args.read_only) process_new_events(uni_v3, mgr.uniswap_v3_event_mappings, f"fastlane_bot/data/blockchain_data/{args.blockchain}/uniswap_v3_event_mappings.csv", args.read_only) process_new_events(solidly_v2, mgr.solidly_v2_event_mappings, f"fastlane_bot/data/blockchain_data/{args.blockchain}/solidly_v2_event_mappings.csv", args.read_only) From 497a8f69078648b7875c48b1fd1f81f0de754433 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Mon, 27 May 2024 19:10:22 +0800 Subject: [PATCH 130/131] fix: get topics from correct event contract abi --- fastlane_bot/events/event_gatherer.py | 9 +++------ fastlane_bot/events/exchanges/balancer.py | 5 +++-- fastlane_bot/events/exchanges/bancor_pol.py | 6 ++++-- fastlane_bot/events/exchanges/bancor_v2.py | 6 ++++-- fastlane_bot/events/exchanges/bancor_v3.py | 6 ++++-- fastlane_bot/events/exchanges/base.py | 8 ++++++-- fastlane_bot/events/exchanges/carbon_v1.py | 6 ++++-- fastlane_bot/events/exchanges/uniswap_v2.py | 6 ++++-- fastlane_bot/events/exchanges/uniswap_v3.py | 6 ++++-- fastlane_bot/tests/test_event_topics.py | 3 +-- main.py | 1 - 11 files changed, 37 insertions(+), 25 deletions(-) diff --git a/fastlane_bot/events/event_gatherer.py b/fastlane_bot/events/event_gatherer.py index fa6b9bb4b..93156cab8 100644 --- a/fastlane_bot/events/event_gatherer.py +++ b/fastlane_bot/events/event_gatherer.py @@ -27,7 +27,6 @@ def __init__( config: Config, w3: AsyncWeb3, exchanges: Dict[str, Exchange], - event_contracts: Dict[str, Contract], ): """ Initializes the EventManager. Args: @@ -37,13 +36,11 @@ def __init__( self._config = config self._w3 = w3 self._subscriptions = [] - unique_topics = set() - for exchange_name, exchange in exchanges.items(): - subscriptions = exchange.get_subscriptions(event_contracts[exchange_name]) + for exchange in exchanges.values(): + subscriptions = exchange.get_subscriptions(w3) for sub in subscriptions: - if sub.topic not in unique_topics: - unique_topics.add(sub.topic) + if sub.topic not in [s.topic for s in self._subscriptions]: self._subscriptions.append(sub) def get_all_events(self, from_block: int, to_block: int): diff --git a/fastlane_bot/events/exchanges/balancer.py b/fastlane_bot/events/exchanges/balancer.py index 384ee5fda..efba312e1 100644 --- a/fastlane_bot/events/exchanges/balancer.py +++ b/fastlane_bot/events/exchanges/balancer.py @@ -12,8 +12,9 @@ Licensed under MIT. """ from dataclasses import dataclass -from typing import List, Type, Tuple, Any +from typing import List, Type, Tuple, Any, Union +from web3 import Web3, AsyncWeb3 from web3.contract import Contract from fastlane_bot.data.abi import BALANCER_VAULT_ABI, BALANCER_POOL_ABI_V1 @@ -48,7 +49,7 @@ def get_pool_abi(self): def get_events(self, contract: Contract) -> List[Type[Contract]]: return [contract.events.AuthorizerChanged] - def get_subscriptions(self, contract: Contract) -> List[Subscription]: + def get_subscriptions(self, w3: Union[Web3, AsyncWeb3]) -> List[Subscription]: return [] async def get_fee(self, pool_id: str, contract: Contract) -> Tuple[str, float]: diff --git a/fastlane_bot/events/exchanges/bancor_pol.py b/fastlane_bot/events/exchanges/bancor_pol.py index 25ba9be5f..2c63dda6d 100644 --- a/fastlane_bot/events/exchanges/bancor_pol.py +++ b/fastlane_bot/events/exchanges/bancor_pol.py @@ -12,8 +12,9 @@ Licensed under MIT. """ from dataclasses import dataclass -from typing import List, Type, Tuple, Any, Dict, Callable +from typing import List, Type, Tuple, Any, Dict, Callable, Union +from web3 import Web3, AsyncWeb3 from web3.contract import Contract from fastlane_bot.data.abi import BANCOR_POL_ABI @@ -48,7 +49,8 @@ def factory_abi(self): def get_events(self, contract: Contract) -> List[Type[Contract]]: return [contract.events.TokenTraded, contract.events.TradingEnabled] - def get_subscriptions(self, contract: Contract) -> List[Subscription]: + def get_subscriptions(self, w3: Union[Web3, AsyncWeb3]) -> List[Subscription]: + contract = self.get_event_contract(w3) return [ Subscription(contract.events.TokenTraded, collect_all=True), Subscription(contract.events.TradingEnabled, "0xae3f48c001771f8e9868e24d47b9e4295b06b1d78072acf96f167074aa3fab64", collect_all=True), diff --git a/fastlane_bot/events/exchanges/bancor_v2.py b/fastlane_bot/events/exchanges/bancor_v2.py index a4ab5db4a..efa54f433 100644 --- a/fastlane_bot/events/exchanges/bancor_v2.py +++ b/fastlane_bot/events/exchanges/bancor_v2.py @@ -12,8 +12,9 @@ Licensed under MIT. """ from dataclasses import dataclass -from typing import List, Type, Tuple +from typing import List, Type, Tuple, Union +from web3 import Web3, AsyncWeb3 from web3.contract import Contract, AsyncContract from fastlane_bot.data.abi import BANCOR_V2_CONVERTER_ABI @@ -46,7 +47,8 @@ def factory_abi(self): def get_events(self, contract: Contract) -> List[Type[Contract]]: return [contract.events.TokenRateUpdate] - def get_subscriptions(self, contract: Contract) -> List[Subscription]: + def get_subscriptions(self, w3: Union[Web3, AsyncWeb3]) -> List[Subscription]: + contract = self.get_event_contract(w3) return [Subscription(contract.events.TokenRateUpdate)] # def async convert_address(self, address: str, contract: Contract) -> str: diff --git a/fastlane_bot/events/exchanges/bancor_v3.py b/fastlane_bot/events/exchanges/bancor_v3.py index b9ea312b7..ed5ba0720 100644 --- a/fastlane_bot/events/exchanges/bancor_v3.py +++ b/fastlane_bot/events/exchanges/bancor_v3.py @@ -12,8 +12,9 @@ Licensed under MIT. """ from dataclasses import dataclass -from typing import List, Type, Tuple +from typing import List, Type, Tuple, Union +from web3 import Web3, AsyncWeb3 from web3.contract import Contract from fastlane_bot.data.abi import BANCOR_V3_POOL_COLLECTION_ABI @@ -50,7 +51,8 @@ def factory_abi(self): def get_events(self, contract: Contract) -> List[Type[Contract]]: return [contract.events.TradingLiquidityUpdated] - def get_subscriptions(self, contract: Contract) -> List[Subscription]: + def get_subscriptions(self, w3: Union[Web3, AsyncWeb3]) -> List[Subscription]: + contract = self.get_event_contract(w3) return [ Subscription(contract.events.TradingLiquidityUpdated, TRADING_LIQUIDITY_UPDATED_TOPIC), # Subscription(contract.events.TotalLiquidityUpdated, TOTAL_LIQUIDITY_UPDATED_TOPIC), # Unused diff --git a/fastlane_bot/events/exchanges/base.py b/fastlane_bot/events/exchanges/base.py index 8ff438a1b..62bfe7996 100644 --- a/fastlane_bot/events/exchanges/base.py +++ b/fastlane_bot/events/exchanges/base.py @@ -12,8 +12,9 @@ """ from abc import ABC, abstractmethod from dataclasses import dataclass, field -from typing import Dict, List, Type, Any +from typing import Dict, List, Type, Any, Union +from web3 import Web3, AsyncWeb3 from web3.contract import Contract, AsyncContract from fastlane_bot.config.constants import CARBON_V1_NAME @@ -51,6 +52,9 @@ def get_pools(self) -> List[Pool]: """ return list(self.pools.values()) + def get_event_contract(self, w3: Union[Web3, AsyncWeb3]) -> Union[Contract, AsyncContract]: + return w3.eth.contract(abi=self.get_abi()) + @abstractmethod def add_pool(self, pool: Pool): """ @@ -99,7 +103,7 @@ def get_events(self, contract: Contract) -> List[Type[Contract]]: pass @abstractmethod - def get_subscriptions(self, contract: Contract) -> List[Subscription]: + def get_subscriptions(self, w3: Union[Web3, AsyncWeb3]) -> List[Subscription]: ... @staticmethod diff --git a/fastlane_bot/events/exchanges/carbon_v1.py b/fastlane_bot/events/exchanges/carbon_v1.py index fa4a40107..125dadb26 100644 --- a/fastlane_bot/events/exchanges/carbon_v1.py +++ b/fastlane_bot/events/exchanges/carbon_v1.py @@ -12,9 +12,10 @@ Licensed under MIT. """ from dataclasses import dataclass -from typing import List, Type, Tuple, Any, Dict, Callable +from typing import List, Type, Tuple, Any, Dict, Callable, Union from fastlane_bot import Config +from web3 import Web3, AsyncWeb3 from web3.contract import Contract from fastlane_bot.data.abi import CARBON_CONTROLLER_ABI @@ -80,7 +81,8 @@ def get_events(self, contract: Contract) -> List[Type[Contract]]: contract.events.PairCreated, ] if self.exchange_initialized else [] - def get_subscriptions(self, contract: Contract) -> List[Subscription]: + def get_subscriptions(self, w3: Union[Web3, AsyncWeb3]) -> List[Subscription]: + contract = self.get_event_contract(w3) return [ Subscription(contract.events.StrategyCreated, STRATEGY_CREATED_TOPIC), Subscription(contract.events.StrategyUpdated, STRATEGY_UPDATED_TOPIC), diff --git a/fastlane_bot/events/exchanges/uniswap_v2.py b/fastlane_bot/events/exchanges/uniswap_v2.py index ce1e209cc..3fb5b902d 100644 --- a/fastlane_bot/events/exchanges/uniswap_v2.py +++ b/fastlane_bot/events/exchanges/uniswap_v2.py @@ -12,8 +12,9 @@ Licensed under MIT. """ from dataclasses import dataclass -from typing import List, Type, Tuple, Any +from typing import List, Type, Tuple, Any, Union +from web3 import Web3, AsyncWeb3 from web3.contract import Contract, AsyncContract from fastlane_bot.data.abi import UNISWAP_V2_POOL_ABI, UNISWAP_V2_FACTORY_ABI @@ -49,7 +50,8 @@ def get_abi(self): def get_events(self, contract: Contract) -> List[Type[Contract]]: return [contract.events.Sync] if self.exchange_initialized else [] - def get_subscriptions(self, contract: Contract) -> List[Subscription]: + def get_subscriptions(self, w3: Union[Web3, AsyncWeb3]) -> List[Subscription]: + contract = self.get_event_contract(w3) return [Subscription(contract.events.Sync)] async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, float]: diff --git a/fastlane_bot/events/exchanges/uniswap_v3.py b/fastlane_bot/events/exchanges/uniswap_v3.py index 76d8a93d5..6a478faf6 100644 --- a/fastlane_bot/events/exchanges/uniswap_v3.py +++ b/fastlane_bot/events/exchanges/uniswap_v3.py @@ -12,8 +12,9 @@ Licensed under MIT. """ from dataclasses import dataclass -from typing import List, Type, Tuple, Any +from typing import List, Type, Tuple, Any, Union +from web3 import Web3, AsyncWeb3 from web3.contract import Contract from fastlane_bot.config.constants import AGNI_V3_NAME, PANCAKESWAP_V3_NAME, FUSIONX_V3_NAME, ECHODEX_V3_NAME, SECTA_V3_NAME @@ -46,7 +47,8 @@ def factory_abi(self): def get_events(self, contract: Contract) -> List[Type[Contract]]: return [contract.events.Swap] if self.exchange_initialized else [] - def get_subscriptions(self, contract: Contract) -> List[Subscription]: + def get_subscriptions(self, w3: Union[Web3, AsyncWeb3]) -> List[Subscription]: + contract = self.get_event_contract(w3) return [Subscription(contract.events.Swap)] async def get_fee(self, address: str, contract: Contract) -> Tuple[str, float]: diff --git a/fastlane_bot/tests/test_event_topics.py b/fastlane_bot/tests/test_event_topics.py index 67e456f71..506f9b280 100644 --- a/fastlane_bot/tests/test_event_topics.py +++ b/fastlane_bot/tests/test_event_topics.py @@ -46,7 +46,6 @@ ]) def test_event_topic(config, cls, exchange_name, event_topics): exchange = cls(exchange_name=exchange_name) - contract = config.w3.eth.contract(abi=exchange.get_abi()) - for subscription in exchange.get_subscriptions(contract): + for subscription in exchange.get_subscriptions(config.w3): assert event_topics.pop(subscription._event.event_name) == subscription.topic assert event_topics == {} diff --git a/main.py b/main.py index 15f4b3d05..36633d9d9 100644 --- a/main.py +++ b/main.py @@ -310,7 +310,6 @@ def run(mgr, args, tenderly_uri=None) -> None: config=mgr.cfg, w3=mgr.w3_async, exchanges=mgr.exchanges, - event_contracts=mgr.event_contracts ) pool_finder = PoolFinder( From 385f3d3ff648afa533f3696c644c1b320853e632 Mon Sep 17 00:00:00 2001 From: Platon Floria Date: Mon, 27 May 2024 19:17:43 +0800 Subject: [PATCH 131/131] fix: solidly subscriptions --- fastlane_bot/events/exchanges/solidly_v2/base.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fastlane_bot/events/exchanges/solidly_v2/base.py b/fastlane_bot/events/exchanges/solidly_v2/base.py index 7bffef541..693c82197 100644 --- a/fastlane_bot/events/exchanges/solidly_v2/base.py +++ b/fastlane_bot/events/exchanges/solidly_v2/base.py @@ -13,8 +13,9 @@ """ from abc import abstractmethod from dataclasses import dataclass -from typing import List, Type, Any +from typing import List, Type, Any, Union +from web3 import Web3, AsyncWeb3 from web3.contract import Contract, AsyncContract from fastlane_bot.data.abi import SOLIDLY_V2_POOL_ABI @@ -50,7 +51,8 @@ def add_pool(self, pool: Pool): def get_events(self, contract: Contract) -> List[Type[Contract]]: return [contract.events.Sync] if self.exchange_initialized else [] - def get_subscriptions(self, contract: Contract) -> List[Subscription]: + def get_subscriptions(self, w3: Union[Web3, AsyncWeb3]) -> List[Subscription]: + contract = self.get_event_contract(w3) return [Subscription(contract.events.Sync)] def get_abi(self):