# Allowing refreshReward() to fail during minting or buring esLBR could result in gain or loss previously earned reward

esLBR.mint/burn swallow refreshReward() failures via try-catch, letting users mint before reward refresh to inflate earned rewards or be backrun on burn to lose pending rewards.

- Payout: Contest reward
- Severity: medium
- Program: Lybra Finance
- Credited: Kenshin
- Disclosed: 2023-08-21
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-06-lybra-findings/issues/794
- Library page: https://bugbountylibrary.com/r/c4%3A2023-06-lybra%3AM-06
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:race-window technique:source-review vuln:accounting-error vuln:reward-distribution

**Target:** esLBR token mint/burn reward accounting
**Root cause:** esLBR.mint() and burn() wrap refreshReward() in try-catch, so a failing reward-pool update is silently skipped while the balance change still applies, desyncing userRewardPerTokenPaid from actual balance.
**Steps:**
1. Deploy esLBR with Configurator and mock ProtocolRewardsPool; mint 100 esLBR each to exploiter and victim.
2. Set rewardPerTokenStored=2; call `eslbr.mint(victim,100 ether)` while refreshReward works.
3. Force refreshReward to revert; call `eslbr.mint(exploiter,100 ether)` — balance increases but reward checkpoint not updated.
4. Unset revert; call `rewardsPool.refreshReward(exploiter)` and `refreshReward(victim)`; exploiter's earned() exceeds victim's.
5. For burn case: force revert, `eslbr.burn(victim,100 ether)`, then refresh both; victim loses pending rewards.
**How found:** Code review of esLBR.mint/burn noticing try-catch around refreshReward, then reasoning about reward accounting desync when the external call fails; validated with Foundry mock.
**Exploitation:** Attacker mints esLBR while refreshReward is unavailable (e.g., pool paused/reverting), then triggers refreshReward after it recovers so the larger balance is checkpointed against the old rewardPerTokenPaid, capturing rewards they did not accrue. Conversely a searcher backruns a victim's burn with refreshReward(victim) to checkpoint the reduced balance and forfeit the victim's pending rewards.
**Insight:** When a token's balance change is coupled to an external reward checkpoint via try-catch, the failure path leaves userRewardPerTokenPaid stale — look for mint/burn/transfer hooks that can silently skip accounting updates and check whether the skipped update is exploitable by timing the next successful refresh.
