The conversion of rewards to PToken is incorrect when the reward token has fewer than 18 decimals
Summary
The conversion formula is given by pTokensToBurn = FixedPointMathLib.divWadUp(amountToClaim, rewardsPerPToken);, where amountToClaim represents the reward amount and rewardsPerPToken denotes the exchange rate. In the FixedPointMathLib library, this formula is expressed as pTokensToBurn = amountToClaim * 1e18 / rewardsPerPToken.
Focusing on the decimals of each variable, rewardsPerPToken has 18 decimals, while amountToClaim shares the same decimal precision as the reward token. In the formula pTokensToBurn = amountToClaim * 1e18 / rewardsPerPToken, the decimals of rewardsPerPToken are effectively canceled by 1e18, resulting in pTokensToBurn having the same decimal precision as amountToClaim, which corresponds to the reward token's decimals.
This creates a potential issue when the reward token has fewer than 18 decimals, as pTokens are intended to maintain 18 decimals.
Vulnerability Detail
Consider the following scenario:
The reward token has 6 decimals, and rewardsPerPToken = 1e18 (indicating a 1:1 ratio of reward to pToken).
Alice calls the redeemRewards() function to claim her rewards by burning her pTokens. She sets amountToClaim to 1e6, which represents $1 worth of the reward token.
Using the formula, pTokensToBurn is calculated as 1e6 * 1e18 / 1e18 = 1e6 (see L191), resulting in the burning of pTokens amounting to 1e6 (see L192).
As a result, Alice claims 1 reward token by burning only pTokens equivalent to 1e6/1e18, despite the exchange rate being 1:1.
function redeemRewards(Claim calldata _claim, address _receiver) public {
...
191 uint256 pTokensToBurn = FixedPointMathLib.divWadUp(amountToClaim, rewardsPerPToken);
192 pTokens[pointsId].burn(msg.sender, pTokensToBurn);
...
}
KupiaSec
High
The conversion of rewards to
PToken
is incorrect when the reward token has fewer than 18 decimalsSummary
The conversion formula is given by
pTokensToBurn = FixedPointMathLib.divWadUp(amountToClaim, rewardsPerPToken);
, whereamountToClaim
represents the reward amount andrewardsPerPToken
denotes the exchange rate. In theFixedPointMathLib
library, this formula is expressed aspTokensToBurn = amountToClaim * 1e18 / rewardsPerPToken
.Focusing on the decimals of each variable,
rewardsPerPToken
has 18 decimals, whileamountToClaim
shares the same decimal precision as the reward token. In the formulapTokensToBurn = amountToClaim * 1e18 / rewardsPerPToken
, the decimals ofrewardsPerPToken
are effectively canceled by1e18
, resulting inpTokensToBurn
having the same decimal precision asamountToClaim
, which corresponds to the reward token's decimals.This creates a potential issue when the reward token has fewer than 18 decimals, as
pToken
s are intended to maintain 18 decimals.Vulnerability Detail
Consider the following scenario:
rewardsPerPToken = 1e18
(indicating a1:1
ratio of reward topToken
).redeemRewards()
function to claim her rewards by burning herpToken
s. She setsamountToClaim
to 1e6, which represents $1 worth of the reward token.pTokensToBurn
is calculated as1e6 * 1e18 / 1e18 = 1e6
(seeL191
), resulting in the burning ofpToken
s amounting to1e6
(seeL192
).As a result, Alice claims 1 reward token by burning only
pToken
s equivalent to1e6/1e18
, despite the exchange rate being1:1
.This issue also occurs in the convertRewardsToPTokens() function.
Impact
Users can claim rewards by burning significantly fewer
pToken
s than they are supposed to.Code Snippet
https://github.com/sherlock-audit/2024-07-sense-points-marketplace/tree/main/point-tokenization-vault/contracts/PointTokenVault.sol#L172-L226
Tool used
Manual Review
Recommendation
The conversion formula should be refined to accurately handle decimals.
Duplicate of #155