# Edge case breaks APR cap calculation and leads to excessive fee extraction from the pool

Integer division in Blend fee vault's update_rate zeroes target growth for small time_elapsed or low APR, causing 100% of interest to be taken as fees.

- Payout: Contest reward
- Severity: medium
- Program: Blend
- Credited: Sparrow
- Disclosed: 2025-08-13
- Write-up quality: 6/10
- Original: https://code4rena.com/reports/2025-02-blend-v2-audit-certora-formal-verification#m-15
- Library page: https://bugbountylibrary.com/r/c4%3A2025-02-blend-v2-audit-certora-formal-verification%3AM-15
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:solidity technique:source-review vuln:accounting-error vuln:fee-bypass vuln:precision-loss

**Target:** Soroban fee vault reserve_vault update_rate
**Root cause:** target_growth_rate = 100_000 * target_apr * time_elapsed / SECONDS_PER_YEAR + SCALAR_12 truncates to SCALAR_12 when the numerator is below SECONDS_PER_YEAR, so target_b_rate equals the old b_rate and all growth is treated as above-cap fees.
**Steps:**
1. Configure vault in APR-capped mode with target_apr=0_0100000 (1%).
2. Set ledger timestamp 30s after last_update_timestamp.
3. Set new b_rate to 1_000_050_000_000 (0.005% growth, below 1% APR cap).
4. Call update_rate; observe 100_000*0_0100000*30/31_536_000 = 0, target_growth_rate = SCALAR_12.
5. target_b_rate = b_rate, so fee = total_b_tokens * (new_rate - target_b_rate)/new_rate, extracting all growth.
**How found:** Reading update_rate's scaled integer math and noticing the product 100_000*target_apr*time_elapsed can fall below SECONDS_PER_YEAR, making integer division yield zero and collapsing the target growth rate to 1.0.
**Insight:** When auditing scaled fixed-point APR/fee math, check whether the numerator can be smaller than the denominator for realistic low-rate/short-interval inputs; truncation to the scalar baseline silently converts a cap into a 100% fee.
