From 8b8cda9aa89abfa71ba1edc7801d6cb2ee87cbbe Mon Sep 17 00:00:00 2001 From: Uxio Fuentefria Date: Tue, 5 Dec 2023 19:39:53 +0100 Subject: [PATCH] Refactor Sourcify Client - Rename `Sourcify` to `SourcifyClient` - Add method to check networks not supported - Raise a `SourcifyClientConfigurationProblem` if network is not supported --- docs/source/gnosis.eth.clients.rst | 4 +-- gnosis/eth/clients/__init__.py | 12 ++++++--- .../{sourcify.py => sourcify_client.py} | 24 +++++++++++++++++- ...st_sourcify.py => test_sourcify_client.py} | 25 +++++++++++++++---- 4 files changed, 54 insertions(+), 11 deletions(-) rename gnosis/eth/clients/{sourcify.py => sourcify_client.py} (82%) rename gnosis/eth/tests/clients/{test_sourcify.py => test_sourcify_client.py} (57%) diff --git a/docs/source/gnosis.eth.clients.rst b/docs/source/gnosis.eth.clients.rst index 1ed6cd788..8c8574420 100644 --- a/docs/source/gnosis.eth.clients.rst +++ b/docs/source/gnosis.eth.clients.rst @@ -28,10 +28,10 @@ gnosis.eth.clients.etherscan\_client module :undoc-members: :show-inheritance: -gnosis.eth.clients.sourcify module +gnosis.eth.clients.sourcify_client module ---------------------------------- -.. automodule:: gnosis.eth.clients.sourcify +.. automodule:: gnosis.eth.clients.sourcify_client :members: :undoc-members: :show-inheritance: diff --git a/gnosis/eth/clients/__init__.py b/gnosis/eth/clients/__init__.py index 1d5175977..dccbf61e2 100644 --- a/gnosis/eth/clients/__init__.py +++ b/gnosis/eth/clients/__init__.py @@ -11,16 +11,22 @@ EtherscanClientException, EtherscanRateLimitError, ) -from .sourcify import Sourcify +from .sourcify_client import ( + SourcifyClient, + SourcifyClientConfigurationProblem, + SourcifyClientException, +) __all__ = [ + "BlockScoutConfigurationProblem", "BlockscoutClient", "BlockscoutClientException", - "BlockScoutConfigurationProblem", "ContractMetadata", "EtherscanClient", "EtherscanClientConfigurationProblem", "EtherscanClientException", "EtherscanRateLimitError", - "Sourcify", + "SourcifyClient", + "SourcifyClientConfigurationProblem", + "SourcifyClientException", ] diff --git a/gnosis/eth/clients/sourcify.py b/gnosis/eth/clients/sourcify_client.py similarity index 82% rename from gnosis/eth/clients/sourcify.py rename to gnosis/eth/clients/sourcify_client.py index bba39a0dd..118d339b9 100644 --- a/gnosis/eth/clients/sourcify.py +++ b/gnosis/eth/clients/sourcify_client.py @@ -3,12 +3,22 @@ import requests +from gnosis.util import cache + from .. import EthereumNetwork from ..utils import fast_is_checksum_address from .contract_metadata import ContractMetadata -class Sourcify: +class SourcifyClientException(Exception): + pass + + +class SourcifyClientConfigurationProblem(Exception): + pass + + +class SourcifyClient: """ Get contract metadata from Sourcify. Matches can be full or partial: @@ -31,6 +41,11 @@ def __init__( self.http_session = self._prepare_http_session() self.request_timeout = request_timeout + if not self.is_chain_supported(network.value): + raise SourcifyClientConfigurationProblem( + f"Network {network.name} - {network.value} not supported" + ) + def _prepare_http_session(self) -> requests.Session: """ Prepare http session with custom pooling. See: @@ -63,6 +78,13 @@ def _do_request(self, url: str) -> Optional[Dict[str, Any]]: return response.json() + def is_chain_supported(self, chain_id: int) -> bool: + return chain_id in (int(chain["chainId"]) for chain in self.get_chains()) + + @cache + def get_chains(self) -> Dict[str, Any]: + return self._do_request("https://sourcify.dev/server/chains") + def get_contract_metadata( self, contract_address: str ) -> Optional[ContractMetadata]: diff --git a/gnosis/eth/tests/clients/test_sourcify.py b/gnosis/eth/tests/clients/test_sourcify_client.py similarity index 57% rename from gnosis/eth/tests/clients/test_sourcify.py rename to gnosis/eth/tests/clients/test_sourcify_client.py index 102f3c5d3..df9f3eba0 100644 --- a/gnosis/eth/tests/clients/test_sourcify.py +++ b/gnosis/eth/tests/clients/test_sourcify_client.py @@ -3,12 +3,27 @@ from django.test import TestCase from ... import EthereumNetwork -from ...clients import Sourcify +from ...clients import SourcifyClient +from ...clients.sourcify_client import SourcifyClientConfigurationProblem -class TestSourcify(TestCase): - def test_sourcify_get_contract_metadata(self): - sourcify = Sourcify() +class TestSourcifyClient(TestCase): + def test_init(self): + with self.assertRaises(SourcifyClientConfigurationProblem): + SourcifyClient(EthereumNetwork.OLYMPIC) + + self.assertIsInstance(SourcifyClient(), SourcifyClient) + self.assertIsInstance(SourcifyClient(EthereumNetwork.GNOSIS), SourcifyClient) + + def test_is_chain_supported(self): + sourcify = SourcifyClient() + + self.assertTrue(sourcify.is_chain_supported(EthereumNetwork.MAINNET.value)) + self.assertTrue(sourcify.is_chain_supported(EthereumNetwork.GNOSIS.value)) + self.assertFalse(sourcify.is_chain_supported(2)) + + def test_get_contract_metadata(self): + sourcify = SourcifyClient() safe_contract_address = "0x6851D6fDFAfD08c0295C392436245E5bc78B0185" try: contract_metadata = sourcify.get_contract_metadata(safe_contract_address) @@ -18,7 +33,7 @@ def test_sourcify_get_contract_metadata(self): self.assertIsInstance(contract_metadata.abi, List) self.assertTrue(contract_metadata.abi) self.assertFalse(contract_metadata.partial_match) - contract_metadata_rinkeby = Sourcify( + contract_metadata_rinkeby = SourcifyClient( EthereumNetwork.RINKEBY ).get_contract_metadata(safe_contract_address) self.assertEqual(contract_metadata, contract_metadata_rinkeby)