# repayBorrow calls wrong frozen info update for overdue repayments

UToken.repayBorrow updates frozen info for the borrower instead of the borrower's stakers, leaving stale totalFrozen and miscalculating UNION rewards on debtWriteOff.

- Payout: Contest reward
- Severity: high
- Program: Union Finance
- Credited: hyh
- Disclosed: 2022-11-04
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2022-10-union-finance-judging/issues/143
- Library page: https://bugbountylibrary.com/r/sherlock%3A2022-10-union-finance%3AH-1
- Tags: domain:web3 impact:integrity kind:contest platform:sherlock sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:reward-distribution

**Target:** UToken/UserManager/Comptroller reward accounting
**Root cause:** _repayBorrowFresh calls updateFrozenInfo(borrower,0) on overdue repay, but frozen coin age is derived from a staker's vouchees; borrowers usually have no vouchees, so the staker's frozen state is never refreshed.
**Steps:**
1. Bob (staker) vouches for Alice (borrower) via UserManager, creating vouchees[Bob] entry and vouchers[Alice][idx].
2. Alice borrows from UToken and becomes overdue (block.number - vouch.lastUpdated > overdueBlocks).
3. Alice calls repayBorrow(); _repayBorrowFresh detects isOverdue and calls `IUserManager(userManager).updateFrozenInfo(borrower=Alice, 0)`.
4. getFrozenInfo(Alice) iterates vouchees[Alice] which is empty, so memberFrozen[Bob] and totalFrozen stay stale.
5. Later debtWriteOff(Bob, Alice, amount) runs `comptroller.updateTotalStaked(stakingToken, totalStaked - totalFrozen)` with stale totalFrozen, skewing effectiveAmount in inflation/reward math.
**How found:** Code-reading of _repayBorrowFresh's overdue branch, then tracing updateFrozenInfo -> _updateFrozen -> getFrozenInfo to notice it iterates vouchees[staker], making the borrower argument a noop unless the borrower is also a staker.
**Exploitation:** No direct theft; a staker who assumes repayments refresh frozen info skips batchUpdateFrozenInfo() before debtWriteOff, so Comptroller computes rewards against an inflated totalFrozen, understating effectiveAmount and mis-distributing UNION rewards.
**Insight:** When a state-update helper takes an account argument, verify which side of the relationship the helper actually reads; here frozen age is computed from the staker's vouchees, so passing the borrower silently no-ops. Trace the callee's data source, not the caller's intent.
