The FjordStaking contract uses a fixed precision of 18 decimals for reward calculations, However, this approach can lead to precision loss when distributing rewards in tokens with fewer decimals, such as USDC, potentially resulting in zero rewards being distributed to stakers. An attacker can exploit this precision mismatch by frequently updating the reward calculation, preventing any meaningful reward distribution. As a result, stakers receive zero USDC
Precision Loss: The use of PRECISION_18 in calculations could lead to significant precision loss when dealing with tokens like USDC. This could result in reward-per-token calculations yielding zero, effectively preventing the distribution of rewards.
Frequent Updates: Frequent updates to the reward calculations, especially in a high-activity environment, could exacerbate the issue by continually resetting the reward-per-token to zero due to insufficient precision.
The root cause is the use of a fixed precision constant, PRECISION_18
(1e18), for calculating rewards, assuming all tokens have 18 decimals. When USDC, which has only 6 decimals, is used, the reward calculation leads to significant precision loss, particularly when rewards are updated frequently.
Contract Setup:
Staked Token: USDC (6 decimals).
Staked Amount: 100 USDC.
Epoch Reward Per Token Values:
rewardPerToken[_fromEpoch] = 1e18
(equivalent to 1.0 USDC).
rewardPerToken[_toEpoch] = 1e18 + 1e12
(equivalent to 1.000001 USDC).
Precision Constant:
PRECISION_18 = 1e18
.
Function in Question:
Step-by-Step Calculation:
Step 1: Calculate the difference in rewardPerToken
values between the two epochs.
The difference is 1e12
, which is equivalent to 0.000001 USDC
.
Step 2: Calculate the reward amount using the calculateReward
function.
The calculated rewardAmount
is 1e2
, which represents 100
in the token's smallest unit. For USDC, this corresponds to 0.0001 USDC
.
Step 3: Interpret the result.
The calculated reward of 0.0001 USDC
is extremely small, potentially rounded down to zero, or simply too small to be considered a valid reward. This loss of precision results in the staker receiving either a very small reward or nothing at all.
Expected Outcome:
Small Stakers: If the staker's amount is relatively small, the reward-per-token difference becomes negligible, leading to rewards that are effectively zero.
Impact on Users: The staker may not receive any meaningful reward for staking, leading to frustration and potentially driving them away from using the contract.
The fixed PRECISION_18
constant causes significant precision loss when working with tokens that have fewer than 18 decimals, such as USDC. This precision mismatch leads to rewards being calculated as zero or near-zero, especially for smaller stakers, which disrupts the intended functionality of the contract.
Incorrect Reward Distribution
Small or Zero Rewards for Stakers: Due to the precision mismatch, rewards calculated for stakers might be rounded down to zero or be so small that they are negligible. This particularly affects users who stake smaller amounts, as their calculated rewards might fall below the threshold that the contract can recognize or distribute.
Manual review
To avoid this issue, the contract should be modified to dynamically adjust the precision based on the token's actual decimals, ensuring accurate reward distribution.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.