# The user who withdraws liquidity from a particular pool is able to claim more rewards than they should by carefully selecting a decreaseShareAmount value such that the virtualRewardsToRemove is rounded down to zero

Salty.IO StakingRewards rounds virtualRewardsToRemove down, letting a user withdraw tiny share amounts to zero it out and claim unearned virtual rewards.

- Payout: Contest reward
- Severity: medium
- Program: Salty.IO
- Credited: Udsen
- Disclosed: 2024-04-19
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2024-01-salty-findings/issues/1021
- Library page: https://bugbountylibrary.com/r/c4%3A2024-01-salty%3AM-01
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:solidity technique:source-review vuln:business-logic vuln:precision-loss vuln:reward-distribution

**Target:** StakingRewards.sol _decreaseUserShare
**Root cause:** virtualRewardsToRemove is computed with integer division that rounds down in the user's favor; with a tiny decreaseShareAmount it truncates to 0, so claimableRewards equals full rewardsForAmount including virtual rewards.
**Steps:**
1. Call `_decreaseUserShare` with a minimal `decreaseShareAmount` (only check is `!= 0`)
2. Ensure `(user.virtualRewards * decreaseShareAmount) / user.userShare` truncates to 0
3. `claimableRewards = rewardsForAmount - 0` pays out virtual rewards
4. Repeat small withdrawals to drain unearned rewards
**How found:** Code reading of _decreaseUserShare noticed the division rounds down in user's favor and that decreaseShareAmount has only a nonzero check, allowing truncation to zero.
**Exploitation:** User repeatedly withdraws dust-sized share amounts so virtualRewardsToRemove rounds to zero each time, collecting rewardsForAmount that includes non-claimable virtual rewards.
**Insight:** When a pro-rata subtraction uses floor division and the input has only a !=0 check, dust-sized inputs can zero out the subtracted term; check rounding direction on every proportional deduction.
