diff --git a/gnosis/safe/api/base_api.py b/gnosis/safe/api/base_api.py index 54da7aa9d..9bc4a3871 100644 --- a/gnosis/safe/api/base_api.py +++ b/gnosis/safe/api/base_api.py @@ -4,7 +4,11 @@ import requests -from gnosis.eth.ethereum_client import EthereumClient, EthereumNetwork +from gnosis.eth.ethereum_client import ( + EthereumClient, + EthereumNetwork, + EthereumNetworkNotSupported, +) class SafeAPIException(Exception): @@ -15,19 +19,27 @@ class SafeBaseAPI(ABC): URL_BY_NETWORK: Dict[EthereumNetwork, str] = {} def __init__( - self, network: EthereumNetwork, ethereum_client: Optional[EthereumClient] = None + self, + network: EthereumNetwork, + ethereum_client: Optional[EthereumClient] = None, + base_url: Optional[str] = None, ): + """ + :param network: Network for the transaction service + :param ethereum_client: + :param base_url: If a custom transaction service is used + :raises: EthereumNetworkNotSupported + """ self.network = network self.ethereum_client = ethereum_client - self.base_url = self.URL_BY_NETWORK[network] + self.base_url = base_url or self.URL_BY_NETWORK.get(network) + if not self.base_url: + raise EthereumNetworkNotSupported(network) @classmethod - def from_ethereum_client( - cls, ethereum_client: EthereumClient - ) -> Optional["SafeBaseAPI"]: + def from_ethereum_client(cls, ethereum_client: EthereumClient) -> "SafeBaseAPI": ethereum_network = ethereum_client.get_network() - if ethereum_network in cls.URL_BY_NETWORK: - return cls(ethereum_network, ethereum_client=ethereum_client) + return cls(ethereum_network, ethereum_client=ethereum_client) def _get_request(self, url: str) -> requests.Response: full_url = urljoin(self.base_url, url) diff --git a/gnosis/safe/api/transaction_service_api.py b/gnosis/safe/api/transaction_service_api.py index 4e7ee58f7..54886922e 100644 --- a/gnosis/safe/api/transaction_service_api.py +++ b/gnosis/safe/api/transaction_service_api.py @@ -19,14 +19,14 @@ class TransactionServiceApi(SafeBaseAPI): URL_BY_NETWORK = { EthereumNetwork.ARBITRUM: "https://safe-transaction.arbitrum.gnosis.io", - EthereumNetwork.AURORA: "https://safe-transaction.aurora.gnosis.io/", + EthereumNetwork.AURORA: "https://safe-transaction.aurora.gnosis.io", EthereumNetwork.AVALANCHE: "https://safe-transaction.avalanche.gnosis.io", EthereumNetwork.BINANCE: "https://safe-transaction.bsc.gnosis.io", EthereumNetwork.ENERGY_WEB_CHAIN: "https://safe-transaction.ewc.gnosis.io", EthereumNetwork.GOERLI: "https://safe-transaction.goerli.gnosis.io", EthereumNetwork.MAINNET: "https://safe-transaction.mainnet.gnosis.io", EthereumNetwork.MATIC: "https://safe-transaction.polygon.gnosis.io", - EthereumNetwork.OPTIMISTIC: "https://safe-transaction.optimism.gnosis.io/", + EthereumNetwork.OPTIMISTIC: "https://safe-transaction.optimism.gnosis.io", EthereumNetwork.RINKEBY: "https://safe-transaction.rinkeby.gnosis.io", EthereumNetwork.VOLTA: "https://safe-transaction.volta.gnosis.io", EthereumNetwork.XDAI: "https://safe-transaction.xdai.gnosis.io", diff --git a/gnosis/safe/tests/api/test_transaction_service_api.py b/gnosis/safe/tests/api/test_transaction_service_api.py index 8cfaa6501..1f05ac36f 100644 --- a/gnosis/safe/tests/api/test_transaction_service_api.py +++ b/gnosis/safe/tests/api/test_transaction_service_api.py @@ -1,18 +1,45 @@ -import unittest +from unittest import mock -from gnosis.eth import EthereumNetwork +from django.test import TestCase + +from gnosis.eth import EthereumClient, EthereumNetwork, EthereumNetworkNotSupported from gnosis.eth.tests.ethereum_test_case import EthereumTestCaseMixin from ...api.transaction_service_api import TransactionServiceApi -class TestTransactionServiceAPI(EthereumTestCaseMixin, unittest.TestCase): +class TestTransactionServiceAPI(EthereumTestCaseMixin, TestCase): def setUp(self) -> None: - self.transaction_service = TransactionServiceApi( + self.transaction_service_api = TransactionServiceApi( EthereumNetwork.RINKEBY, ethereum_client=self.ethereum_client ) self.safe_address = "0x7552Ed65a45E27740a15B8D5415E90d8ca64C109" + def test_constructor(self): + ethereum_network = EthereumNetwork.RINKEBY + base_url = "https://safe.global" + transaction_service_api = TransactionServiceApi( + ethereum_network, ethereum_client=None, base_url=base_url + ) + self.assertEqual(transaction_service_api.network, ethereum_network) + self.assertIsNone(transaction_service_api.ethereum_client) + self.assertEqual(transaction_service_api.base_url, base_url) + + def test_from_ethereum_client(self): + with self.assertRaisesMessage(EthereumNetworkNotSupported, "GANACHE"): + TransactionServiceApi.from_ethereum_client(self.ethereum_client) + + with mock.patch.object( + EthereumClient, "get_network", return_value=EthereumNetwork.RINKEBY + ): + transaction_service_api = TransactionServiceApi.from_ethereum_client( + self.ethereum_client + ) + self.assertEqual( + transaction_service_api.ethereum_client, self.ethereum_client + ) + self.assertEqual(transaction_service_api.network, EthereumNetwork.RINKEBY) + def test_data_decoded_to_text(self): test_data = { "method": "multiSend", @@ -58,7 +85,7 @@ def test_data_decoded_to_text(self): } ], } - decoded_data_text = self.transaction_service.data_decoded_to_text(test_data) + decoded_data_text = self.transaction_service_api.data_decoded_to_text(test_data) self.assertIn( "- changeMasterCopy: 0x34CfAC646f301356fAa8B21e94227e3583Fe3F5F", decoded_data_text, @@ -69,9 +96,9 @@ def test_data_decoded_to_text(self): ) def test_get_balances(self): - balances = self.transaction_service.get_balances(self.safe_address) + balances = self.transaction_service_api.get_balances(self.safe_address) self.assertIsInstance(balances, list) def test_get_transactions(self): - transactions = self.transaction_service.get_transactions(self.safe_address) + transactions = self.transaction_service_api.get_transactions(self.safe_address) self.assertIsInstance(transactions, list)