# Zero reward rate calculation impedes low-decimals token distributions

BathBuddy's integer division of reward by duration truncates to zero for low-decimal tokens like WBTC, silently yielding no rewards to stakers.

- Payout: Contest reward
- Severity: medium
- Program: Rubicon
- Credited: 0xNineDec
- Disclosed: 2025-02-17
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-04-rubicon-findings/issues/489
- Library page: https://bugbountylibrary.com/r/c4%3A2023-04-rubicon%3AM-24
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:medium tech:solidity technique:source-review vuln:precision-loss

**Target:** BathBuddy reward distribution contract (notifyRewardAmount)
**Root cause:** rewardRates = reward.div(rewardsDuration) truncates to zero when reward < duration in token base units, so low-decimal tokens (WBTC, 8 decimals) with small amounts produce a zero rate and no rewards accrue.
**Steps:**
1. Deploy BathBuddy with a reward token of 8 decimals (WBTC-like).
2. Call `notifyRewardAmount(parseUnits("0.315", 8), token)` with rewardsDuration = 365 days (31.536e6 s).
3. 315e8 / 31.536e6 = 0 -> rewardRates = 0.
4. Advance time one year, call `bathHouse.claimRewards([buddy], [token])`; balance delta is 0.
5. Repeat with 0.3154e8 -> rate 1, rewards = 31536000 base units.
**How found:** Code-reading of notifyRewardAmount's linear rate formula; noticed integer division truncation and reasoned that arbitrary reward tokens with low decimals and small amounts would floor the rate to zero, then confirmed with a modified hardhat fixture.
**Insight:** When a contract computes rate = amount/duration in token base units, check the smallest feasible amount for low-decimal tokens (WBTC 8, USDC 6): if amount < duration the rate floors to zero and distributions silently pay nothing. Test the boundary amount = duration exactly.
