From 12ab820b9e2dc5054cac9022dcbcd893744bffa8 Mon Sep 17 00:00:00 2001 From: harisang Date: Sat, 7 Oct 2023 01:07:35 +0300 Subject: [PATCH 01/19] add buffer value test --- src/constants.py | 6 ++ .../buffers_monitoring_test.py | 100 ++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 src/monitoring_tests/buffers_monitoring_test.py diff --git a/src/constants.py b/src/constants.py index 87b8039..c510579 100644 --- a/src/constants.py +++ b/src/constants.py @@ -25,6 +25,12 @@ # cap parameter, per CIP-20, measured in ETH CAP_PARAMETER = 0.01 +# number of tx hashes before a new buffers check is ran +BUFFER_INTERVAL = 150 + +# threshold of value of buffers above which an alert is generated +BUFFER_VALUE_THRESHOLD = 200000 + # threshold parameter to generate an alert when receiving kickbacks KICKBACKS_ALERT_THRESHOLD = 0.03 diff --git a/src/monitoring_tests/buffers_monitoring_test.py b/src/monitoring_tests/buffers_monitoring_test.py new file mode 100644 index 0000000..17e5a60 --- /dev/null +++ b/src/monitoring_tests/buffers_monitoring_test.py @@ -0,0 +1,100 @@ +""" +Checks the value of buffers every 150 settlements by invoking +the ehtplorer api, and in some cases, coingecko. +""" +# pylint: disable=logging-fstring-interpolation +from typing import Any +import requests +from src.monitoring_tests.base_test import BaseTest +from src.constants import ( + BUFFER_INTERVAL, + header, + REQUEST_TIMEOUT, + BUFFER_VALUE_THRESHOLD, +) + + +class BuffersMonitoringTest(BaseTest): + """ + This test compares the surplus all orders from the winning settlement to + the different executions of these orders by other solvers in the competition. + """ + + def __init__(self) -> None: + super().__init__() + self.counter: int = 0 + self.buffers_value = 0 + + def compute_buffers_value(self) -> bool: + """ + Evaluates current state of buffers. + """ + # get all token balances of the smart contract + request_url = "https://api.ethplorer.io/\ + getAddressInfo/\ + 0x9008D19f58AAbD9eD0D60971565AA8510560ab41?\ + apiKey=freekey" + try: + resp = requests.get(request_url, headers=header, timeout=REQUEST_TIMEOUT) + rsp = resp.json() + + value_in_usd = 0.0 + for token in rsp["tokens"]: + balance = token["balance"] + decimals = int(token["tokenInfo"]["decimals"]) + if token["tokenInfo"]["price"] is not False: + price_in_usd = token["tokenInfo"]["price"]["rate"] + token_buffer_value_in_usd = ( + balance / 10**decimals + ) * price_in_usd + # in case some price is way off and it blows a lot the total value held in the + # smart contract we use a second price feed, from coingecko, to correct in case + # the initial price is indeed off + if token_buffer_value_in_usd > 10000: + coingecko_request_url = ( + "https://api.coingecko.com/\ + api/v3/simple/token_price/\ + ethereum?contract_addresses=" + + token["tokenInfo"]["address"] + + "&vs_currencies=usd" + ) + coingecko_resp = requests.get( + coingecko_request_url, + headers=header, + timeout=REQUEST_TIMEOUT, + ) + coingecko_rsp = coingecko_resp.json() + coingecko_price_in_usd = coingecko_rsp[ + token["tokenInfo"]["address"] + ]["usd"] + coingecko_value_in_usd = ( + balance / 10**decimals + ) * coingecko_price_in_usd + if coingecko_value_in_usd < token_buffer_value_in_usd: + token_buffer_value_in_usd = coingecko_value_in_usd + value_in_usd += token_buffer_value_in_usd + self.buffers_value = value_in_usd + log_output = f"Buffer value is {self.buffers_value} USD" + if self.buffers_value > BUFFER_VALUE_THRESHOLD: + self.alert(log_output) + else: + self.info(log_output) + + except requests.RequestException as err: + self.logger.warning( + f"Connection error while fetching buffer tokens and prices, error: {err}" + ) + return False + return True + + def run(self, tx_hash: str) -> bool: + """ + Wrapper function for the whole test. Checks if solver competition data is retrievable + and runs EBBO test, else returns True to add to list of unchecked hashes. + """ + self.counter += 1 + if self.counter > BUFFER_INTERVAL: + success = self.compute_buffers_value() + if success: + self.counter = 0 + return True From 904a1ae9d7475e0f94cbebc596536da8c59f5351 Mon Sep 17 00:00:00 2001 From: harisang Date: Sat, 7 Oct 2023 01:18:14 +0300 Subject: [PATCH 02/19] fixed minor issues --- .../buffers_monitoring_test.py | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/monitoring_tests/buffers_monitoring_test.py b/src/monitoring_tests/buffers_monitoring_test.py index 17e5a60..0340c3d 100644 --- a/src/monitoring_tests/buffers_monitoring_test.py +++ b/src/monitoring_tests/buffers_monitoring_test.py @@ -3,7 +3,6 @@ the ehtplorer api, and in some cases, coingecko. """ # pylint: disable=logging-fstring-interpolation -from typing import Any import requests from src.monitoring_tests.base_test import BaseTest from src.constants import ( @@ -30,12 +29,15 @@ def compute_buffers_value(self) -> bool: Evaluates current state of buffers. """ # get all token balances of the smart contract - request_url = "https://api.ethplorer.io/\ - getAddressInfo/\ - 0x9008D19f58AAbD9eD0D60971565AA8510560ab41?\ - apiKey=freekey" try: - resp = requests.get(request_url, headers=header, timeout=REQUEST_TIMEOUT) + resp = requests.get( + "https://api.ethplorer.io/\ + getAddressInfo/\ + 0x9008D19f58AAbD9eD0D60971565AA8510560ab41?\ + apiKey=freekey", + headers=header, + timeout=REQUEST_TIMEOUT, + ) rsp = resp.json() value_in_usd = 0.0 @@ -51,15 +53,12 @@ def compute_buffers_value(self) -> bool: # smart contract we use a second price feed, from coingecko, to correct in case # the initial price is indeed off if token_buffer_value_in_usd > 10000: - coingecko_request_url = ( + coingecko_resp = requests.get( "https://api.coingecko.com/\ api/v3/simple/token_price/\ ethereum?contract_addresses=" + token["tokenInfo"]["address"] - + "&vs_currencies=usd" - ) - coingecko_resp = requests.get( - coingecko_request_url, + + "&vs_currencies=usd", headers=header, timeout=REQUEST_TIMEOUT, ) @@ -78,7 +77,7 @@ def compute_buffers_value(self) -> bool: if self.buffers_value > BUFFER_VALUE_THRESHOLD: self.alert(log_output) else: - self.info(log_output) + self.logger.info(log_output) except requests.RequestException as err: self.logger.warning( From 44f5dfb1551b67c653a453cc5e637962a94119ea Mon Sep 17 00:00:00 2001 From: harisang Date: Sat, 7 Oct 2023 01:20:54 +0300 Subject: [PATCH 03/19] fixed mypy error --- src/monitoring_tests/buffers_monitoring_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/monitoring_tests/buffers_monitoring_test.py b/src/monitoring_tests/buffers_monitoring_test.py index 0340c3d..95d67c6 100644 --- a/src/monitoring_tests/buffers_monitoring_test.py +++ b/src/monitoring_tests/buffers_monitoring_test.py @@ -22,7 +22,7 @@ class BuffersMonitoringTest(BaseTest): def __init__(self) -> None: super().__init__() self.counter: int = 0 - self.buffers_value = 0 + self.buffers_value: float = 0.0 def compute_buffers_value(self) -> bool: """ From 2f6d261bb0eb3e336b66858fd6ae8b493462b9fd Mon Sep 17 00:00:00 2001 From: harisang Date: Sat, 7 Oct 2023 01:25:17 +0300 Subject: [PATCH 04/19] fixed comments --- src/monitoring_tests/buffers_monitoring_test.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/monitoring_tests/buffers_monitoring_test.py b/src/monitoring_tests/buffers_monitoring_test.py index 95d67c6..1dcb5c3 100644 --- a/src/monitoring_tests/buffers_monitoring_test.py +++ b/src/monitoring_tests/buffers_monitoring_test.py @@ -15,8 +15,9 @@ class BuffersMonitoringTest(BaseTest): """ - This test compares the surplus all orders from the winning settlement to - the different executions of these orders by other solvers in the competition. + This test checks the value of the settlement contract buffers + every 150 settlements and generates an alert if it is higher than 200_000 USD. + Price feeds from ethplorer and coingecko (as backup) are used. """ def __init__(self) -> None: @@ -88,8 +89,8 @@ def compute_buffers_value(self) -> bool: def run(self, tx_hash: str) -> bool: """ - Wrapper function for the whole test. Checks if solver competition data is retrievable - and runs EBBO test, else returns True to add to list of unchecked hashes. + Wrapper function for the whole test. Checks if 150 settlements have been observed, + in which case it invokes the main function that checks the current value of buffers. """ self.counter += 1 if self.counter > BUFFER_INTERVAL: From c79286706e301ef4517adbbea76c82fa2d84741a Mon Sep 17 00:00:00 2001 From: harisang Date: Sat, 7 Oct 2023 01:28:41 +0300 Subject: [PATCH 05/19] adds the test in the main daemon --- src/daemon.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/daemon.py b/src/daemon.py index d40854f..9b956e4 100644 --- a/src/daemon.py +++ b/src/daemon.py @@ -27,6 +27,9 @@ from src.monitoring_tests.mev_blocker_kickbacks_test import ( MEVBlockerRefundsMonitoringTest, ) +from src.monitoring_tests.buffers_monitoring_test import ( + BuffersMonitoringTest, +) from src.constants import SLEEP_TIME_IN_SEC @@ -44,6 +47,7 @@ def main() -> None: PartialFillCostCoverageTest(), CostCoveragePerSolverTest(), MEVBlockerRefundsMonitoringTest(), + BuffersMonitoringTest(), ] start_block: Optional[int] = None From 4b1bc04e3f43602ad42a24c14f05f9922af7db7e Mon Sep 17 00:00:00 2001 From: harisang Date: Mon, 9 Oct 2023 13:11:37 +0300 Subject: [PATCH 06/19] renamed constant --- src/constants.py | 2 +- src/monitoring_tests/buffers_monitoring_test.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/constants.py b/src/constants.py index c510579..4b3c1ee 100644 --- a/src/constants.py +++ b/src/constants.py @@ -29,7 +29,7 @@ BUFFER_INTERVAL = 150 # threshold of value of buffers above which an alert is generated -BUFFER_VALUE_THRESHOLD = 200000 +BUFFERS_VALUE_USD_THRESHOLD = 200000 # threshold parameter to generate an alert when receiving kickbacks KICKBACKS_ALERT_THRESHOLD = 0.03 diff --git a/src/monitoring_tests/buffers_monitoring_test.py b/src/monitoring_tests/buffers_monitoring_test.py index 1dcb5c3..da02192 100644 --- a/src/monitoring_tests/buffers_monitoring_test.py +++ b/src/monitoring_tests/buffers_monitoring_test.py @@ -9,7 +9,7 @@ BUFFER_INTERVAL, header, REQUEST_TIMEOUT, - BUFFER_VALUE_THRESHOLD, + BUFFERS_VALUE_USD_THRESHOLD, ) @@ -75,7 +75,7 @@ def compute_buffers_value(self) -> bool: value_in_usd += token_buffer_value_in_usd self.buffers_value = value_in_usd log_output = f"Buffer value is {self.buffers_value} USD" - if self.buffers_value > BUFFER_VALUE_THRESHOLD: + if self.buffers_value > BUFFERS_VALUE_USD_THRESHOLD: self.alert(log_output) else: self.logger.info(log_output) From b3b184252e83686064ea065e2cb4cabd7462ae1b Mon Sep 17 00:00:00 2001 From: harisang Date: Mon, 9 Oct 2023 13:26:57 +0300 Subject: [PATCH 07/19] remove unused class variable --- src/monitoring_tests/buffers_monitoring_test.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/monitoring_tests/buffers_monitoring_test.py b/src/monitoring_tests/buffers_monitoring_test.py index da02192..03296ed 100644 --- a/src/monitoring_tests/buffers_monitoring_test.py +++ b/src/monitoring_tests/buffers_monitoring_test.py @@ -23,7 +23,6 @@ class BuffersMonitoringTest(BaseTest): def __init__(self) -> None: super().__init__() self.counter: int = 0 - self.buffers_value: float = 0.0 def compute_buffers_value(self) -> bool: """ @@ -73,9 +72,8 @@ def compute_buffers_value(self) -> bool: if coingecko_value_in_usd < token_buffer_value_in_usd: token_buffer_value_in_usd = coingecko_value_in_usd value_in_usd += token_buffer_value_in_usd - self.buffers_value = value_in_usd - log_output = f"Buffer value is {self.buffers_value} USD" - if self.buffers_value > BUFFERS_VALUE_USD_THRESHOLD: + log_output = f"Buffer value is {value_in_usd} USD" + if value_in_usd > BUFFERS_VALUE_USD_THRESHOLD: self.alert(log_output) else: self.logger.info(log_output) From c026b099ade5a90ce3a6bda5307085ca78e6cc44 Mon Sep 17 00:00:00 2001 From: harisang Date: Wed, 18 Oct 2023 16:55:49 +0300 Subject: [PATCH 08/19] add kleros list filtering --- src/monitoring_tests/buffers_monitoring_test.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/monitoring_tests/buffers_monitoring_test.py b/src/monitoring_tests/buffers_monitoring_test.py index 03296ed..bd5a7aa 100644 --- a/src/monitoring_tests/buffers_monitoring_test.py +++ b/src/monitoring_tests/buffers_monitoring_test.py @@ -40,8 +40,20 @@ def compute_buffers_value(self) -> bool: ) rsp = resp.json() + kleros_resp = requests.get( + "http://t2crtokens.eth.link", + headers=header, + timeout=REQUEST_TIMEOUT, + ) + kleros_rsp = kleros_resp.json() + kleros_list = [] + for t in kleros_rsp["tokens"]: + kleros_list.append(t["address"]) + value_in_usd = 0.0 for token in rsp["tokens"]: + if token["tokenInfo"]["address"] not in kleros_list: + continue balance = token["balance"] decimals = int(token["tokenInfo"]["decimals"]) if token["tokenInfo"]["price"] is not False: From 74360e426aea22a4ae6b2e17636d96398136266d Mon Sep 17 00:00:00 2001 From: harisang Date: Thu, 19 Oct 2023 02:12:54 +0300 Subject: [PATCH 09/19] add coingecko and kleros api --- src/apis/coingeckoapi.py | 45 +++++++++++++++++++ src/apis/klerosapi.py | 42 +++++++++++++++++ .../buffers_monitoring_test.py | 41 ++++++----------- 3 files changed, 101 insertions(+), 27 deletions(-) create mode 100644 src/apis/coingeckoapi.py create mode 100644 src/apis/klerosapi.py diff --git a/src/apis/coingeckoapi.py b/src/apis/coingeckoapi.py new file mode 100644 index 0000000..158620c --- /dev/null +++ b/src/apis/coingeckoapi.py @@ -0,0 +1,45 @@ +""" +CoingeckoAPI for fetching the price in usd of a given token. +""" +# pylint: disable=logging-fstring-interpolation + +from typing import Optional +import requests +from src.helper_functions import get_logger +from src.constants import ( + header, + REQUEST_TIMEOUT, +) + + +class CoingeckoAPI: + """ + Class for fetching token prices from Coingecko. + """ + + def __init__(self) -> None: + self.logger = get_logger() + + def get_token_price_in_usd(self, address: str) -> Optional[float]: + """ + Returns the Coingecko price in usd of the given token. + """ + coingecko_url = ( + "https://api.coingecko.com/api/v3/simple/token_price/ethereum?contract_addresses=" + + address + + "&vs_currencies=usd" + ) + try: + coingecko_data = requests.get( + coingecko_url, + headers=header, + timeout=REQUEST_TIMEOUT, + ) + coingecko_rsp = coingecko_data.json() + coingecko_price_in_usd = coingecko_rsp[address]["usd"] + except requests.RequestException as err: + self.logger.warning( + f"Connection error while fetching Coingecko price for token {address}, error: {err}" + ) + return None + return coingecko_price_in_usd diff --git a/src/apis/klerosapi.py b/src/apis/klerosapi.py new file mode 100644 index 0000000..03b7e43 --- /dev/null +++ b/src/apis/klerosapi.py @@ -0,0 +1,42 @@ +""" +KlerosAPI for fetching the Kleros token list. +""" +# pylint: disable=logging-fstring-interpolation + +import requests +from src.helper_functions import get_logger +from src.constants import ( + header, + REQUEST_TIMEOUT, +) + + +class KlerosAPI: + """ + Class for fetching the Kleros token list. + """ + + def __init__(self) -> None: + self.logger = get_logger() + + def get_token_list(self) -> list[str]: + """ + Returns the Kleros token list. + """ + kleros_url = "http://t2crtokens.eth.link" + + try: + kleros_data = requests.get( + kleros_url, + headers=header, + timeout=REQUEST_TIMEOUT, + ) + kleros_rsp = kleros_data.json() + kleros_list = [] + for token in kleros_rsp["tokens"]: + kleros_list.append(token["address"].lower()) + except requests.RequestException as err: + self.logger.warning( + f"Connection error while fetching the Kleros token list, error: {err}" + ) + return kleros_list diff --git a/src/monitoring_tests/buffers_monitoring_test.py b/src/monitoring_tests/buffers_monitoring_test.py index bd5a7aa..9594538 100644 --- a/src/monitoring_tests/buffers_monitoring_test.py +++ b/src/monitoring_tests/buffers_monitoring_test.py @@ -5,6 +5,8 @@ # pylint: disable=logging-fstring-interpolation import requests from src.monitoring_tests.base_test import BaseTest +from src.apis.coingeckoapi import CoingeckoAPI +from src.apis.klerosapi import KlerosAPI from src.constants import ( BUFFER_INTERVAL, header, @@ -22,6 +24,8 @@ class BuffersMonitoringTest(BaseTest): def __init__(self) -> None: super().__init__() + self.coingecko_api = CoingeckoAPI() + self.kleros_api = KlerosAPI() self.counter: int = 0 def compute_buffers_value(self) -> bool: @@ -30,7 +34,7 @@ def compute_buffers_value(self) -> bool: """ # get all token balances of the smart contract try: - resp = requests.get( + ethplorer_data = requests.get( "https://api.ethplorer.io/\ getAddressInfo/\ 0x9008D19f58AAbD9eD0D60971565AA8510560ab41?\ @@ -38,20 +42,11 @@ def compute_buffers_value(self) -> bool: headers=header, timeout=REQUEST_TIMEOUT, ) - rsp = resp.json() - - kleros_resp = requests.get( - "http://t2crtokens.eth.link", - headers=header, - timeout=REQUEST_TIMEOUT, - ) - kleros_rsp = kleros_resp.json() - kleros_list = [] - for t in kleros_rsp["tokens"]: - kleros_list.append(t["address"]) + ethplorer_rsp = ethplorer_data.json() + kleros_list = self.kleros_api.get_token_list() value_in_usd = 0.0 - for token in rsp["tokens"]: + for token in ethplorer_rsp["tokens"]: if token["tokenInfo"]["address"] not in kleros_list: continue balance = token["balance"] @@ -65,19 +60,11 @@ def compute_buffers_value(self) -> bool: # smart contract we use a second price feed, from coingecko, to correct in case # the initial price is indeed off if token_buffer_value_in_usd > 10000: - coingecko_resp = requests.get( - "https://api.coingecko.com/\ - api/v3/simple/token_price/\ - ethereum?contract_addresses=" - + token["tokenInfo"]["address"] - + "&vs_currencies=usd", - headers=header, - timeout=REQUEST_TIMEOUT, + coingecko_price_in_usd = ( + self.coingecko_api.get_token_price_in_usd( + token["tokenInfo"]["address"] + ) ) - coingecko_rsp = coingecko_resp.json() - coingecko_price_in_usd = coingecko_rsp[ - token["tokenInfo"]["address"] - ]["usd"] coingecko_value_in_usd = ( balance / 10**decimals ) * coingecko_price_in_usd @@ -90,9 +77,9 @@ def compute_buffers_value(self) -> bool: else: self.logger.info(log_output) - except requests.RequestException as err: + except Exception as err: self.logger.warning( - f"Connection error while fetching buffer tokens and prices, error: {err}" + f"Error while fetching buffer tokens and prices, error: {err}" ) return False return True From de768252bf51b82d7473ccd9fb2297fd5d67d184 Mon Sep 17 00:00:00 2001 From: harisang Date: Thu, 19 Oct 2023 02:18:26 +0300 Subject: [PATCH 10/19] fix exception handling --- src/monitoring_tests/buffers_monitoring_test.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/monitoring_tests/buffers_monitoring_test.py b/src/monitoring_tests/buffers_monitoring_test.py index 9594538..81befae 100644 --- a/src/monitoring_tests/buffers_monitoring_test.py +++ b/src/monitoring_tests/buffers_monitoring_test.py @@ -46,6 +46,8 @@ def compute_buffers_value(self) -> bool: kleros_list = self.kleros_api.get_token_list() value_in_usd = 0.0 + if "tokens" not in ethplorer_rsp: + return False for token in ethplorer_rsp["tokens"]: if token["tokenInfo"]["address"] not in kleros_list: continue @@ -77,9 +79,9 @@ def compute_buffers_value(self) -> bool: else: self.logger.info(log_output) - except Exception as err: + except requests.RequestException as err: self.logger.warning( - f"Error while fetching buffer tokens and prices, error: {err}" + f"Connection Error while fetching buffer tokens and prices, error: {err}" ) return False return True From f58aac0a075e608d7744e538a7e644fb30d7a03c Mon Sep 17 00:00:00 2001 From: harisang Date: Thu, 19 Oct 2023 02:21:14 +0300 Subject: [PATCH 11/19] fix mypy error --- src/apis/coingeckoapi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apis/coingeckoapi.py b/src/apis/coingeckoapi.py index 158620c..b3b50c3 100644 --- a/src/apis/coingeckoapi.py +++ b/src/apis/coingeckoapi.py @@ -36,7 +36,7 @@ def get_token_price_in_usd(self, address: str) -> Optional[float]: timeout=REQUEST_TIMEOUT, ) coingecko_rsp = coingecko_data.json() - coingecko_price_in_usd = coingecko_rsp[address]["usd"] + coingecko_price_in_usd = float(coingecko_rsp[address]["usd"]) except requests.RequestException as err: self.logger.warning( f"Connection error while fetching Coingecko price for token {address}, error: {err}" From 64a1fd32684b5500b550c2d037cf5c6befeb98bc Mon Sep 17 00:00:00 2001 From: harisang Date: Mon, 6 Nov 2023 14:25:54 +0200 Subject: [PATCH 12/19] fix url formatting --- src/monitoring_tests/buffers_monitoring_test.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/monitoring_tests/buffers_monitoring_test.py b/src/monitoring_tests/buffers_monitoring_test.py index 81befae..f3a8d99 100644 --- a/src/monitoring_tests/buffers_monitoring_test.py +++ b/src/monitoring_tests/buffers_monitoring_test.py @@ -35,10 +35,7 @@ def compute_buffers_value(self) -> bool: # get all token balances of the smart contract try: ethplorer_data = requests.get( - "https://api.ethplorer.io/\ - getAddressInfo/\ - 0x9008D19f58AAbD9eD0D60971565AA8510560ab41?\ - apiKey=freekey", + "https://api.ethplorer.io/getAddressInfo/0x9008D19f58AAbD9eD0D60971565AA8510560ab41?apiKey=freekey", headers=header, timeout=REQUEST_TIMEOUT, ) @@ -93,6 +90,7 @@ def run(self, tx_hash: str) -> bool: """ self.counter += 1 if self.counter > BUFFER_INTERVAL: + print("HERE") success = self.compute_buffers_value() if success: self.counter = 0 From 6b84dd8562d2d08036c47e0f1c476aac98fdf8b1 Mon Sep 17 00:00:00 2001 From: harisang Date: Mon, 6 Nov 2023 14:38:08 +0200 Subject: [PATCH 13/19] fix pylint error --- src/monitoring_tests/buffers_monitoring_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/monitoring_tests/buffers_monitoring_test.py b/src/monitoring_tests/buffers_monitoring_test.py index f3a8d99..3fff4b6 100644 --- a/src/monitoring_tests/buffers_monitoring_test.py +++ b/src/monitoring_tests/buffers_monitoring_test.py @@ -35,7 +35,8 @@ def compute_buffers_value(self) -> bool: # get all token balances of the smart contract try: ethplorer_data = requests.get( - "https://api.ethplorer.io/getAddressInfo/0x9008D19f58AAbD9eD0D60971565AA8510560ab41?apiKey=freekey", + "https://api.ethplorer.io/getAddressInfo/" + + "0x9008D19f58AAbD9eD0D60971565AA8510560ab41?apiKey=freekey", headers=header, timeout=REQUEST_TIMEOUT, ) From 2f40137a2497ce28b53d50c94f3ca0cd62372627 Mon Sep 17 00:00:00 2001 From: harisang Date: Mon, 6 Nov 2023 14:51:39 +0200 Subject: [PATCH 14/19] properly handle exception --- src/apis/klerosapi.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/apis/klerosapi.py b/src/apis/klerosapi.py index 03b7e43..56df1f6 100644 --- a/src/apis/klerosapi.py +++ b/src/apis/klerosapi.py @@ -33,6 +33,8 @@ def get_token_list(self) -> list[str]: ) kleros_rsp = kleros_data.json() kleros_list = [] + if "tokens" not in kleros_rsp: + return kleros_list for token in kleros_rsp["tokens"]: kleros_list.append(token["address"].lower()) except requests.RequestException as err: From 33c6422cf734466c3fcfb46059578bdc8e8fbd1e Mon Sep 17 00:00:00 2001 From: harisang Date: Mon, 6 Nov 2023 14:53:12 +0200 Subject: [PATCH 15/19] add type annotation --- src/apis/klerosapi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apis/klerosapi.py b/src/apis/klerosapi.py index 56df1f6..89882dc 100644 --- a/src/apis/klerosapi.py +++ b/src/apis/klerosapi.py @@ -32,7 +32,7 @@ def get_token_list(self) -> list[str]: timeout=REQUEST_TIMEOUT, ) kleros_rsp = kleros_data.json() - kleros_list = [] + kleros_list: list[str] = [] if "tokens" not in kleros_rsp: return kleros_list for token in kleros_rsp["tokens"]: From 8082829299dff50b140715b4353ed1ca14da1ebb Mon Sep 17 00:00:00 2001 From: harisang Date: Wed, 8 Nov 2023 14:27:39 +0200 Subject: [PATCH 16/19] removed dummy debug comment --- src/monitoring_tests/buffers_monitoring_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/monitoring_tests/buffers_monitoring_test.py b/src/monitoring_tests/buffers_monitoring_test.py index 3fff4b6..891f066 100644 --- a/src/monitoring_tests/buffers_monitoring_test.py +++ b/src/monitoring_tests/buffers_monitoring_test.py @@ -91,7 +91,6 @@ def run(self, tx_hash: str) -> bool: """ self.counter += 1 if self.counter > BUFFER_INTERVAL: - print("HERE") success = self.compute_buffers_value() if success: self.counter = 0 From 22e3adf9f8f18fc1985b383381cc8df2f26d156c Mon Sep 17 00:00:00 2001 From: harisang Date: Wed, 8 Nov 2023 14:48:50 +0200 Subject: [PATCH 17/19] incorporated comments and added more token lists --- src/apis/klerosapi.py | 44 ---------------- src/apis/tokenlistapi.py | 50 +++++++++++++++++++ .../buffers_monitoring_test.py | 14 +++--- 3 files changed, 58 insertions(+), 50 deletions(-) delete mode 100644 src/apis/klerosapi.py create mode 100644 src/apis/tokenlistapi.py diff --git a/src/apis/klerosapi.py b/src/apis/klerosapi.py deleted file mode 100644 index 89882dc..0000000 --- a/src/apis/klerosapi.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -KlerosAPI for fetching the Kleros token list. -""" -# pylint: disable=logging-fstring-interpolation - -import requests -from src.helper_functions import get_logger -from src.constants import ( - header, - REQUEST_TIMEOUT, -) - - -class KlerosAPI: - """ - Class for fetching the Kleros token list. - """ - - def __init__(self) -> None: - self.logger = get_logger() - - def get_token_list(self) -> list[str]: - """ - Returns the Kleros token list. - """ - kleros_url = "http://t2crtokens.eth.link" - - try: - kleros_data = requests.get( - kleros_url, - headers=header, - timeout=REQUEST_TIMEOUT, - ) - kleros_rsp = kleros_data.json() - kleros_list: list[str] = [] - if "tokens" not in kleros_rsp: - return kleros_list - for token in kleros_rsp["tokens"]: - kleros_list.append(token["address"].lower()) - except requests.RequestException as err: - self.logger.warning( - f"Connection error while fetching the Kleros token list, error: {err}" - ) - return kleros_list diff --git a/src/apis/tokenlistapi.py b/src/apis/tokenlistapi.py new file mode 100644 index 0000000..a92c40a --- /dev/null +++ b/src/apis/tokenlistapi.py @@ -0,0 +1,50 @@ +""" +TokenListAPI for fetching a curated token list. +""" +# pylint: disable=logging-fstring-interpolation +from typing import Optional +import requests +from src.helper_functions import get_logger +from src.constants import ( + header, + REQUEST_TIMEOUT, +) + + +class TokenListAPI: + """ + Class for fetching a curated token list. + """ + + def __init__(self) -> None: + self.logger = get_logger() + + def get_token_list(self) -> Optional[list[str]]: + """ + Returns a token list. + """ + kleros_url = "http://t2crtokens.eth.link" + one_inch_url = "https://tokens.1inch.eth.link" + aave_url = "https://tokenlist.aave.eth.link" + + url_list = [kleros_url, one_inch_url, aave_url] + + token_list: list[str] = [] + for url in url_list: + try: + data = requests.get( + url, + headers=header, + timeout=REQUEST_TIMEOUT, + ) + rsp = data.json() + if "tokens" in rsp: + for token in rsp["tokens"]: + token_list.append(token["address"].lower()) + except requests.RequestException as err: + self.logger.warning( + f"Connection error while fetching a token list, error: {err}" + ) + if len(token_list) > 0: + return token_list + return None diff --git a/src/monitoring_tests/buffers_monitoring_test.py b/src/monitoring_tests/buffers_monitoring_test.py index 891f066..050bd17 100644 --- a/src/monitoring_tests/buffers_monitoring_test.py +++ b/src/monitoring_tests/buffers_monitoring_test.py @@ -6,7 +6,7 @@ import requests from src.monitoring_tests.base_test import BaseTest from src.apis.coingeckoapi import CoingeckoAPI -from src.apis.klerosapi import KlerosAPI +from src.apis.tokenlistapi import TokenListAPI from src.constants import ( BUFFER_INTERVAL, header, @@ -25,7 +25,7 @@ class BuffersMonitoringTest(BaseTest): def __init__(self) -> None: super().__init__() self.coingecko_api = CoingeckoAPI() - self.kleros_api = KlerosAPI() + self.tokenlist_api = TokenListAPI() self.counter: int = 0 def compute_buffers_value(self) -> bool: @@ -41,13 +41,15 @@ def compute_buffers_value(self) -> bool: timeout=REQUEST_TIMEOUT, ) ethplorer_rsp = ethplorer_data.json() - kleros_list = self.kleros_api.get_token_list() - - value_in_usd = 0.0 if "tokens" not in ethplorer_rsp: return False + token_list = self.tokenlist_api.get_token_list() + if token_list is None: + return False + + value_in_usd = 0.0 for token in ethplorer_rsp["tokens"]: - if token["tokenInfo"]["address"] not in kleros_list: + if token["tokenInfo"]["address"] not in token_list: continue balance = token["balance"] decimals = int(token["tokenInfo"]["decimals"]) From 30043a583fafe672b5055d38792793b1bbc234fb Mon Sep 17 00:00:00 2001 From: Haris Angelidakis <64154020+harisang@users.noreply.github.com> Date: Thu, 9 Nov 2023 16:12:25 +0200 Subject: [PATCH 18/19] Update src/apis/tokenlistapi.py Co-authored-by: Felix Henneke --- src/apis/tokenlistapi.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/apis/tokenlistapi.py b/src/apis/tokenlistapi.py index a92c40a..b65f3b6 100644 --- a/src/apis/tokenlistapi.py +++ b/src/apis/tokenlistapi.py @@ -18,19 +18,18 @@ class TokenListAPI: def __init__(self) -> None: self.logger = get_logger() + self.token_lists = [ + "http://t2crtokens.eth.link", + "https://tokens.1inch.eth.link", + "https://tokenlist.aave.eth.link", + ] def get_token_list(self) -> Optional[list[str]]: """ Returns a token list. """ - kleros_url = "http://t2crtokens.eth.link" - one_inch_url = "https://tokens.1inch.eth.link" - aave_url = "https://tokenlist.aave.eth.link" - - url_list = [kleros_url, one_inch_url, aave_url] - token_list: list[str] = [] - for url in url_list: + for url in self.token_lists: try: data = requests.get( url, From 144929f99957126122c4a17751f0c0a6119d83d7 Mon Sep 17 00:00:00 2001 From: Haris Angelidakis <64154020+harisang@users.noreply.github.com> Date: Thu, 9 Nov 2023 17:44:23 +0200 Subject: [PATCH 19/19] Update src/apis/tokenlistapi.py Co-authored-by: Felix Henneke --- src/apis/tokenlistapi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apis/tokenlistapi.py b/src/apis/tokenlistapi.py index b65f3b6..6b1ad31 100644 --- a/src/apis/tokenlistapi.py +++ b/src/apis/tokenlistapi.py @@ -42,7 +42,7 @@ def get_token_list(self) -> Optional[list[str]]: token_list.append(token["address"].lower()) except requests.RequestException as err: self.logger.warning( - f"Connection error while fetching a token list, error: {err}" + f"Exception while fetching a token list: {err}" ) if len(token_list) > 0: return token_list