berndartmueller - Destination vault debt can be selectively updated to collect fees on "profits" while ignoring the losses from other destination vaults
Audit: 2023-06-tokemak-judging
Severity: HIGH

berndartmueller

medium

# Destination vault debt can be selectively updated to collect fees on "profits" while ignoring the losses from other destination vaults
## Summary

The `LMPVault.updateDebtReporting` function allows anyone to selectively update the debt of destination vaults, leading to a (temporarily) incomplete `totalDebt` (and `totalIdle`) value. This results in the collection of protocol fees, even though the `LMPVault` potentially has not made any profit, leading to a loss for the users (depositors) of the `LMPVault`.

## Vulnerability Detail

Protocol fees are collected on the `LMPVault`'s profits generated by its destination vaults. The profits are calculated based on the idle funds (`totalIdle`) and the total debt (`totalDebt`). The `totalDebt` and `totalIdle` values are updated whenever destination vaults are rebalanced or by manually calling the `updateDebtReporting` function. This function is publicly callable by anyone and expects an array of destination vaults to update the debt reporting.

As the caller can arbitrarily select which destination vaults to update the debt reporting for ([the vaults have to be valid](https://github.com/sherlock-audit/2023-06-tokemak/blob/main/v2-core-audit-2023-07-14/src/vault/LMPVault.sol#L762-L764)), the caller can purposefully and selectively update the debt reporting for destination vaults that have generated profits, while ignoring the losses from other destination vaults.

This will result in the collection of protocol fees, as it seems that the `LMPVault` made a profit. However, the destination vaults with losses are ignored and not accounted for in the `totalDebt`. Consequently, fees are collected even though the `LMPVault` potentially has not made any profit, leading to a loss for the users (depositors) of the `LMPVault`.

The following test case demonstrates how destination vaults can be purposefully and selectively updated to collect fees on "profits" while ignoring the losses from the other destination vaults:

<details>
  <summary><strong>Test case (click to reveal)</strong></summary>

```diff
diff --git a/v2-core-audit-2023-07-14/test/vault/LMPVault-Withdraw.t.sol b/v2-core-audit-2023-07-14/test/vault/LMPVault-Withdraw.t.sol
index 47b238e..f2d06b9 100644
--- a/v2-core-audit-2023-07-14/test/vault/LMPVault-Withdraw.t.sol
+++ b/v2-core-audit-2023-07-14/test/vault/LMPVault-Withdraw.t.sol
@@ -1047,6 +1047,77 @@ contract LMPVaultMintingTests is Test {
         assertEq(balAfter - balBefore, 900, "actual");
     }

+    function test_IncompleteUpdateDebtReporting() public {
+        _accessController.grantRole(Roles.SOLVER_ROLE, address(this));
+        _accessController.grantRole(Roles.LMP_FEE_SETTER_ROLE, address(this));
+
+        // Configure our fees and where they will go
+        address feeSink = vm.addr(1000);
+        _lmpVault.setFeeSink(feeSink);
+        vm.label(feeSink, "feeSink");
+        _lmpVault.setPerformanceFeeBps(1000); // 10%
+
+        // User is going to deposit