# Wrong accounting logic when syncRewards() is called within beforeWithdraw makes withdrawals impossible

sfrxETH.beforeWithdraw decrements storedTotalAssets before syncRewards reads balances, inflating lastRewardAmount and causing permanent underflow that blocks all withdrawals.

- Payout: Contest reward
- Severity: high
- Program: Frax Finance
- Credited: Lambda
- Disclosed: 2022-11-29
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2022-09-frax-findings/issues/15
- Library page: https://bugbountylibrary.com/r/c4%3A2022-09-frax%3AH-01
- Tags: domain:web3 impact:dos impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:dos

**Target:** sfrxETH ERC4626 vault beforeWithdraw/syncRewards
**Root cause:** beforeWithdraw calls xERC4626's beforeWithdraw (decrementing storedTotalAssets) before syncRewards, so syncRewards computes nextRewards = balanceOf - storedTotalAssets - lastRewardAmount with a stale balance and a reduced storedTotalAssets, inflating lastRewardAmount.
**Steps:**
1. Deposit 1 ether frxETH into sfrxETH via `deposit(deposit, address(this))`.
2. `vm.warp(block.timestamp + 1000)` past rewardsCycleEnd.
3. Call `sfrxETHtoken.withdraw(withdraw, address(this), address(this))` — beforeWithdraw decrements storedTotalAssets then calls syncRewards with balance still including the un-transferred assets.
4. `vm.warp(block.timestamp + 1000)` and call `sfrxETHtoken.syncRewards()` — reverts with underflow because lastRewardAmount > asset.balanceOf(address(this)).
**How found:** Code-reading of the beforeWithdraw override ordering: noticed storedTotalAssets is decremented before syncRewards reads asset.balanceOf, so the two are out of sync during the nextRewards computation.
**Exploitation:** Normal user withdrawal after rewardsCycleEnd triggers inflated lastRewardAmount; subsequent syncRewards calls underflow and revert, permanently bricking withdrawals. A user could also exploit inflated lastRewardAmount to over-claim rewards from other depositors.
**Insight:** When overriding ERC4626 hooks, check ordering of state mutations vs. balance reads inside sync/reward functions — a stale balanceOf combined with an already-decremented storedTotalAssets silently inflates reward accounting and can cause permanent underflow.
