Repository: rotki/rotki

Issue:
Errors retrieving KuCoin trades
## Problem Definition

Received the following errors, when trades were being retrieved from the KuCoin exchange:

"Backend messages"
`Query history of kucoin exchange died with exception: Expected either FVal or int.. Check the logs for more details`

"Trades for KuCoin"
`Failed query for KuCoin: Error: The backend query task died unexpectedly: Expected either FVal or int.`

![image](https://user-images.githubusercontent.com/1310982/108278782-83a34a00-7149-11eb-85d3-9ec9e893486b.png)

Steps:

1. Added KuCoin exchange.
2. Switched to dashboard and saw KuCoin balances.
3. Clicked History -> Trades and the process began to retrieve the trades.
4. The "Backend messages" error appeared in the Notifications, after about a minute.
5. The "Trades for KuCoin" error appeared, after a couple of minutes.
6. Closed the application and restarted it, with Debug logging.
7. Clicked History -> Trades again and received the same errors. 


## Logs

Log files attached (but deleted from lefteris)

1. rotkehlchen.log
2. rotki_electron.log


### System Description


Operating system: Windows 10 64-bit
Rotki version: 1.14.0




Discussion:
Hey @bgibbsjr thanksa lot for the report. I am deleting the logs from the issue as they may contain sensitive info.

I can see where the problem is from the logs.

For some reason Kucoin for your account sends some data differently than we expect and does not agree with their api docs. Will analyze the problem and figure out a solution. It will be included in the next release.
Thank-you!

Resolving patch:
diff --git a/rotkehlchen/exchanges/binance.py b/rotkehlchen/exchanges/binance.py
--- a/rotkehlchen/exchanges/binance.py
+++ b/rotkehlchen/exchanges/binance.py
@@ -292,6 +292,12 @@ def api_query(
             method: str,
             options: Optional[Dict] = None,
     ) -> Union[List, Dict]:
+        """Performs a binance api query
+
+        May raise:
+         - RemoteError
+         - BinancePermissionError
+        """
         call_options = options.copy() if options else {}
 
         while True:
@@ -336,7 +342,7 @@ def api_query(
                 elif api_type == 'api' and method in V1_METHODS:
                     api_version = 1
                 else:
-                    raise ValueError(f'Unexpected {self.name} API method {method}')
+                    raise AssertionError(f'Unexpected {self.name} API method {method}')
 
                 api_subdomain = api_type if is_new_futures_api else 'api'
                 request_url = (
@@ -423,6 +429,7 @@ def api_query_dict(
             method: str,
             options: Optional[Dict] = None,
     ) -> Dict:
+        """May raise RemoteError and BinancePermissionError due to api_query"""
         result = self.api_query(api_type, method, options)
         assert isinstance(result, Dict)  # pylint: disable=isinstance-second-argument-not-valid-type  # noqa: E501
         return result
@@ -433,6 +440,7 @@ def api_query_list(
             method: str,
             options: Optional[Dict] = None,
     ) -> List:
+        """May raise RemoteError and BinancePermissionError due to api_query"""
         result = self.api_query(api_type, method, options)
         assert isinstance(result, List)  # pylint: disable=isinstance-second-argument-not-valid-type  # noqa: E501
         return result
@@ -709,6 +717,12 @@ def query_online_trade_history(
             end_ts: Timestamp,
             markets: Optional[List[str]] = None,
     ) -> List[Trade]:
+        """
+
+        May raise due to api query and unexpected id:
+        - RemoteError
+        - BinancePermissionError
+        """
         self.first_connection()
 
         if not markets:
@@ -737,7 +751,13 @@ def query_online_trade_history(
                         # 'endTime': end_ts * 1000,
                     })
                 if result:
-                    last_trade_id = result[-1]['id'] + 1
+                    try:
+                        last_trade_id = int(result[-1]['id']) + 1
+                    except (ValueError, KeyError, IndexError) as e:
+                        raise RemoteError(
+                            f'Could not parse id from Binance myTrades api query result: {result}',
+                        ) from e
+
                 len_result = len(result)
                 log.debug(f'{self.name} myTrades query result', results_num=len_result)
                 for r in result:
diff --git a/rotkehlchen/exchanges/kucoin.py b/rotkehlchen/exchanges/kucoin.py
--- a/rotkehlchen/exchanges/kucoin.py
+++ b/rotkehlchen/exchanges/kucoin.py
@@ -605,7 +605,7 @@ def _deserialize_trade(
             rate=rate,
             fee=fee,
             fee_currency=fee_currency,
-            link=trade_id,
+            link=str(trade_id),
             notes='',
         )
         return trade
diff --git a/rotkehlchen/utils/serialization.py b/rotkehlchen/utils/serialization.py
--- a/rotkehlchen/utils/serialization.py
+++ b/rotkehlchen/utils/serialization.py
@@ -87,6 +87,8 @@ def rkl_decode_value(
                 (k == 'name' and isinstance(value, (FVal, int))) or
                 (k == 'symbol' and isinstance(value, (FVal, int))) or
                 (k == 'baseAsset' and isinstance(value, (FVal, int))) or
+                (k == 'tradeId' and isinstance(value, (FVal, int))) or
+                (k == 'id' and isinstance(value, (FVal, int))) or
                 (k == 'quoteAsset' and isinstance(value, (FVal, int)))
             )
             if should_not_be_fval:


Test patch: