Repository: rotki/rotki

Issue:
Keep getting this error: "local variable 'raw_fee' referenced before assignment"
## Problem Definition

I constantly get this error in my notification panel, possibly every 10 minutes.
![image](https://user-images.githubusercontent.com/30185650/135701789-e68c54c2-7d65-4327-bd0e-18641bab087a.png)

I connected my Coinbase API to rotki, and I don't understand why it keeps giving me this error.
Also see the previous issue I opened: [https://github.com/rotki/rotki/issues/3546](url)

### System Description

Operating system: Windows 10 21H1 19043.1237
Rotki version: 1.21.0

Keep getting this error: "local variable 'raw_fee' referenced before assignment"
## Problem Definition

I constantly get this error in my notification panel, possibly every 10 minutes.
![image](https://user-images.githubusercontent.com/30185650/135701789-e68c54c2-7d65-4327-bd0e-18641bab087a.png)

I connected my Coinbase API to rotki, and I don't understand why it keeps giving me this error.
Also see the previous issue I opened: [https://github.com/rotki/rotki/issues/3546](url)

### System Description

Operating system: Windows 10 21H1 19043.1237
Rotki version: 1.21.0



Discussion:
This is a bug! Nice find! Can you actually also provide us with logs? https://rotki.readthedocs.io/en/latest/contribute.html#id2


You should either email logs to support@rotki.com or DM them to me or any other rotki member in our discord: https://discord.com/invite/aGCxHG7
Need the data from the logs mostly for testing. I am going to fix the issue already since the error makes it obvious where it is.
This is a bug! Nice find! Can you actually also provide us with logs? https://rotki.readthedocs.io/en/latest/contribute.html#id2


You should either email logs to support@rotki.com or DM them to me or any other rotki member in our discord: https://discord.com/invite/aGCxHG7
Need the data from the logs mostly for testing. I am going to fix the issue already since the error makes it obvious where it is.

Resolving patch:
diff --git a/rotkehlchen/exchanges/coinbase.py b/rotkehlchen/exchanges/coinbase.py
--- a/rotkehlchen/exchanges/coinbase.py
+++ b/rotkehlchen/exchanges/coinbase.py
@@ -598,13 +598,19 @@ def _deserialize_asset_movement(self, raw_data: Dict[str, Any]) -> Optional[Asse
             # Only get address/transaction id for "send" type of transactions
             address = None
             transaction_id = None
+            fee = Fee(ZERO)
             # movement_category: Union[Literal['deposit'], Literal['withdrawal']]
             if 'type' in raw_data:
                 # Then this should be a "send" which is the way Coinbase uses to send
                 # crypto outside of the exchange
                 # https://developers.coinbase.com/api/v2?python#transaction-resource
-                msg = 'Non "send" type found in coinbase deposit/withdrawal processing'
-                assert raw_data['type'] == 'send', msg
+                if raw_data['type'] != 'send':
+                    log.error(
+                        f'In a coinbase deposit/withdrawal we got non send type {raw_data["type"]}'
+                        f'. This means either api is broken or we called it wrong',
+                    )
+                    return None
+
                 movement_category = AssetMovementCategory.WITHDRAWAL
                 # Can't see the fee being charged from the "send" resource
 
@@ -612,21 +618,20 @@ def _deserialize_asset_movement(self, raw_data: Dict[str, Any]) -> Optional[Asse
                 asset = asset_from_coinbase(raw_data['amount']['currency'], time=timestamp)
                 # Fees dont appear in the docs but from an experiment of sending ETH
                 # to an address from coinbase there is the network fee in the response
-                fee = Fee(ZERO)
                 raw_network = raw_data.get('network', None)
                 if raw_network:
                     raw_fee = raw_network.get('transaction_fee', None)
 
-                if raw_fee:
-                    # Since this is a withdrawal the fee should be the same as the moved asset
-                    if asset != asset_from_coinbase(raw_fee['currency'], time=timestamp):
-                        # If not we set ZERO fee and ignore
-                        log.error(
-                            f'In a coinbase withdrawal of {asset.identifier} the fee'
-                            f'is denoted in {raw_fee["currency"]}',
-                        )
-                    else:
-                        fee = deserialize_fee(raw_fee['amount'])
+                    if raw_fee:
+                        # Since this is a withdrawal the fee should be the same as the moved asset
+                        if asset != asset_from_coinbase(raw_fee['currency'], time=timestamp):
+                            # If not we set ZERO fee and ignore
+                            log.error(
+                                f'In a coinbase withdrawal of {asset.identifier} the fee'
+                                f'is denoted in {raw_fee["currency"]}',
+                            )
+                        else:
+                            fee = deserialize_fee(raw_fee['amount'])
 
                 if 'network' in raw_data:
                     transaction_id = get_key_if_has_val(raw_data['network'], 'hash')
@@ -635,7 +640,9 @@ def _deserialize_asset_movement(self, raw_data: Dict[str, Any]) -> Optional[Asse
             else:
                 movement_category = deserialize_asset_movement_category(raw_data['resource'])
                 amount = deserialize_asset_amount_force_positive(raw_data['amount']['amount'])
-                fee = deserialize_fee(raw_data['fee']['amount'])
+                if 'fee' in raw_data:
+                    fee = deserialize_fee(raw_data['fee']['amount'])
+
                 asset = asset_from_coinbase(raw_data['amount']['currency'], time=timestamp)
 
             return AssetMovement(
@@ -670,7 +677,7 @@ def _deserialize_asset_movement(self, raw_data: Dict[str, Any]) -> Optional[Asse
             )
             log.error(
                 f'Unexpected data encountered during deserialization of coinbase '
-                f'asset_movement {raw_data}. Error was: {str(e)}',
+                f'asset_movement {raw_data}. Error was: {msg}',
             )
 
         return None


Test patch:
diff --git a/rotkehlchen/tests/exchanges/test_coinbase.py b/rotkehlchen/tests/exchanges/test_coinbase.py
--- a/rotkehlchen/tests/exchanges/test_coinbase.py
+++ b/rotkehlchen/tests/exchanges/test_coinbase.py
@@ -410,6 +410,32 @@ def mock_coinbase_accounts(url, timeout):  # pylint: disable=unused-argument
     },
     "idem": "zzzz",
     "details": {"title": "Sent Ethereum", "subtitle": "To Ethereum address"}
+}, {
+  "id": "id2",
+  "type": "send",
+  "status": "completed",
+  "amount": {
+    "amount": "-0.05770427",
+    "currency": "ETH"
+  },
+  "native_amount": {
+    "amount": "-9.83",
+    "currency": "EUR"
+  },
+  "description": null,
+  "created_at": "2019-08-25T09:42:06Z",
+  "updated_at": "2019-08-25T09:43:42Z",
+  "resource": "transaction",
+  "resource_path": "/v2/accounts/foo/transactions/coo",
+  "instant_exchange": false,
+    "to": {
+      "resource": "ethereum_address",
+      "address": "0x6dcd6449dbca615e40d696328209686ea95327b2",
+      "currency": "ETH",
+      "address_info": {"address": "0xboo"}
+    },
+    "idem": "zzzz",
+    "details": {"title": "Sent Ethereum", "subtitle": "To Ethereum address"}
 }]}"""
 
 
@@ -707,7 +733,7 @@ def test_coinbase_query_deposit_withdrawals(function_scope_coinbase):
     errors = coinbase.msg_aggregator.consume_errors()
     assert len(warnings) == 0
     assert len(errors) == 0
-    assert len(movements) == 3
+    assert len(movements) == 4
     expected_movements = [AssetMovement(
         location=Location.COINBASE,
         category=AssetMovementCategory.DEPOSIT,
@@ -741,6 +767,17 @@ def test_coinbase_query_deposit_withdrawals(function_scope_coinbase):
         fee_asset=A_ETH,
         fee=FVal('0.00021'),
         link='id1',
+    ), AssetMovement(
+        location=Location.COINBASE,
+        category=AssetMovementCategory.WITHDRAWAL,
+        address='0x6dcD6449dbCa615e40d696328209686eA95327b2',
+        transaction_id=None,
+        timestamp=1566726126,
+        asset=A_ETH,
+        amount=FVal('0.05770427'),
+        fee_asset=A_ETH,
+        fee=ZERO,
+        link='id2',
     )]
     assert expected_movements == movements