# Inadequate slippage control

Notional's fCash trade slippage check compared the user's rate limit against the post-trade implied rate instead of the rate actually used in the trade, letting trades execute beyond the user's limit.

- Payout: Contest reward
- Severity: medium
- Program: Notional
- Credited: xiaoming90 + 0xleastwood
- Disclosed: 2023-03-09
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-03-notional-judging/issues/177
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-03-notional%3AM-8
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:medium tech:evm tech:solidity technique:source-review vuln:business-logic

**Target:** fCash trading / InterestRateCurve and TradingAction contracts
**Root cause:** Slippage control in _executeLendBorrowTrade compares rateLimit against market.lastImpliedRate (post-trade rate recomputed from new utilization) rather than the postFeeInterestRate actually used to price the trade, so a transient spike during execution can be masked by the settled rate.
**Steps:**
1. Call executeTrade on a Borrow/Lend fCash trade with a nonzero rateLimit packed in the trade bytes.
2. In _getNetCashAmountsUnderlying, trade is priced at postFeeInterestRate (IR1) derived from pre-trade utilization.
3. After trade, market.totalfCash and totalCashUnderlying are updated and lastImpliedRate (IR2) is recomputed from post-trade utilization.
4. TradingAction checks `market.lastImpliedRate <= rateLimit` (borrow) or `>= rateLimit` (lend) against IR2, not IR1.
5. If IR1 exceeds rateLimit but IR2 resettles at/below it, the trade succeeds despite exceeding the user's acceptable rate.
**How found:** Code review of the trade execution path: noticed the slippage require reads market.lastImpliedRate, which is computed from post-trade utilization, while the actual trade pricing uses postFeeInterestRate computed pre-trade; reasoned the two rates diverge and the check should use the execution rate.
**Exploitation:** A user submits a borrow with a rate limit; during mempool delay the rate spikes so the trade executes at IR1 above the limit, but the post-trade rate IR2 settles back within the limit, so the require passes and the user borrows at a worse rate than intended. Exacerbated for large trades relative to pool liquidity.
**Insight:** When auditing slippage/limit checks, verify the value compared is the same value used to price the trade, not a value recomputed after state mutation; post-trade recomputed rates can mask transient execution-rate spikes.
