# Anyone can drain users' funds due to incorrect rounding direction in MintController

MintController.assetToReceipt rounds convertRatio down before dividing, inflating iUSD minted; repeated mint/redeem drains locked users' funds via negative yield.

- Payout: Contest reward
- Severity: high
- Program: infiniFi
- Credited: bbl4de
- Disclosed: 2025-05-23
- Write-up quality: 7/10
- Original: https://cdn.cantina.xyz/reports/cantina_competition_infinifi_april2025.pdf#3.1.4
- Library page: https://bugbountylibrary.com/r/cantina%3Ainfinifi_april2025%3A3.1.4
- Tags: domain:web3 impact:dos impact:funds-loss kind:contest platform:cantina sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic vuln:precision-loss

**Target:** MintController.assetToReceipt() in Solidity smart contract
**Root cause:** convertRatio = receiptTokenPrice.divWadDown(assetTokenPrice) rounds the denominator down, so the subsequent _assetAmount.divWadDown(convertRatio) effectively rounds up, minting more iUSD than the USDC is worth.
**Steps:**
1. Set oracleIusd price to e.g. 1.0000001e18 with assetPrice 1e30.
2. Alice calls gateway.mint(alice, 100_000e6) with 100k USDC; assetToReceipt returns inflated receipt amount.
3. Farm manager moves USDC from mintController to redeemController.
4. Alice calls yieldSharing.accrue() then gateway.redeem(alice, amountReceipt), receiving back the full 100k USDC.
5. Repeat mint/redeem; each cycle accrues negative yield distributed to locked positions like Bob's, draining them.
**How found:** Code review of FixedPointMathLib rounding conventions: noticed the codebase intends rounding to favor the protocol, then spotted convertRatio rounded down but used as a divisor, inverting the effective rounding direction.
**Exploitation:** Attacker mints iUSD at an inflated rate due to rounding, then redeems for the same USDC amount; the rounding discrepancy is booked as negative yield and socialized to locked stakers, letting the attacker repeat with only gas cost while draining others' funds and forcing _revertIfThereAreUnaccruedLosses() reverts.
**Escalation:** Repeated mint/redeem cycles accumulate unaccrued yield, DoS-ing all functions guarded by _revertIfThereAreUnaccruedLosses() while steadily draining locked positions.
**Insight:** When a rounded intermediate value is later used as a divisor, its rounding direction flips; audit every divWadDown/divWadUp for whether the value feeds a numerator or denominator in the final result.
