Repository: rotki/rotki

Issue:
Removing an ETH account that has funds in a vault does not always remove those funds from the dashboard
## Problem Definition

Removing an ETH account that has funds in a vault does not always remove those funds from the dashboard. Collateral is removed but liabilities not.

## Task

Fix it


Discussion:
Ha this is still a problem! Seems to remove the collateral but not the liabilities. Wlll fix in v1.17.2

Resolving patch:
diff --git a/rotkehlchen/chain/manager.py b/rotkehlchen/chain/manager.py
--- a/rotkehlchen/chain/manager.py
+++ b/rotkehlchen/chain/manager.py
@@ -658,6 +658,11 @@ def modify_eth_account(
                     self.totals.assets[asset] -= balance
                     if self.totals.assets[asset].amount <= ZERO:
                         self.totals.assets[asset] = Balance()
+
+                for asset, balance in balances.liabilities.items():
+                    self.totals.liabilities[asset] -= balance
+                    if self.totals.liabilities[asset].amount <= ZERO:
+                        self.totals.assets[asset] = Balance()
             self.balances.eth.pop(account, None)
         else:
             raise AssertionError('Programmer error: Should be append or remove')


Test patch:
diff --git a/rotkehlchen/tests/api/test_blockchain.py b/rotkehlchen/tests/api/test_blockchain.py
--- a/rotkehlchen/tests/api/test_blockchain.py
+++ b/rotkehlchen/tests/api/test_blockchain.py
@@ -1414,6 +1414,9 @@ def _remove_blockchain_accounts_test_start(
     token_balances = {A_RDN: ['0', '0', '450000000', '0']}
     eth_balances_after_removal = ['2000000', '4000000']
     token_balances_after_removal = {}
+    starting_liabilities = {A_DAI: ['5555555', '1000000', '0', '99999999']}
+    after_liabilities = {A_DAI: ['1000000', '99999999']}
+
     if query_balances_before_first_modification:
         # Also test by having balances queried before removing an account
         setup = setup_balances(
@@ -1422,6 +1425,7 @@ def _remove_blockchain_accounts_test_start(
             btc_accounts=btc_accounts,
             eth_balances=all_eth_balances,
             token_balances=token_balances,
+            liabilities=starting_liabilities,
         )
         with ExitStack() as stack:
             setup.enter_blockchain_patches(stack)
@@ -1435,6 +1439,7 @@ def _remove_blockchain_accounts_test_start(
         btc_accounts=btc_accounts,
         eth_balances=all_eth_balances,
         token_balances=token_balances,
+        liabilities=starting_liabilities,
     )
 
     # The application has started with 4 ethereum accounts. Remove two and see that balances match
@@ -1458,6 +1463,7 @@ def _remove_blockchain_accounts_test_start(
         eth_balances=eth_balances_after_removal,
         token_balances=token_balances_after_removal,
         also_btc=query_balances_before_first_modification,
+        expected_liabilities=after_liabilities,
     )
     # Also make sure they are removed from the DB
     accounts = rotki.data.db.get_blockchain_accounts()
@@ -1481,6 +1487,7 @@ def _remove_blockchain_accounts_test_start(
         eth_balances=eth_balances_after_removal,
         token_balances=token_balances_after_removal,
         also_btc=True,
+        expected_liabilities=after_liabilities,
     )
 
     return eth_accounts_after_removal, eth_balances_after_removal, token_balances_after_removal
diff --git a/rotkehlchen/tests/utils/blockchain.py b/rotkehlchen/tests/utils/blockchain.py
--- a/rotkehlchen/tests/utils/blockchain.py
+++ b/rotkehlchen/tests/utils/blockchain.py
@@ -76,6 +76,7 @@ def assert_eth_balances_result(
         eth_balances: List[str],
         token_balances: Dict[EthereumToken, List[str]],
         also_btc: bool,
+        expected_liabilities: Dict[EthereumToken, List[str]] = None,
         totals_only: bool = False,
 ) -> None:
     """Asserts for correct ETH blockchain balances when mocked in tests
@@ -117,6 +118,17 @@ def assert_eth_balances_result(
     else:
         totals = result['totals']['assets']
 
+    if expected_liabilities is not None:
+        per_account = result['per_account']['ETH']
+        for token, balances in expected_liabilities.items():
+            total_amount = ZERO
+            for idx, account in enumerate(eth_accounts):
+                amount = FVal(per_account[account]['liabilities'][token.identifier]['amount'])
+                assert amount == FVal(balances[idx])
+                total_amount += amount
+
+            assert FVal(result['totals']['liabilities'][token.identifier]['amount']) == total_amount  # noqa: E501
+
     # Check our owned eth tokens here since the test may have changed their number
     owned_assets = set(rotki.chain_manager.totals.assets.keys())
     if not also_btc:
diff --git a/rotkehlchen/tests/utils/rotkehlchen.py b/rotkehlchen/tests/utils/rotkehlchen.py
--- a/rotkehlchen/tests/utils/rotkehlchen.py
+++ b/rotkehlchen/tests/utils/rotkehlchen.py
@@ -4,10 +4,11 @@
 
 import requests
 
-from rotkehlchen.accounting.structures import BalanceType
+from rotkehlchen.accounting.structures import Balance, BalanceType
 from rotkehlchen.assets.asset import Asset, EthereumToken
 from rotkehlchen.balances.manual import ManuallyTrackedBalance
 from rotkehlchen.constants.assets import A_BTC, A_ETH
+from rotkehlchen.constants.misc import ZERO
 from rotkehlchen.db.utils import DBAssetBalance, LocationData
 from rotkehlchen.fval import FVal
 from rotkehlchen.tests.utils.blockchain import (
@@ -37,6 +38,7 @@ class BalancesTestSetup(NamedTuple):
     beaconchain_patch: _patch
     ethtokens_max_chunks_patch: _patch
     bitcoin_patch: _patch
+    defi_balances_patch: Optional[_patch]
 
     def enter_all_patches(self, stack: ExitStack):
         stack.enter_context(self.poloniex_patch)
@@ -53,6 +55,8 @@ def enter_ethereum_patches(self, stack: ExitStack):
         stack.enter_context(self.etherscan_patch)
         stack.enter_context(self.ethtokens_max_chunks_patch)
         stack.enter_context(self.beaconchain_patch)
+        if self.defi_balances_patch is not None:
+            stack.enter_context(self.defi_balances_patch)
         return stack
 
 
@@ -62,6 +66,7 @@ def setup_balances(
         btc_accounts: Optional[List[BTCAddress]],
         eth_balances: Optional[List[str]] = None,
         token_balances: Optional[Dict[EthereumToken, List[str]]] = None,
+        liabilities: Optional[Dict[EthereumToken, List[str]]] = None,
         btc_balances: Optional[List[str]] = None,
         manually_tracked_balances: Optional[List[ManuallyTrackedBalance]] = None,
         original_queries: Optional[List[str]] = None,
@@ -124,6 +129,37 @@ def setup_balances(
         for token in token_balances:
             eth_map[acc][token] = token_balances[token][idx]
 
+    defi_balances_patch = None
+    if liabilities is not None:
+        def mock_add_defi_balances_to_token_and_totals():
+            # super hacky way of mocking this but well fuck it
+            if len(rotki.chain_manager.balances.eth) == 4:
+                d_liabilities = liabilities.copy()
+            else:  # we know the only test this is used removes index 0 and 2
+                msg = 'Should be at removal of accounts and only have 2 left'
+                assert len(rotki.chain_manager.balances.eth) == 2, msg
+                d_liabilities = {
+                    k: [
+                        x for idx, x in enumerate(v) if idx not in (0, 2)
+                    ] for k, v in liabilities.items()
+                }
+
+            for token, balances in d_liabilities.items():
+                for idx, balance in enumerate(balances):
+                    balance = FVal(balance)
+                    if balance == ZERO:
+                        continue
+
+                    account = ethereum_accounts[idx]
+                    rotki.chain_manager.balances.eth[account].liabilities[token] = Balance(balance)
+                    rotki.chain_manager.totals.liabilities[token] += Balance(balance)
+
+        defi_balances_patch = patch.object(
+            rotki.chain_manager,
+            'add_defi_balances_to_token_and_totals',
+            side_effect=mock_add_defi_balances_to_token_and_totals,
+        )
+
     btc_map: Dict[BTCAddress, str] = {}
     for idx, btc_acc in enumerate(btc_accounts):
         btc_map[btc_acc] = btc_balances[idx]
@@ -176,6 +212,7 @@ def setup_balances(
         ethtokens_max_chunks_patch=ethtokens_max_chunks_patch,
         bitcoin_patch=bitcoin_patch,
         beaconchain_patch=beaconchain_patch,
+        defi_balances_patch=defi_balances_patch,
     )