Incorrect use of `token.decimals()` leads to error in rewards calculation and distribution
code423n4 opened this issue · 2 comments
Lines of code
https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/miner/ProtocolRewardsPool.sol#L209-L211
https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/miner/ProtocolRewardsPool.sol#L235-L236
Vulnerability details
token.decimals()
is used for scaling up and scaling down amounts instead of 10 ** token.decimals()
. So instead of scaling, it messes up all calculations.
Impact
There are two impacts related to this issue:
- Users receive much less rewards than they should via
ProtocolRewardsPool::getReward()
. ProtocolRewardsPool::notifyRewardAmount()
hugely increases the reward per token stored when external stablecoins are notified as rewards.
Proof of Concept
token.decimals()
is used for scaling up and scaling down amounts instead of 10 ** token.decimals()
. This leads to calculation with huge errors. For example, if the stable token has 18 decimals, it would translate to total = amount * 18
vs total = amount * 1e18
.
In getReward()
, it is used to calculate the tokenAmount
of rewards that the user will receive. In this case token.decimals()
is much lower than 10 ** token.decimals()
, so they will receive an insignificant amount of rewards:
ERC20 token = ERC20(configurator.stableToken());
uint256 tokenAmount = (reward - eUSDShare - peUSDBalance) * token.decimals() / 1e18;
token.transfer(msg.sender, tokenAmount);
ProtocolRewardsPool.sol#L209-L211
In the case of notifyRewardAmount()
, it calculates the rewardPerTokenStored
that will be later used for distributing rewards. Here, it divides by token.decimals()
. This means it will divide by a very small number, leading to a huge result:
ERC20 token = ERC20(configurator.stableToken());
rewardPerTokenStored = rewardPerTokenStored + (amount * 1e36 / token.decimals()) / totalStaked();
ProtocolRewardsPool.sol#L235-L236
Tools Used
Manual Review
Recommended Mitigation Steps
Escale amounts using 10 ** token.decimals()
instead of token.decimals()
.
Assessed type
Math
JeffCX marked the issue as duplicate of #501
0xean marked the issue as satisfactory