# Incorrect function call leads to stale borrowing fees

GMX's getTotalBorrowingFees used stale cumulativeBorrowingFactor instead of next factor, mispricing market tokens on deposits/withdrawals for LPs.

- Payout: Contest reward
- Severity: high
- Program: Gmx
- Credited: 0xAmanda
- Disclosed: 2022-09-22
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-02-gmx-judging/issues/197
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-02-gmx%3AH-2
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** GMX Synthetics MarketUtils.getTotalBorrowingFees
**Root cause:** getTotalBorrowingFees calls getCumulativeBorrowingFactor (last-updated value) instead of getNextCumulativeBorrowingFactor, so pending borrowing fees accrued since last update are omitted from the fee calculation.
**Steps:**
1. Read MarketUtils.getTotalBorrowingFees: returns openInterest * cumulativeBorrowingFactor - totalBorrowing
2. Note it calls getCumulativeBorrowingFactor, which returns the stored factor without adding durationInSeconds * borrowingFactorPerSecond
3. Compare with getNextCumulativeBorrowingFactor which computes delta = durationInSeconds * borrowingFactorPerSecond and adds it
4. Observe deposit/withdraw valuation paths use getTotalBorrowingFees without prior updateFundingAndBorrowingState, yielding stale fee value
**How found:** Code reading of the fee calculation path: noticed getTotalBorrowingFees used the stored cumulative factor rather than the next (accrued) factor, and that some valuation paths skip updateFundingAndBorrowingState.
**Exploitation:** Not an attacker-driven exploit; stale fee value causes market token valuation mismatch during deposits/withdrawals, letting LPs transact at incorrect prices.
**Insight:** In accumulator-style fee/funding designs, check every read path that computes pending amounts: if it uses the stored accumulator instead of the projected next value, and the caller doesn't force an update first, valuation is stale. Grep for getX vs getNextX pairs.
