# Borrowing fee calculation is inconsistent

Hmx AssetService charges borrowing fees only on rate delta since last checkpoint, so users who skip interactions pay less than active users.

- Payout: Contest reward
- Severity: medium
- Program: Hmx
- Credited: Amar Fares
- Disclosed: 2025-02-17
- Write-up quality: 6/10
- Original: https://cdn.cantina.xyz/reports/cantina_competition_hmx_january2025.pdf#3.2.5
- Library page: https://bugbountylibrary.com/r/cantina%3Ahmx_january2025%3A3.2.5
- Tags: domain:web3 impact:funds-loss kind:contest platform:cantina sev:medium tech:solidity technique:source-review vuln:business-logic vuln:fee-bypass vuln:precision-loss

**Target:** AssetService::_settlePendingBorrowingFee / _receiveBorrowingFeeFromSubaccount
**Root cause:** Fee is computed as (currentRate - lastCheckpointRate) * balance, so intermediate rate hikes are skipped when the user's checkpoint is stale, rather than compounding over each rate change.
**Steps:**
1. Alice balance -100, rate 10%→20%, settle: fee = 10% * 100 = 10, balance -110
2. Rate 20%→30%, settle: fee = 10% * 110 = 11, balance -121; total paid 21
3. Bob balance -100, skips first hike, rate 10%→30%, settle: fee = 20% * 100 = 20, balance -120; total paid 20
4. Compare: identical rate exposure, Bob pays less because no checkpoint between hikes
**How found:** Code review of _settlePendingBorrowingFee early-return and delta-based fee math; constructed two-user scenario with sequential rate hikes to expose the discrepancy.
**Exploitation:** User simply avoids interacting with the protocol across rate hikes so the stale checkpoint collapses multiple increments into one delta, reducing fees owed versus an active user.
**Insight:** When fees accrue on a delta between stored and current rate, check whether the stored checkpoint can go stale across multiple rate updates — the delta collapses and undercharges; compare active vs inactive user paths.
