Repository: rotki/rotki

Issue:
Binance withdrawals don't include fees
For all deposits to Binance the transaction fee is listed as zero. I could correct this by manually adding a ledger action, or adding a blockchain balance. However not all blockchains are supported.

Could Rotki take the txid for the asset and query the fee that was paid to make the deposit?

Should I add blockchain balances for the supported assets BTC, ETH and manually add ledger actions for the others?


Discussion:
The Binance withdrawals in Rotki also don't include the fee which is listed in the CSV from Binance.
The deposit fee is not the same as the transaction gas fee of the deposit. It's possible for the exchange to also add an extra deposit fee on top, which is what that field is for. Binances does not do that.

If you want to count the transaction gas fee (for ehereum) of the deposit, then that should already be counted if you are tracking the ethereum address that makes the deposit.

> The Binance withdrawals in Rotki also don't include the fee which is listed in the CSV from Binance.

Now as for withdrawals, at the time that we coded the integration of binance the API did not include any withdrawal fees. I checked again today, and it seems they now added them: https://binance-docs.github.io/apidocs/spot/en/#withdraw-history-user_data

Which is great news because that means, we can actually include those in the withdrawals as read by rotki.

Is it okay with you if we keep this issue for adding the binance withdrawal fee only? For deposits you can do what I suggested above as binance does not charge (or include in their [api](https://binance-docs.github.io/apidocs/spot/en/#deposit-history-user_data)) anything extra for deposits.
That's great news it's supported now.

I think it's fine to keep this issue for withdrawal only.

To support deposits fees via the txid from the import you'd have to compare with txid's already tracked in Rotki. Do you want to create a separate issue for this?
> To support deposits fees via the txid from the import you'd have to compare with txid's already tracked in Rotki. Do you want to create a separate issue for this?

By default if you have "gas costs" settings on all transactions gas fees are counted. So you can achieve this by activating that setting. And if you want to ignore some transactions from the history you can ignore them and their gas costs would not be included.
> > To support deposits fees via the txid from the import you'd have to compare with txid's already tracked in Rotki. Do you want to create a separate issue for this?
> 
> By default if you have "gas costs" settings on all transactions gas fees are counted. So you can achieve this by activating that setting. And if you want to ignore some transactions from the history you can ignore them and their gas costs would not be included.

You currently only support 3 assets so looking up this information using the txid from Binance would help. All other transactions would have to be manual though. It's just an idea because if you have 100's of transactions and trades, one would like that the balance Rotki calculates at the end for that asset equals the actual balance.
> You currently only support 3 assets so looking up this information using the txid from Binance would help

What do you mean by support 3 assets?

We are talking about the ethereum gas fee here, right? So always about ETH. And you want to detect how much ETH was spent as gas for the binance deposits? Then as I said above if you activate the gas cost to count those fees. Am I understanding what you need correctly?

This should also reduce the ethereum amount as counted in the cost basis and accounting of what you should have now.
Or ... now that I look at it it should. But is not. Which means I need to push a fix.
Sorry I was not clear - I'm was not talking about Ethereum.

I'm talking about all the other coins e.g. BCH that someone might add to Rotki which Rotki does not support natively like ETH or BTC.

`Could Rotki take the txid for the asset and query the fee that was paid to make the deposit?`
 - This means could Rotki take the txid from Binance and query a block explorer for that asset to get the deposit fee (for blockchains that Rotki doesn't support fully yet).

Do you also need to apply the same cost basis fix (when fee is spent) for other transactions that are not ETH?
> This means could Rotki take the txid from Binance and query a block explorer for that asset to get the deposit fee (for blockchains that Rotki doesn't support fully yet).

I now understand what you mean @a7e8. No that's unfortunately not possible for blockchains of which we don't handle native transactions. And the only one we do now is ethereum. With soon to come also bitcoin and kusama.
Yeah it was just a hopeful idea because the txid is in the data from Binance.

Perhaps you can allow edits of the entries that are imported so that we can manually add the fees? Otherwise you have two entries, one just for the fee component.
> Perhaps you can allow edits of the entries that are imported so that we can manually add the fees?

That's a valid request. A bit more complicated than it sounds since we don't allow editing of any imported data at the moment but it can in theory be done to satisfy this use case. Can you make another issue for this and we keep this one for the specific issue of:

> Is it okay with you if we keep this issue for adding the binance withdrawal fee only? For deposits you can do what I suggested above as binance does not charge (or include in their api) anything extra for deposits.


Sure https://github.com/rotki/rotki/issues/2482

Resolving patch:
diff --git a/rotkehlchen/exchanges/binance.py b/rotkehlchen/exchanges/binance.py
--- a/rotkehlchen/exchanges/binance.py
+++ b/rotkehlchen/exchanges/binance.py
@@ -932,9 +932,11 @@ def _deserialize_asset_movement(self, raw_data: Dict[str, Any]) -> Optional[Asse
             if 'insertTime' in raw_data:
                 category = AssetMovementCategory.DEPOSIT
                 time_key = 'insertTime'
+                fee = Fee(ZERO)
             else:
                 category = AssetMovementCategory.WITHDRAWAL
                 time_key = 'applyTime'
+                fee = Fee(deserialize_asset_amount(raw_data['transactionFee']))
 
             timestamp = deserialize_timestamp_from_binance(raw_data[time_key])
             asset = asset_from_binance(raw_data['asset'])
@@ -947,8 +949,7 @@ def _deserialize_asset_movement(self, raw_data: Dict[str, Any]) -> Optional[Asse
                 asset=asset,
                 amount=deserialize_asset_amount_force_positive(raw_data['amount']),
                 fee_asset=asset,
-                # Binance does not include withdrawal fees neither in the API nor in their UI
-                fee=Fee(ZERO),
+                fee=fee,
                 link=str(raw_data['txId']),
             )
 


Test patch:
diff --git a/rotkehlchen/tests/exchanges/test_binance.py b/rotkehlchen/tests/exchanges/test_binance.py
--- a/rotkehlchen/tests/exchanges/test_binance.py
+++ b/rotkehlchen/tests/exchanges/test_binance.py
@@ -530,6 +530,7 @@ def check_permutations_of_input_invalid_data(deposits, withdrawals):
         {
             "id":"7213fea8e94b4a5593d507237e5a555b",
             "amount": 0.04670582,
+            "transactionFee": 0.01,
             "address": "0x6915f16f8791d0a1cc2bf47c13a6b2a92000504b",
             "asset": "ETH",
             "txId": "0xdf33b22bdb2b28b1f75ccd201a4a4m6e7g83jy5fc5d5a9d1340961598cfcb0a1",
diff --git a/rotkehlchen/tests/utils/exchanges.py b/rotkehlchen/tests/utils/exchanges.py
--- a/rotkehlchen/tests/utils/exchanges.py
+++ b/rotkehlchen/tests/utils/exchanges.py
@@ -313,26 +313,30 @@
     "withdrawList": [
         {
             "id":"7213fea8e94b4a5593d507237e5a555b",
-            "amount": 1,
+            "withdrawOrderId": null,
+            "amount": 0.99,
+            "transactionFee": 0.01,
             "address": "0x6915f16f8791d0a1cc2bf47c13a6b2a92000504b",
             "asset": "ETH",
             "txId": "0xdf33b22bdb2b28b1f75ccd201a4a4m6e7g83jy5fc5d5a9d1340961598cfcb0a1",
-            "applyTime": 1508488245000,
+            "applyTime": 1508198532000,
             "status": 4
         },
         {
             "id":"7213fea8e94b4a5534ggsd237e5a555b",
-            "amount": 850.1,
-            "address": "463tWEBn5XZJSxLU34r6g7h8jtxuNcDbjLSjkn3XAXHCbLrTTErJrBWYgHJQyrCwkNgYvyVz8",
+            "withdrawOrderId": "withdrawtest",
+            "amount": 999.9999,
+            "transactionFee": 0.0001,
+            "address": "463tWEBn5XZJSxLU34r6g7h8jtxuNcDbjLSjkn3XAXHCbLrTTErJrBWYgHJQyrCwkNgYvyV3z8zctJLPCZy24jvb3NiTcTJ",
             "addressTag": "342341222",
             "txId": "b3c6219639c8ae3f9cf010cdc24fw7f7yt8j1e063f9b4bd1a05cb44c4b6e2509",
             "asset": "XMR",
-            "applyTime": 1508512521000,
+            "applyTime": 1508198532000,
             "status": 4
         }
     ],
     "success": true
-}"""
+}"""  # noqa: E501
 
 
 def assert_binance_balances_result(balances: Dict[str, Any]) -> None:
@@ -362,19 +366,19 @@ def assert_binance_asset_movements_result(movements: List[AssetMovement], locati
 
     assert movements[2].location == location
     assert movements[2].category == AssetMovementCategory.WITHDRAWAL
-    assert movements[2].timestamp == 1508488245
+    assert movements[2].timestamp == 1508198532
     assert isinstance(movements[2].asset, Asset)
     assert movements[2].asset == A_ETH
-    assert movements[2].amount == FVal('1')
-    assert movements[2].fee == ZERO
+    assert movements[2].amount == FVal('0.99')
+    assert movements[2].fee == FVal('0.01')
 
     assert movements[3].location == location
     assert movements[3].category == AssetMovementCategory.WITHDRAWAL
-    assert movements[3].timestamp == 1508512521
+    assert movements[3].timestamp == 1508198532
     assert isinstance(movements[3].asset, Asset)
     assert movements[3].asset == A_XMR
-    assert movements[3].amount == FVal('850.1')
-    assert movements[3].fee == ZERO
+    assert movements[3].amount == FVal('999.9999')
+    assert movements[3].fee == FVal('0.0001')
 
 
 def assert_poloniex_balances_result(balances: Dict[str, Any]) -> None: