def test_process_result(): d = { 'overview': { 'foo': FVal(1.0), }, 'all_events': { 'boo': FVal(1.0), 'something': [ {'a': 'a', 'f': FVal(1.0)}, {'b': 'b', 'f': FVal(2.0)}, ], }, } # Without process result should throw an error but with it no with pytest.raises(TypeError): json.dumps(d) json.dumps(process_result(d))
def query_account(self): result_data = { 'makerCommission': 15, 'takerCommission': 15, 'buyerCommission': 0, 'sellerCommission': 0, 'canTrade': True, 'canWithdraw': True, 'canDeposit': True, 'updateTime': 123456789, } balances = [] for asset, value in self.balances_dict.items(): balances.append({ 'asset': asset, 'free': str(value), 'locked': '0.0', }) result_data['balances'] = balances return process_result(result_data)
def query_all_balances( self, save_data: bool, async_query: bool, ignore_cache: bool, ) -> Response: if async_query: return self._query_async( command='_query_all_balances', save_data=save_data, ignore_cache=ignore_cache, ) response = self._query_all_balances(save_data=save_data, ignore_cache=ignore_cache) return api_response( _wrap_in_result(process_result(response['result']), response['message']), HTTPStatus.OK, )
def query_ledgers(self, ledger_type: str): if ledger_type == 'all': result_list = self.deposits_ledger result_list.extend(self.withdrawals_ledger) count = len(self.deposits_ledger) count += len(self.withdrawals_ledger) elif ledger_type == 'deposit': count = len(self.deposits_ledger) result_list = self.deposits_ledger elif ledger_type == 'withdrawal': count = len(self.withdrawals_ledger) result_list = self.withdrawals_ledger else: raise ValueError(f'Invalid ledger_type {ledger_type} requested') ledger_dict = {} for entry in result_list: ledger_dict[entry['refid']] = entry result = {'ledger': ledger_dict, 'count': count} response = {'result': result, 'error': []} return process_result(response)
def _get_transaction_receipt( self, web3: Optional[Web3], tx_hash: EVMTxHash, ) -> Dict[str, Any]: if web3 is None: tx_receipt = self.etherscan.get_transaction_receipt(tx_hash) try: # Turn hex numbers to int block_number = int(tx_receipt['blockNumber'], 16) tx_receipt['blockNumber'] = block_number tx_receipt['cumulativeGasUsed'] = int(tx_receipt['cumulativeGasUsed'], 16) tx_receipt['gasUsed'] = int(tx_receipt['gasUsed'], 16) tx_receipt['status'] = int(tx_receipt.get('status', '0x1'), 16) tx_index = int(tx_receipt['transactionIndex'], 16) tx_receipt['transactionIndex'] = tx_index for receipt_log in tx_receipt['logs']: receipt_log['blockNumber'] = block_number receipt_log['logIndex'] = deserialize_int_from_hex( symbol=receipt_log['logIndex'], location='etherscan tx receipt', ) receipt_log['transactionIndex'] = tx_index except (DeserializationError, ValueError, KeyError) as e: msg = str(e) if isinstance(e, KeyError): msg = f'missing key {msg}' log.error( f'Couldnt deserialize transaction receipt {tx_receipt} data from ' f'etherscan due to {msg}', ) raise RemoteError( f'Couldnt deserialize transaction receipt data from etherscan ' f'due to {msg}. Check logs for details', ) from e return tx_receipt # Can raise TransactionNotFound if the user's node is pruned and transaction is old tx_receipt = web3.eth.get_transaction_receipt(tx_hash) # type: ignore return process_result(tx_receipt)
def process_history( self, from_timestamp: Timestamp, to_timestamp: Timestamp, async_query: bool, ) -> Response: if async_query: return self._query_async( command='_process_history', from_timestamp=from_timestamp, to_timestamp=to_timestamp, ) response = self._process_history( from_timestamp=from_timestamp, to_timestamp=to_timestamp, ) result = response['result'] msg = response['message'] result_dict = _wrap_in_result(result=process_result(result), message=msg) return api_response(result_dict, status_code=HTTPStatus.OK)
def query_blockchain_balances( self, blockchain: Optional[SupportedBlockchain], async_query: bool, ignore_cache: bool, ) -> Response: if async_query: return self._query_async( command='_query_blockchain_balances', blockchain=blockchain, ignore_cache=ignore_cache, ) response = self._query_blockchain_balances( blockchain=blockchain, ignore_cache=ignore_cache, ) result_dict = { 'result': response['result'], 'message': response['message'] } return api_response(process_result(result_dict), status_code=response['status_code'])
def query_exchange_balances( self, name: Optional[str], async_query: bool, ignore_cache: bool, ) -> Response: if async_query: return self._query_async( command='_query_exchange_balances', name=name, ignore_cache=ignore_cache, ) response = self._query_exchange_balances(name=name, ignore_cache=ignore_cache) balances = response['result'] msg = response['message'] if balances is None: return api_response(wrap_in_fail_result(msg), status_code=HTTPStatus.CONFLICT) return api_response(_wrap_in_ok_result(process_result(balances)), HTTPStatus.OK)
def query_netvalue_data(self): res = self.rotkehlchen.data.db.get_netvalue_data() result = {'times': res[0], 'data': res[1]} return process_result(result)
def query_fiat_balances(self): res = self.rotkehlchen.query_fiat_balances() return process_result(res)
def query_blockchain_balances(self): result, empty_or_error = self.rotkehlchen.blockchain.query_balances() return process_result({'result': result, 'message': empty_or_error})
def query_otctrades(self): trades = self.rotkehlchen.data.get_external_trades() result = {'result': trades, 'message': ''} return process_result(result)
def version_check() -> Response: result = _wrap_in_ok_result(check_if_version_up_to_date()) return api_response(process_result(result), status_code=HTTPStatus.OK)
def query_balances(self): response = {'result': self.balances_dict, 'error': []} return process_result(response)
def query_periodic_data(self): """Will query for some client data that can change frequently""" result = self.rotkehlchen.query_periodic_data() return process_result(result)
def query_netvalue_data(self) -> Response: data = self.rotkehlchen.data.db.get_netvalue_data() result = process_result({'times': data[0], 'data': data[1]}) return api_response(_wrap_in_ok_result(result), status_code=HTTPStatus.OK)
def create_new_user( self, name: str, password: str, premium_api_key: str, premium_api_secret: str, ) -> Response: result_dict: Dict[str, Any] = {'result': None, 'message': ''} if self.rotkehlchen.user_is_logged_in: result_dict['message'] = ( f'Can not create a new user because user ' f'{self.rotkehlchen.data.username} is already logged in. ' f'Log out of that user first', ) return api_response(result_dict, status_code=HTTPStatus.CONFLICT) if (premium_api_key != '' and premium_api_secret == '' or premium_api_secret != '' and premium_api_key == ''): result_dict[ 'message'] = 'Must provide both or neither of api key/secret' return api_response(result_dict, status_code=HTTPStatus.BAD_REQUEST) premium_credentials = None if premium_api_key != '' and premium_api_secret != '': try: premium_credentials = PremiumCredentials( given_api_key=premium_api_key, given_api_secret=premium_api_secret, ) except IncorrectApiKeyFormat: result_dict[ 'message'] = 'Provided API/Key secret format is invalid' return api_response(result_dict, status_code=HTTPStatus.BAD_REQUEST) try: self.rotkehlchen.unlock_user( user=name, password=password, create_new=True, # For new accounts the value of sync approval does not matter. # Will always get the latest data from the server since locally we got nothing sync_approval='yes', premium_credentials=premium_credentials, ) # not catching RotkehlchenPermissionError here as for new account with premium # syncing there is no way that permission needs to be asked by the user except (AuthenticationError, PremiumAuthenticationError) as e: self.rotkehlchen.reset_after_failed_account_creation_or_login() result_dict['message'] = str(e) return api_response(result_dict, status_code=HTTPStatus.CONFLICT) # Success! result_dict['result'] = { 'exchanges': self.rotkehlchen.exchange_manager.get_connected_exchange_names(), 'premium': self.rotkehlchen.premium is not None, 'settings': process_result(self.rotkehlchen.data.db.get_settings()), } return api_response(result_dict, status_code=HTTPStatus.OK)
def query_fiat_balances(self) -> Response: balances = self.rotkehlchen.query_fiat_balances() return api_response(_wrap_in_ok_result(process_result(balances)), HTTPStatus.OK)
def test_hexbytes_in_process_result(): expected_str = '{"overview": "0xd4e56740f876aef8c010906a34"}' d = {'overview': HexBytes(b'\xd4\xe5g@\xf8v\xae\xf8\xc0\x10\x90j4')} assert json.dumps(process_result(d)) == expected_str
def get_settings(self) -> Response: result_dict = _wrap_in_ok_result( process_result(self.rotkehlchen.data.db.get_settings())) return api_response(result=result_dict, status_code=HTTPStatus.OK)
def query_owned_assets(self): res = self.rotkehlchen.data.db.query_owned_assets() result = {'result': res, 'message': ''} return process_result(result)
def test_tuple_in_process_result(): d = {'overview': [{'foo': (FVal('0.1'), )}]} # Process result should detect the tuple and throw with pytest.raises(ValueError): json.dumps(process_result(d))
def query_latest_asset_value_distribution(self): res = self.rotkehlchen.data.db.get_latest_asset_value_distribution() result = {'result': res, 'message': ''} return process_result(result)
def unlock_user( self, user: str, password: str, create_new: Union[bool, str], sync_approval: str, api_key: str, api_secret: str, ) -> Dict[str, Any]: """Either unlock an existing user or create a new one""" res = {'result': True, 'message': ''} assert isinstance(sync_approval, str), "sync_approval should be a string" assert isinstance(api_key, str), "api_key should be a string" assert isinstance(api_secret, str), "api_secret should be a string" if not isinstance(create_new, bool): if not isinstance(create_new, str): raise ValueError('create_new can only be boolean or str') if create_new in ('False', 'false', 'FALSE'): create_new = False elif create_new in ('True', 'true', 'TRUE'): create_new = True else: raise ValueError( f'Invalid string value for create_new {create_new}') valid_actions = ['unknown', 'yes', 'no'] if sync_approval not in valid_actions: raise ValueError('Provided invalid value for sync_approval') if api_key != '' and create_new is False: raise ValueError( 'Should not ever have api_key provided during a normal login') if api_key != '' and api_secret == '' or api_secret != '' and api_key == '': raise ValueError('Must provide both or neither of api key/secret') try: self.rotkehlchen.unlock_user( user, password, create_new, sync_approval, api_key, api_secret, ) res['exchanges'] = self.rotkehlchen.exchange_manager.get_connected_exchange_names( ) res['premium'] = self.rotkehlchen.premium is not None res['settings'] = process_result( self.rotkehlchen.data.db.get_settings()) except AuthenticationError as e: res['result'] = False res['message'] = str(e) except RotkehlchenPermissionError as e: res['result'] = False res['permission_needed'] = True res['message'] = str(e) return res
def get_eth_tokens(self): result = { 'all_eth_tokens': self.rotkehlchen.data.eth_tokens, 'owned_eth_tokens': self.rotkehlchen.blockchain.eth_tokens, } return process_result(result)
def get_settings(self): return process_result(self.rotkehlchen.data.db.get_settings())
def test_eth2_result_serialization(): addr1 = make_ethereum_address() addr2 = make_ethereum_address() result = Eth2DepositResult( deposits=[ Eth2Deposit( from_address=addr1, pubkey= '0xb016e31f633a21fbe42a015152399361184f1e2c0803d89823c224994af74a561c4ad8cfc94b18781d589d03e952cd5b', # noqa: E501 withdrawal_credentials= '0x004c7691c2085648f394ffaef851f3b1d51b95f7263114bc923fc5338f5fc499', # noqa: E501 value=Balance(FVal(32), FVal(64)), validator_index=9, tx_hash= '0xd9eca1c2a0c5ff2f25071713432b21cc4d0ff2e8963edc63a48478e395e08db1', log_index=22, timestamp=Timestamp(int(1604506685)), ), Eth2Deposit( from_address=addr2, pubkey= '0xa8ff5fc88412d080a297683c25a791ef77eb52d75b265fabab1f2c2591bb927c35818ac6289bc6680ab252787d0ebab3', # noqa: E501 withdrawal_credentials= '0x00cfe1c10347d642a8b8daf86d23bcb368076972691445de2cf517ff43765817', # noqa: E501 value=Balance(FVal(32), FVal(64)), validator_index=1650, tx_hash= '0x6905f4d1843fb8c003c1fbbc2c8e6c5f9792f4f44ddb1122553412ee0b128da7', log_index=221, timestamp=Timestamp(int(1605043544)), ), ], totals={ addr1: Balance(FVal(1), FVal(1)), addr2: Balance(FVal(2), FVal(2)), }, ) serialized = process_result(result) assert serialized == { 'deposits': [ { 'from_address': addr1, 'pubkey': '0xb016e31f633a21fbe42a015152399361184f1e2c0803d89823c224994af74a561c4ad8cfc94b18781d589d03e952cd5b', # noqa: E501 'withdrawal_credentials': '0x004c7691c2085648f394ffaef851f3b1d51b95f7263114bc923fc5338f5fc499', # noqa: E501 'value': { 'amount': '32', 'usd_value': '64' }, 'validator_index': 9, 'tx_hash': '0xd9eca1c2a0c5ff2f25071713432b21cc4d0ff2e8963edc63a48478e395e08db1', 'log_index': 22, 'timestamp': 1604506685, }, { 'from_address': addr2, 'pubkey': '0xa8ff5fc88412d080a297683c25a791ef77eb52d75b265fabab1f2c2591bb927c35818ac6289bc6680ab252787d0ebab3', # noqa: E501 'withdrawal_credentials': '0x00cfe1c10347d642a8b8daf86d23bcb368076972691445de2cf517ff43765817', # noqa: E501 'value': { 'amount': '32', 'usd_value': '64' }, 'validator_index': 1650, 'tx_hash': '0x6905f4d1843fb8c003c1fbbc2c8e6c5f9792f4f44ddb1122553412ee0b128da7', 'log_index': 221, 'timestamp': 1605043544, }, ], 'totals': { addr1: { 'amount': '1', 'usd_value': '1' }, addr2: { 'amount': '2', 'usd_value': '2' }, }, }
def query_periodic_data(self) -> Response: data = self.rotkehlchen.query_periodic_data() result = process_result(data) return api_response(_wrap_in_ok_result(result), status_code=HTTPStatus.OK)
def get_fiat_exchange_rates(currencies: List[str]): fiat_currencies = cast(List[FiatAsset], currencies) rates = Inquirer().get_fiat_usd_exchange_rates(fiat_currencies) res = {'exchange_rates': rates} return process_result(res)
def query_trade_history(self): trades_length = len(self.trades_dict) response = {'result': {'trades': self.trades_dict, 'count': trades_length}, 'error': []} return process_result(response)