# The _totalStaked tracker calculation is incorrect and will be inflated due to the improper logic in the writeOffDebt function of the UserManager contract, leading to wrong Comptroller gInflationIndex being calculated and wrong user rewards being issued

UserManager.writeOffDebt subtracts unscaled amount instead of scaled actualAmount from _totalStaked, inflating Comptroller gInflationIndex and corrupting reward accounting.

- Payout: Contest reward
- Severity: high
- Program: Union Finance Update 2
- Credited: KungFuPanda
- Disclosed: 2024-06-12
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2024-06-union-finance-update-2-judging/issues/105
- Library page: https://bugbountylibrary.com/r/sherlock%3A2024-06-union-finance-update-2%3AH-4
- Tags: domain:web3 impact:integrity kind:contest platform:sherlock sev:high tech:solidity technique:source-review vuln:accounting-error vuln:business-logic vuln:precision-loss vuln:reward-distribution

**Target:** UserManager/Comptroller staking reward accounting
**Root cause:** writeOffDebt decrements _totalStaked by the unscaled nominal `amount` rather than the decimal-scaled `actualAmount`, unlike stake/unstake which track scaled amounts.
**Steps:**
1. Note stake/unstake update `_totalStaked` with `decimalScaling(amount, stakingTokenDecimal)` (actualAmount).
2. Call `writeOffDebt` on a staker with debt; observe `_totalStaked -= amount` (unscaled) while `staker.stakedAmount -= actualAmount`.
3. Call unrestricted `batchUpdateFrozenInfo` to push `_totalStaked - _totalFrozen` into `Comptroller.updateTotalStaked`.
4. Comptroller recomputes `gInflationIndex = _getInflationIndexNew(totalStaked, dt)` with the inflated totalStaked, corrupting per-user reward accrual.
**How found:** Code review comparing the new scaled/unscaled amount convention across stake, unstake, and writeOffDebt; spotted writeOffDebt using `amount` instead of `actualAmount` and traced the value into Comptroller's inflation index.
**Exploitation:** No direct theft path; each debtWriteOff silently inflates _totalStaked, and anyone can trigger batchUpdateFrozenInfo to propagate the wrong value into gInflationIndex, mispricing all users' reward accrual.
**Insight:** When a codebase introduces a scaled-vs-nominal amount convention, audit every arithmetic site touching shared accounting counters for the wrong variant; here the mismatch only surfaces via the downstream Comptroller index.
