Repository: rotki/rotki

Issue:
Bitstamp trades, deposits, withdrawals are no longer pulled properly
## Problem Definition

~~I have a bitstamp api key which seems to be unable to pull trades history. More details on the why are still under investigation~~

Bitstamp dev-rugged us :rage: 

They changed the type of an event from an int to a str. So.

`{"type": 0}` -> `{"type": "0"}`

No api version change happened. They just merrily went and changed the response of an already established API endpoint.

So excuse my :fr: French but FUCK YOU Bitstamp.

## Task

Fix it.


Discussion:

Resolving patch:
diff --git a/rotkehlchen/exchanges/bitstamp.py b/rotkehlchen/exchanges/bitstamp.py
--- a/rotkehlchen/exchanges/bitstamp.py
+++ b/rotkehlchen/exchanges/bitstamp.py
@@ -42,6 +42,7 @@
 from rotkehlchen.serialization.deserialize import (
     deserialize_asset_amount,
     deserialize_fee,
+    deserialize_int_from_str,
     deserialize_timestamp_from_bitstamp_date,
 )
 from rotkehlchen.typing import ApiKey, ApiSecret, AssetAmount, Location, Timestamp
@@ -364,7 +365,7 @@ def _api_query(
         else:
             self.session.headers.pop('Content-Type', None)
 
-        log.debug('Bitstamp API request', request_url=request_url)
+        log.debug('Bitstamp API request', request_url=request_url, options=options)
         try:
             response = self.session.request(
                 method=method,
@@ -469,18 +470,20 @@ def _api_query_paginated(
                 return no_results
 
             has_results = False
-            is_result_timesamp_gt_end_ts = False
+            is_result_timestamp_gt_end_ts = False
             result: Union[Trade, AssetMovement]
             for raw_result in response_list:
-                if raw_result['type'] not in raw_result_type_filter:
-                    continue
                 try:
+                    entry_type = deserialize_int_from_str(raw_result['type'], 'bitstamp event')
+                    if entry_type not in raw_result_type_filter:
+                        log.debug(f'Skipping entry {raw_result} due to type mismatch')
+                        continue
                     result_timestamp = deserialize_timestamp_from_bitstamp_date(
                         raw_result['datetime'],
                     )
 
                     if result_timestamp > end_ts:
-                        is_result_timesamp_gt_end_ts = True  # prevent extra request
+                        is_result_timestamp_gt_end_ts = True  # prevent extra request
                         break
 
                     log.debug(f'Attempting to deserialize bitstamp {case_pretty}: {raw_result}')
@@ -502,7 +505,7 @@ def _api_query_paginated(
                 results.append(result)  # type: ignore
                 has_results = True  # NB: endpoint agnostic
 
-            if len(response_list) < limit or is_result_timesamp_gt_end_ts:
+            if len(response_list) < limit or is_result_timestamp_gt_end_ts:
                 break
 
             # NB: update pagination params per endpoint
@@ -534,7 +537,7 @@ def _deserialize_asset_movement(
         Endpoint docs:
         https://www.bitstamp.net/api/#user-transactions
         """
-        type_ = raw_movement['type']
+        type_ = deserialize_int_from_str(raw_movement['type'], 'bitstamp asset movement')
         category: AssetMovementCategory
         if type_ == 0:
             category = AssetMovementCategory.DEPOSIT


Test patch:
diff --git a/rotkehlchen/tests/exchanges/test_bitstamp.py b/rotkehlchen/tests/exchanges/test_bitstamp.py
--- a/rotkehlchen/tests/exchanges/test_bitstamp.py
+++ b/rotkehlchen/tests/exchanges/test_bitstamp.py
@@ -506,7 +506,7 @@ def test_api_query_paginated_skips_different_type_result(mock_bitstamp):
     def mock_api_query_response(endpoint, method, options):  # pylint: disable=unused-argument
         return MockResponse(
             HTTPStatus.OK,
-            '[{"type": "whatever"}, {"type": 23}]',
+            '[{"type": "whatever"}, {"type": "23"}]',
         )
 
     with patch.object(mock_bitstamp, '_api_query', side_effect=mock_api_query_response):
@@ -551,7 +551,7 @@ def test_api_query_paginated_stops_timestamp_gt_end_ts(mock_bitstamp):
     def mock_api_query_response(endpoint, method, options):  # pylint: disable=unused-argument
         return MockResponse(
             HTTPStatus.OK,
-            f'[{{"type": 14, "datetime": "{gt_now_iso}"}}]',
+            f'[{{"type": "14", "datetime": "{gt_now_iso}"}}]',
         )
 
     with patch(
@@ -587,7 +587,7 @@ def test_api_query_paginated_trades_pagination(mock_bitstamp):
     user_transaction_1 = """
     {
         "id": 1,
-        "type": -1,
+        "type": "-1",
         "datetime": "2020-12-02 09:00:00"
     }
     """
@@ -595,7 +595,7 @@ def test_api_query_paginated_trades_pagination(mock_bitstamp):
     user_transaction_2 = """
     {
         "id": 2,
-        "type": 2,
+        "type": "2",
         "datetime": "2020-12-02 09:30:00",
         "btc": "0.50000000",
         "usd": "-10000.00000000",
@@ -608,7 +608,7 @@ def test_api_query_paginated_trades_pagination(mock_bitstamp):
     user_transaction_3 = """
     {
         "id": 3,
-        "type": -1,
+        "type": "-1",
         "datetime": "2020-12-02 18:00:00"
     }
     """
@@ -616,7 +616,7 @@ def test_api_query_paginated_trades_pagination(mock_bitstamp):
     user_transaction_4 = """
     {
         "id": 4,
-        "type": -1,
+        "type": "-1",
         "datetime": "2020-12-03 9:00:00"
     }
     """
@@ -624,7 +624,7 @@ def test_api_query_paginated_trades_pagination(mock_bitstamp):
     user_transaction_5 = """
     {
         "id": 5,
-        "type": 2,
+        "type": "2",
         "datetime": "2020-12-03 11:30:00",
         "eur": "-1.00000000",
         "usd": "1.22000000",
@@ -637,7 +637,7 @@ def test_api_query_paginated_trades_pagination(mock_bitstamp):
     user_transaction_6 = """
     {
         "id": 6,
-        "type": 2,
+        "type": "2",
         "datetime": "2020-12-03 12:00:01",
         "eth": "1.00000000",
         "usdc": "-750.00000000",
@@ -809,7 +809,7 @@ def test_query_online_trade_history(mock_bitstamp, start_ts, since_id):
 def test_deserialize_asset_movement_deposit(mock_bitstamp):
     raw_movement = {
         'id': 2,
-        'type': 0,
+        'type': '0',
         'datetime': '2020-12-02 09:30:00',
         'btc': '0.50000000',
         'usd': '0.00000000',
@@ -836,7 +836,7 @@ def test_deserialize_asset_movement_deposit(mock_bitstamp):
 
     raw_movement = {
         'id': 3,
-        'type': 0,
+        'type': '0',
         'datetime': '2018-03-21 06:46:06.559877',
         'btc': '0',
         'usd': '0.00000000',
@@ -865,7 +865,7 @@ def test_deserialize_asset_movement_deposit(mock_bitstamp):
 def test_deserialize_asset_movement_withdrawal(mock_bitstamp):
     raw_movement = {
         'id': 5,
-        'type': 1,
+        'type': '1',
         'datetime': '2020-12-02 09:30:00',
         'btc': '0.00000000',
         'usd': '-10000.00000000',
@@ -892,7 +892,7 @@ def test_deserialize_asset_movement_withdrawal(mock_bitstamp):
 
     raw_movement = {
         'id': 5,
-        'type': 1,
+        'type': '1',
         'datetime': '2018-03-21 06:46:06.559877',
         'btc': '0',
         'usd': '0',