Divide Before Multiply Remediation
Overview
Related Detector: Divide Before Multiply
EVM integer division truncates toward zero. When a formula divides before it multiplies, the truncated intermediate loses precision that the later multiplication then scales up, producing a result that is systematically too small — sometimes zero. In fee, reward, and share-price math this is a real value leak. The remediation is to reorder so multiplication happens first, or to use a full-precision mulDiv.
Recommended Fix
Before (Vulnerable)
// reward = (amount / totalStaked) * rewardPool
// If amount < totalStaked, (amount / totalStaked) truncates to 0 and reward is 0.
function reward(uint256 amount, uint256 totalStaked, uint256 rewardPool)
external pure returns (uint256)
{
return (amount / totalStaked) * rewardPool;
}
After (Fixed — multiply first)
// reward = (amount * rewardPool) / totalStaked
// The division happens last, so the intermediate keeps full precision.
function reward(uint256 amount, uint256 totalStaked, uint256 rewardPool)
external pure returns (uint256)
{
return (amount * rewardPool) / totalStaked;
}
When the numerator amount * rewardPool could itself overflow 256 bits, use a full-precision helper such as OpenZeppelin’s Math.mulDiv(amount, rewardPool, totalStaked), which computes a * b / c without an intermediate overflow.
Common Mistakes
- Fixing one formula but leaving the same pattern in a sibling function (e.g.
depositfixed,withdrawnot). - Reordering to multiply first and introducing an overflow the earlier division was masking; reach for
mulDivwhen operands are large. - Scaling by a fixed-point factor (1e18) after dividing, which does not recover the already-lost precision.