# Expired maturities longer than `FixedLib.INTERVAL` with unaccrued earnings may be arbitraged and/or might lead to significant bad debt creation

Market.totalAssets() ignores unaccrued earnings from maturities overdue by more than one INTERVAL, letting attackers sandwich repayments for risk-free arbitrage and leaving bad debt after liquidations.

- Payout: Contest reward
- Severity: medium
- Program: Interest Rate Model
- Credited: 0x73696d616f
- Disclosed: 2024-04-06
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2024-04-interest-rate-model-judging/issues/158
- Library page: https://bugbountylibrary.com/r/sherlock%3A2024-04-interest-rate-model%3AM-15
- Tags: domain:web3 impact:funds-loss impact:integrity kind:contest platform:sherlock sev:medium tech:evm tech:solidity technique:chained technique:source-review vuln:business-logic vuln:liquidation vuln:oracle-manipulation

**Target:** Market.sol totalAssets/repayAtMaturity accounting
**Root cause:** totalAssets() only accrues unassigned earnings for maturities within the current or future INTERVAL, but repayAtMaturity() converts all past unassigned earnings into floatingAssets regardless of how overdue, creating a discrepancy between previewed and actual asset balances.
**Steps:**
1. Deploy Market; ALICE deposits 10_000 ether and borrows at maturity = 2*INTERVAL.
2. skip(maturity + INTERVAL + 1) so the maturity is overdue beyond one INTERVAL.
3. BOB frontruns ALICE's repayment with `market.deposit(assets, BOB)` to capture shares.
4. ALICE calls `market.repayAtMaturity(maturity, max, max, ALICE)`, converting unaccrued earnings into floatingAssets.
5. BOB's `previewRedeem(bobShares)` returns 10046e18 vs 10000e18 deposited — risk-free profit.
6. For bad debt: skip(2*maturity), liquidate ALICE with `market.liquidate(ALICE, max, market)`; leftover shares remain because totalAssets() under-reported, leaving 4005e18 debt uncleared.
**How found:** Code review of totalAssets() accrual window versus repayAtMaturity() conversion logic; noticed past maturities beyond one INTERVAL are excluded from totalAssets but still credited on repayment, then wrote Foundry PoCs for arbitrage and liquidation leftover.
**Exploitation:** Attacker sandwiches a late repayment of an overdue maturity: deposit before the repay to buy shares cheaply, let repayAtMaturity push unaccrued earnings into floatingAssets, then redeem at inflated share price. Separately, liquidators preview seizeAvailable via Auditor.checkLiquidation() using understated totalAssets(), so actual collateral exceeds the preview and leftover collateral blocks full bad-debt cleanup.
**Insight:** When a protocol previews assets/earnings with a time-window filter but settles them unconditionally on a later action, look for a mismatch between the preview path (used by liquidations, share pricing) and the settlement path — sandwiching the settlement action captures the delta.
