diff --git a/DexilonClientImpl.py b/DexilonClientImpl.py index 1966e91..323eb6f 100644 --- a/DexilonClientImpl.py +++ b/DexilonClientImpl.py @@ -1,3 +1,5 @@ +import json +import logging from datetime import datetime from typing import List @@ -12,7 +14,7 @@ from ErrorBody import ErrorBody from OrderErrorInfo import OrderErrorInfo from SessionClient import SessionClient -from exceptions import DexilonAPIException, DexilonRequestException, DexilonAuthException +from exceptions import DexilonAPIException, DexilonRequestException, DexilonAuthException,DexilonErrorBodyException from responses import AvailableSymbol, OrderBookInfo, JWTTokenResponse, OrderEvent, \ ServiceResponse, ErrorBody, AccountInfo, OrderInfo, AllOpenOrders, \ FullOrderInfo, LeverageUpdateInfo, CosmosAddressMapping @@ -43,10 +45,13 @@ def __init__(self, metamask_address, api_secret): self.headers['MetamaskAddress'] = self.METAMASK_ADDRESS self.API_SECRET = api_secret self.pk1 = keys.PrivateKey(bytes.fromhex(api_secret)) + + def setup(self): self.client: SessionClient = SessionClient(self.API_URL, self.headers) + self.client.base_url = self.API_URL self.dex_session_client: SessionClient = SessionClient(self.COSMOS_ADDRESS_API_URL, self.cosmos_headers) - def change_api_url(self, api_url): + def change_api_url(self, api_url, cosmos_address_api_url): """ Used for testing purposes @@ -54,9 +59,9 @@ def change_api_url(self, api_url): :type api_url: str. """ - self.API_URL = api_url - self.client.base_url = api_url + self.COSMOS_ADDRESS_API_URL = cosmos_address_api_url + def change_cosmos_api_url(self, cosmos_api_url): """ @@ -170,6 +175,7 @@ def _request_dexilon_api(self, method: str, path: str, params: dict = None, data ) def _handle_dexilon_response(self, response: dict, model: BaseModel = None) -> BaseModel: + logging.debug("response: %s" % (response)) if response is None: service_response = parse_obj_as(ServiceResponse, response) return service_response @@ -203,8 +209,21 @@ def request_with_client(self, client, method: str, path: str, params: dict = Non ) def _handle_response_new(self, response: dict, model: BaseModel = None) -> BaseModel: - data: dict = response['body'] + logging.debug("response: %s" % (response)) + data: dict = response if data is None: + error_body: dict = response.get('errorBody') + if error_body: + raise DexilonErrorBodyException( + ErrorBody( + code=error_body.get('code'), + name=error_body.get('name'), + details=error_body.get('details', []) + ) + ) + else: + raise DexilonRequestException( + 'body and errorBody is empty in response %s' % json.dumps(response)) service_response = parse_obj_as(ServiceResponse, response) return service_response if model: @@ -247,8 +266,8 @@ def sign(self, nonce: str) -> str: encode_defunct(nonce), private_key=self.pk1 ).signature.hex() - def get_cosmos_address_mapping(self, eth_address: str): - cosmos_maping_response = self._request_dexilon_api('GET', '/registration/address_mapping/mirror/' + eth_address, + def get_cosmos_address_mapping(self, eth_address: str, chain_id: str): + cosmos_maping_response = self._request_dexilon_api('GET', '/registration/address_mapping/mirror/' + chain_id + '/' + eth_address, model=CosmosAddressMapping) return cosmos_maping_response @@ -256,14 +275,14 @@ def hash_keccak(self, message: str): return Web3.solidityKeccak(['string'], [message]) def authenticate(self): - - dexilon_address = self.get_cosmos_address_mapping(self.METAMASK_ADDRESS) + # TODO remove hardcode! + dexilon_address = self.get_cosmos_address_mapping(self.METAMASK_ADDRESS, "137") if dexilon_address.code is not None: print( 'There is no Dexilon chain mapping for Etherium address ' + self.METAMASK_ADDRESS + '. Registering user in Dexilon chain') dexilon_chain_address = self.register_dexilon_user(self.METAMASK_ADDRESS) else: - dexilon_chain_address = dexilon_address.addressMapping.cosmosAddress + dexilon_chain_address = dexilon_address.cosmosAddress cur_time_in_milliseconds = int((datetime.utcnow() - datetime(1970, 1, 1)).total_seconds() * 1000) nonce = str(cur_time_in_milliseconds) + '#' + dexilon_chain_address diff --git a/SessionClient.py b/SessionClient.py index 5e6e976..233b3a3 100644 --- a/SessionClient.py +++ b/SessionClient.py @@ -40,10 +40,7 @@ def request(self, method: str, path: str, params: dict = None, data: dict = None if not response.status_code in self.STATUS_CODES_TO_PROCESS: errors = data.get('errors', {}) - raise DexilonAPIException( - code=errors.get('code', [0])[0], - message=errors.get('message', [''])[0] - ) + raise DexilonAPIException(response) if response.status_code == 401: raise DexilonAuthException(data) diff --git a/exceptions.py b/exceptions.py index 4b83965..581469f 100644 --- a/exceptions.py +++ b/exceptions.py @@ -1,14 +1,16 @@ +from responses import ErrorBody class DexilonAPIException(Exception): def __init__(self, response): self.code = 0 try: json_res = response.json() + print(json_res) except ValueError: self.message = 'Invalid JSON error message from Dexilon: {}'.format(response.text) else: - self.code = json_res['errors']['code'] - self.message = json_res['errors']['message'] + self.code = json_res['errorBody']['code'] + self.message = json_res['errorBody']['details'] self.status_code = response.status_code self.response = response self.request = getattr(response, 'request', None) @@ -17,6 +19,12 @@ def __str__(self): return 'APIError(code=%s): %s' % (self.code, self.message) +class DexilonErrorBodyException(Exception): + def __init__(self, error_body: ErrorBody): + self.error_body = error_body + + def __str__(self): + return 'ErrorBodyException: %s' % self.error_body class DexilonRequestException(Exception): def __init__(self, message): self.message = message diff --git a/responses.py b/responses.py index 0d15573..886390f 100644 --- a/responses.py +++ b/responses.py @@ -24,14 +24,10 @@ class AvailableSymbol(BaseModel): price24Percentage: Optional[float] -class AddressCosmosMapping(BaseModel): +class CosmosAddressMapping(BaseModel): chainId: int address: str cosmosAddress: str - - -class CosmosAddressMapping(BaseModel): - addressMapping: Optional[AddressCosmosMapping] code: Optional[int] message: Optional[str] diff --git a/tests/authentication_test.py b/tests/authentication_test.py index ed74fa5..9448a9a 100644 --- a/tests/authentication_test.py +++ b/tests/authentication_test.py @@ -1,11 +1,20 @@ +import sys +try: + sys.path.append('/opt/dexbot3/src/') + sys.path.append('/opt/dexbot3/src/dexilon-python-sdk') +except: + print("path not exist") + from DexilonClientImpl import DexilonClientImpl from OrderErrorInfo import OrderErrorInfo from responses import FullOrderInfo class TestAuthentication: - TEST_METAMASK_ADDRESS = '0x201d980aeD5C04a7e75860cFE29CeD9b5da05A08' - TEST_PRIVATE_KEY = '87d25c8ade8c4bb32be098bb35cd594fd1c0511c4423bf36f006f4ecd27f017c' + # TEST_METAMASK_ADDRESS = '0x201d980aeD5C04a7e75860cFE29CeD9b5da05A08' + # TEST_PRIVATE_KEY = '87d25c8ade8c4bb32be098bb35cd594fd1c0511c4423bf36f006f4ecd27f017c' + TEST_METAMASK_ADDRESS = '0x40e42c763Dfd16EF2302c49240040a480a081C3A' + TEST_PRIVATE_KEY = '8abc5ca595d9bb6ebe133936ede1f689450baba2e5a571c2a0e356872a695b28' def setup(self): self.test_instance = DexilonClientImpl(self.TEST_METAMASK_ADDRESS, self.TEST_PRIVATE_KEY) @@ -15,8 +24,7 @@ def setup(self): def test_should_get_cosmos_address_mapping_successfully(self): cosmos_address_maping = self.test_instance.get_cosmos_address_mapping(self.TEST_METAMASK_ADDRESS) assert cosmos_address_maping is not None - assert cosmos_address_maping.addressMapping is not None - + # TODO add asserts def test_should_get_address_not_found_if_there_is_no_mapping(self): cosmos_address_maping = self.test_instance.get_cosmos_address_mapping(self.TEST_METAMASK_ADDRESS + "_WRONG") @@ -50,3 +58,8 @@ def test_should_reauthenticate_on_delete_order(self): self.test_instance.headers['Authorization'] = 'Bearer + ' + self.test_instance.JWT_KEY result = self.test_instance.cancel_order('TESTORDERID1', 'btc_usdc') assert result + +if __name__ == "__main__": + t1 = TestAuthentication() + t1.setup() + t1.test_should_get_cosmos_address_mapping_successfully() \ No newline at end of file