diff --git a/.gitignore b/.gitignore index 83a37f7..427023f 100644 --- a/.gitignore +++ b/.gitignore @@ -121,3 +121,24 @@ coverage.xml *~ *~ .*.swp + +# Test coverage +htmlcov/ +.coverage +.coverage.* +coverage.xml +coverage.svg +.pytest_cache/ + +# Test artifacts +.tox/ +.cache +nosetests.xml +*.cover +.hypothesis/ + +# Virtual environments +.venv +venv/ +ENV/ +env/ diff --git a/crypto_com_developer_platform_client/__init__.py b/crypto_com_developer_platform_client/__init__.py index aa4c483..3bc1240 100644 --- a/crypto_com_developer_platform_client/__init__.py +++ b/crypto_com_developer_platform_client/__init__.py @@ -1,13 +1,13 @@ from .block import Block from .client import Client from .contract import Contract -from .event import Event -from .network import Network from .cronosid import CronosId from .defi import Defi +from .event import Event from .exchange import Exchange from .interfaces.chain_interfaces import CronosEvm, CronosZkEvm from .interfaces.defi_interfaces import DefiProtocol +from .network import Network from .token import Token from .transaction import Transaction from .wallet import Wallet diff --git a/crypto_com_developer_platform_client/client.py b/crypto_com_developer_platform_client/client.py index b35ad5b..00c180a 100644 --- a/crypto_com_developer_platform_client/client.py +++ b/crypto_com_developer_platform_client/client.py @@ -20,11 +20,11 @@ def init(cls, api_key: str, provider: str = "") -> None: from .block import Block from .contract import Contract - from .network import Network - from .event import Event from .cronosid import CronosId from .defi import Defi + from .event import Event from .exchange import Exchange + from .network import Network from .token import Token from .transaction import Transaction from .wallet import Wallet @@ -48,7 +48,7 @@ def get_api_key(cls) -> str: :return: The API key. :raises ValueError: If the API key is not set. """ - if cls._api_key is None: + if not hasattr(cls, "_api_key") or cls._api_key is None: raise ValueError("API key is not set. Please set the API key.") return cls._api_key @@ -60,7 +60,7 @@ def get_provider(cls) -> str: :return: The provider. """ - if cls._provider is None: + if not hasattr(cls, "_provider") or cls._provider is None: raise ValueError("Provider is not set. Please set the provider.") return cls._provider diff --git a/crypto_com_developer_platform_client/exchange.py b/crypto_com_developer_platform_client/exchange.py index 1fb878e..ffffb8e 100644 --- a/crypto_com_developer_platform_client/exchange.py +++ b/crypto_com_developer_platform_client/exchange.py @@ -26,7 +26,10 @@ def get_all_tickers(cls) -> ApiResponse: :return: A list of all available tickers and their information. """ - return get_all_tickers() + if cls._client is None: + raise ValueError("Exchange class not initialized with a Client instance") + + return get_all_tickers(cls._client.get_api_key()) @classmethod def get_ticker_by_instrument(cls, instrument_name: str) -> ApiResponse: @@ -37,7 +40,10 @@ def get_ticker_by_instrument(cls, instrument_name: str) -> ApiResponse: :return: Ticker information for the specified instrument. :raises ValueError: If instrument_name is None or empty. """ + if cls._client is None: + raise ValueError("Exchange class not initialized with a Client instance") + if not instrument_name: raise ValueError("Instrument name is required") - return get_ticker_by_instrument(instrument_name) + return get_ticker_by_instrument(cls._client.get_api_key(), instrument_name) diff --git a/crypto_com_developer_platform_client/integrations/api_interfaces.py b/crypto_com_developer_platform_client/integrations/api_interfaces.py index 666c0f4..d44dd68 100644 --- a/crypto_com_developer_platform_client/integrations/api_interfaces.py +++ b/crypto_com_developer_platform_client/integrations/api_interfaces.py @@ -3,8 +3,8 @@ class Status(str, Enum): - SUCCESS = 'Success' - FAILED = 'Failed' + SUCCESS = "Success" + FAILED = "Failed" class ApiResponse(TypedDict): diff --git a/crypto_com_developer_platform_client/integrations/api_utils.py b/crypto_com_developer_platform_client/integrations/api_utils.py new file mode 100644 index 0000000..01a4cdb --- /dev/null +++ b/crypto_com_developer_platform_client/integrations/api_utils.py @@ -0,0 +1,20 @@ +import requests + + +def handle_api_error(response: requests.Response) -> None: + """ + Handles API error responses by extracting error messages and raising exceptions. + + :param response: The HTTP response object from requests + :raises Exception: Always raises an exception with the appropriate error message + """ + try: + error_body = response.json() + server_error_message = ( + error_body.get("error") or f"HTTP error! status: {response.status_code}" + ) + except ValueError: + # Handle non-JSON error responses + server_error_message = f"HTTP error! status: {response.status_code}" + + raise Exception(server_error_message) diff --git a/crypto_com_developer_platform_client/integrations/block_api.py b/crypto_com_developer_platform_client/integrations/block_api.py index 006012b..45055af 100644 --- a/crypto_com_developer_platform_client/integrations/block_api.py +++ b/crypto_com_developer_platform_client/integrations/block_api.py @@ -2,6 +2,7 @@ from ..constants import API_URL from .api_interfaces import ApiResponse +from .api_utils import handle_api_error def get_current_block(api_key: str) -> ApiResponse: @@ -25,11 +26,7 @@ def get_current_block(api_key: str) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -55,10 +52,6 @@ def get_block_by_tag(api_key: str, block_tag: str, tx_detail: str) -> ApiRespons ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"""HTTP error! status: {response.status_code}""" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() diff --git a/crypto_com_developer_platform_client/integrations/contract_api.py b/crypto_com_developer_platform_client/integrations/contract_api.py index 2019757..711a59d 100644 --- a/crypto_com_developer_platform_client/integrations/contract_api.py +++ b/crypto_com_developer_platform_client/integrations/contract_api.py @@ -1,6 +1,8 @@ import requests + from ..constants import API_URL from .api_interfaces import ApiResponse +from .api_utils import handle_api_error def get_contract_code(api_key: str, contract_address: str) -> ApiResponse: @@ -25,11 +27,7 @@ def get_contract_code(api_key: str, contract_address: str) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -60,10 +58,6 @@ def get_contract_abi( ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"""HTTP error! status: {response.status_code}""" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() diff --git a/crypto_com_developer_platform_client/integrations/cronosid_api.py b/crypto_com_developer_platform_client/integrations/cronosid_api.py index 7b1c1b4..75308e5 100644 --- a/crypto_com_developer_platform_client/integrations/cronosid_api.py +++ b/crypto_com_developer_platform_client/integrations/cronosid_api.py @@ -1,6 +1,8 @@ import requests + from ..constants import API_URL from .api_interfaces import ApiResponse +from .api_utils import handle_api_error def resolve_cronos_id(api_key: str, name: str) -> ApiResponse: @@ -22,11 +24,7 @@ def resolve_cronos_id(api_key: str, name: str) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -50,10 +48,6 @@ def lookup_cronos_id(api_key: str, address: str) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() diff --git a/crypto_com_developer_platform_client/integrations/defi_api.py b/crypto_com_developer_platform_client/integrations/defi_api.py index 95b4413..d17025d 100644 --- a/crypto_com_developer_platform_client/integrations/defi_api.py +++ b/crypto_com_developer_platform_client/integrations/defi_api.py @@ -2,6 +2,7 @@ from ..constants import API_URL from .api_interfaces import ApiResponse +from .api_utils import handle_api_error def get_whitelisted_tokens(project: str, api_key: str) -> ApiResponse: @@ -22,11 +23,7 @@ def get_whitelisted_tokens(project: str, api_key: str) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -49,11 +46,7 @@ def get_all_farms(project: str, api_key: str) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -77,10 +70,6 @@ def get_farm_by_symbol(project: str, symbol: str, api_key: str) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() diff --git a/crypto_com_developer_platform_client/integrations/event_api.py b/crypto_com_developer_platform_client/integrations/event_api.py index 67e616e..6f4b8a2 100644 --- a/crypto_com_developer_platform_client/integrations/event_api.py +++ b/crypto_com_developer_platform_client/integrations/event_api.py @@ -1,6 +1,8 @@ import requests + from ..constants import API_URL from .api_interfaces import ApiResponse +from .api_utils import handle_api_error def get_logs(api_key: str, address: str) -> ApiResponse: @@ -22,10 +24,6 @@ def get_logs(api_key: str, address: str) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() diff --git a/crypto_com_developer_platform_client/integrations/exchange_api.py b/crypto_com_developer_platform_client/integrations/exchange_api.py index 3cb82d9..cffb404 100644 --- a/crypto_com_developer_platform_client/integrations/exchange_api.py +++ b/crypto_com_developer_platform_client/integrations/exchange_api.py @@ -2,6 +2,7 @@ from ..constants import API_URL from .api_interfaces import ApiResponse +from .api_utils import handle_api_error def get_all_tickers(api_key: str) -> ApiResponse: @@ -21,11 +22,7 @@ def get_all_tickers(api_key: str) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -48,10 +45,6 @@ def get_ticker_by_instrument(api_key: str, instrument_name: str) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() diff --git a/crypto_com_developer_platform_client/integrations/network_api.py b/crypto_com_developer_platform_client/integrations/network_api.py index 0380c42..7f473dd 100644 --- a/crypto_com_developer_platform_client/integrations/network_api.py +++ b/crypto_com_developer_platform_client/integrations/network_api.py @@ -1,6 +1,8 @@ import requests + from ..constants import API_URL from .api_interfaces import ApiResponse +from .api_utils import handle_api_error def get_network_info(api_key: str) -> ApiResponse: @@ -21,11 +23,7 @@ def get_network_info(api_key: str) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -48,11 +46,7 @@ def get_chain_id(api_key: str) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -74,10 +68,6 @@ def get_client_version(api_key: str) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() diff --git a/crypto_com_developer_platform_client/integrations/token_api.py b/crypto_com_developer_platform_client/integrations/token_api.py index 48d19b6..5ba054d 100644 --- a/crypto_com_developer_platform_client/integrations/token_api.py +++ b/crypto_com_developer_platform_client/integrations/token_api.py @@ -2,6 +2,7 @@ from ..constants import API_URL from .api_interfaces import ApiResponse +from .api_utils import handle_api_error def get_native_token_balance(api_key: str, wallet_address: str) -> ApiResponse: @@ -22,11 +23,7 @@ def get_native_token_balance(api_key: str, wallet_address: str) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -53,11 +50,7 @@ def get_erc20_token_balance( ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -81,11 +74,7 @@ def transfer_token(api_key: str, payload: dict) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -109,11 +98,7 @@ def wrap_token(api_key: str, payload: dict) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -137,11 +122,7 @@ def swap_token(api_key: str, payload: dict) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -167,11 +148,7 @@ def get_erc721_token_balance( ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -195,11 +172,7 @@ def get_token_owner(api_key: str, contract_address: str, token_id: str) -> ApiRe ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -223,11 +196,7 @@ def get_token_uri(api_key: str, contract_address: str, token_id: str) -> ApiResp ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -250,11 +219,7 @@ def get_erc721_metadata(api_key: str, contract_address: str) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -277,10 +242,6 @@ def get_erc20_metadata(api_key: str, contract_address: str) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() diff --git a/crypto_com_developer_platform_client/integrations/transaction_api.py b/crypto_com_developer_platform_client/integrations/transaction_api.py index 9474d5a..e6357b4 100644 --- a/crypto_com_developer_platform_client/integrations/transaction_api.py +++ b/crypto_com_developer_platform_client/integrations/transaction_api.py @@ -1,9 +1,11 @@ from typing import Optional from urllib.parse import urlencode + import requests from ..constants import API_URL from .api_interfaces import ApiResponse +from .api_utils import handle_api_error def get_transactions_by_address( @@ -53,11 +55,7 @@ def get_transactions_by_address( ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -81,11 +79,7 @@ def get_transaction_by_hash(api_key: str, tx_hash: str) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -109,11 +103,7 @@ def get_transaction_status(api_key: str, tx_hash: str) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -136,11 +126,7 @@ def get_transaction_count(api_key: str, wallet_address: str) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -162,11 +148,7 @@ def get_gas_price(api_key: str) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -188,11 +170,7 @@ def get_fee_data(api_key: str) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -216,10 +194,6 @@ def estimate_gas(api_key: str, payload: dict) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() diff --git a/crypto_com_developer_platform_client/integrations/wallet_api.py b/crypto_com_developer_platform_client/integrations/wallet_api.py index 26b1659..8c26fae 100644 --- a/crypto_com_developer_platform_client/integrations/wallet_api.py +++ b/crypto_com_developer_platform_client/integrations/wallet_api.py @@ -2,6 +2,7 @@ from ..constants import API_URL from .api_interfaces import ApiResponse +from .api_utils import handle_api_error def create_wallet(api_key: str) -> ApiResponse: @@ -22,11 +23,7 @@ def create_wallet(api_key: str) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() @@ -50,10 +47,6 @@ def get_balance(api_key: str, wallet_address: str) -> ApiResponse: ) if response.status_code not in (200, 201): - error_body = response.json() - server_error_message = ( - error_body.get("error") or f"HTTP error! status: {response.status_code}" - ) - raise Exception(server_error_message) + handle_api_error(response) return response.json() diff --git a/crypto_com_developer_platform_client/interfaces/chain_interfaces.py b/crypto_com_developer_platform_client/interfaces/chain_interfaces.py index 75992d1..9e71828 100644 --- a/crypto_com_developer_platform_client/interfaces/chain_interfaces.py +++ b/crypto_com_developer_platform_client/interfaces/chain_interfaces.py @@ -5,6 +5,7 @@ class CronosEvm(str, Enum): """ Chain IDs for Cronos EVM (Mainnet and Testnet). """ + MAINNET = "25" TESTNET = "338" @@ -16,6 +17,7 @@ class CronosZkEvm(str, Enum): """ Chain IDs for Cronos ZK EVM (Mainnet and Testnet). """ + MAINNET = "388" TESTNET = "240" diff --git a/crypto_com_developer_platform_client/interfaces/defi_interfaces.py b/crypto_com_developer_platform_client/interfaces/defi_interfaces.py index 73a0801..7ef6266 100644 --- a/crypto_com_developer_platform_client/interfaces/defi_interfaces.py +++ b/crypto_com_developer_platform_client/interfaces/defi_interfaces.py @@ -5,5 +5,6 @@ class DefiProtocol(Enum): """ Enum representing supported DeFi protocols. """ + H2 = "h2finance" VVS = "vvsfinance" diff --git a/crypto_com_developer_platform_client/network.py b/crypto_com_developer_platform_client/network.py index b38f069..4993dfe 100644 --- a/crypto_com_developer_platform_client/network.py +++ b/crypto_com_developer_platform_client/network.py @@ -1,7 +1,8 @@ from typing import Optional + from .client import Client from .integrations.api_interfaces import ApiResponse -from .integrations.network_api import get_network_info, get_chain_id, get_client_version +from .integrations.network_api import get_chain_id, get_client_version, get_network_info class Network: diff --git a/crypto_com_developer_platform_client/token.py b/crypto_com_developer_platform_client/token.py index d345404..4ecb956 100644 --- a/crypto_com_developer_platform_client/token.py +++ b/crypto_com_developer_platform_client/token.py @@ -1,16 +1,16 @@ from .client import Client from .integrations.api_interfaces import ApiResponse from .integrations.token_api import ( + get_erc20_metadata, get_erc20_token_balance, + get_erc721_metadata, + get_erc721_token_balance, get_native_token_balance, + get_token_owner, + get_token_uri, swap_token, transfer_token, wrap_token, - get_erc721_token_balance, - get_token_owner, - get_token_uri, - get_erc721_metadata, - get_erc20_metadata, ) @@ -61,7 +61,10 @@ def get_erc20_balance( raise ValueError("Token class not initialized with a Client instance.") return get_erc20_token_balance( - cls._client.get_api_key(), wallet_address, contract_address, block_height + cls._client.get_api_key(), + wallet_address, + contract_address, + block_height, ) @classmethod diff --git a/crypto_com_developer_platform_client/transaction.py b/crypto_com_developer_platform_client/transaction.py index 67cf8ac..8a4b7dc 100644 --- a/crypto_com_developer_platform_client/transaction.py +++ b/crypto_com_developer_platform_client/transaction.py @@ -1,14 +1,15 @@ from typing import Optional + from .client import Client from .integrations.api_interfaces import ApiResponse from .integrations.transaction_api import ( + estimate_gas, + get_fee_data, + get_gas_price, get_transaction_by_hash, + get_transaction_count, get_transaction_status, get_transactions_by_address, - get_transaction_count, - get_gas_price, - get_fee_data, - estimate_gas, )