Repository: rotki/rotki

Issue:
Handle incosistent response from Kraken when user has no balances
## Problem Definition

Related to https://github.com/rotki/rotki/issues/943

Kraken provides an inconsistent response when the user has no balance. All other endpoints if the result is supposed to be empty provide an empty result field.

```
 $ ./krakenapi3 TradesHistory
 {"error":[],"result":{"trades":{},"count":0}}

 $ ./krakenapi3 Ledgers
 {"error":[],"result":{"ledger":{},"count":0}}

 $ ./krakenapi3 OpenOrders
 {"error":[],"result":{"open":{}}}
```
all of which include a result field (along with any secondary fields (trades, count, ledger, open, etc.).

But the balances endpoint returns ` {"error":[]}`

Kraken accepts this as a bug on their side but don't know when it will be fixed, so the incosistency should be in the meantime handled in Rotki.

## Task

Handle the incosistency


Discussion:

Resolving patch:
diff --git a/rotkehlchen/exchanges/kraken.py b/rotkehlchen/exchanges/kraken.py
--- a/rotkehlchen/exchanges/kraken.py
+++ b/rotkehlchen/exchanges/kraken.py
@@ -486,14 +486,17 @@ def _query_private(self, method: str, req: Optional[dict] = None) -> Union[Dict,
     def query_balances(self) -> Tuple[Optional[dict], str]:
         try:
             old_balances = self.api_query('Balance', req={})
-
         except RemoteError as e:
-            msg = (
-                'Kraken API request failed. Could not reach kraken due '
-                'to {}'.format(e)
-            )
-            log.error(msg)
-            return None, msg
+            if "Missing key: 'result'" in str(e):
+                # handle https://github.com/rotki/rotki/issues/946
+                old_balances = {}
+            else:
+                msg = (
+                    'Kraken API request failed. Could not reach kraken due '
+                    'to {}'.format(e)
+                )
+                log.error(msg)
+                return None, msg
 
         balances = {}
         for k, v in old_balances.items():


Test patch:
diff --git a/rotkehlchen/tests/api/test_exchanges.py b/rotkehlchen/tests/api/test_exchanges.py
--- a/rotkehlchen/tests/api/test_exchanges.py
+++ b/rotkehlchen/tests/api/test_exchanges.py
@@ -130,6 +130,7 @@ def test_kraken_malformed_response(rotkehlchen_api_server_with_exchanges):
     """Test that if Rotki gets a malformed response from Kraken it's handled properly
 
     Regression test for the first part of https://github.com/rotki/rotki/issues/943
+    and for https://github.com/rotki/rotki/issues/946
     """
     rotki = rotkehlchen_api_server_with_exchanges.rest_api.rotkehlchen
     kraken = rotki.exchange_manager.get('kraken')
@@ -156,7 +157,7 @@ def mock_kraken_return(url, *args, **kwargs):  # pylint: disable=unused-argument
         contained_in_msg='Could not reach kraken due to Invalid JSON in Kraken response',
     )
 
-    # Test that the response missing result key seen in #943 is handled properly
+    # Test that the response missing result key seen in #946 is handled properly
     response_data = '{"error": []}'
     with kraken_patch:
         response = requests.get(
@@ -166,11 +167,10 @@ def mock_kraken_return(url, *args, **kwargs):  # pylint: disable=unused-argument
                 name='kraken',
             ),
         )
-    assert_error_response(
-        response=response,
-        status_code=HTTPStatus.CONFLICT,
-        contained_in_msg="Missing key: 'result'",
-    )
+    assert_proper_response(response=response)
+    data = response.json()
+    assert data['result'] == {}
+    assert data['message'] == ""
 
 
 def test_setup_exchange_does_not_stay_in_mapping_after_500_error(rotkehlchen_api_server):