Lines of code
<https://github.com/code-423n4/2023-03-wenwin/blob/main/src/Lottery.sol#L249-L257>
<https://github.com/code-423n4/2023-03-wenwin/blob/main/src/LotteryMath.sol#L119-L130>
Anyone can call claimRewards function with rewardType = LotteryRewardType.STAKING, in which function LotteryMath.calculateRewards is used to calculate reward to transfer to beneficiary. By observing number of ticketsSold calculated from the dueTicketsSoldAndReset functionโs two state variableโs - nextTicketId and claimedStakingRewardAtTicketId, such that calculateRewards will return zero. Once such value for ticketsSold is identified, attacker can call claimRewards function with reward type STAKING to update claimedStakingRewardAtTicketId in dueTicketsSoldAndReset function and it will then send zero reward to stakingRewardRecipient.
Attacker can have a script to identify such a value of ticketsSold that will lead to above issue.
#Proof of Concept
<https://github.com/code-423n4/2023-03-wenwin/blob/main/src/Lottery.sol#L249-L257>
<https://github.com/code-423n4/2023-03-wenwin/blob/main/src/LotteryMath.sol#L119-L130>
function claimRewards(LotteryRewardType rewardType) external override returns (uint256 claimedAmount) {
address beneficiary = (rewardType == LotteryRewardType.FRONTEND) ? msg.sender : stakingRewardRecipient;
claimedAmount = LotteryMath.calculateRewards(ticketPrice, dueTicketsSoldAndReset(beneficiary), rewardType);
emit ClaimedRewards(beneficiary, claimedAmount, rewardType);
rewardToken.safeTransfer(beneficiary, claimedAmount);
}
function dueTicketsSoldAndReset(address beneficiary) private returns (uint256 dueTickets) {
if (beneficiary == stakingRewardRecipient) {
dueTickets = nextTicketId - claimedStakingRewardAtTicketId;
claimedStakingRewardAtTicketId = nextTicketId;
} else {
dueTickets = frontendDueTicketSales[beneficiary];
frontendDueTicketSales[beneficiary] = 0;
}
}
function calculateRewards(
uint256 ticketPrice,
uint256 ticketsSold,
LotteryRewardType rewardType
)
internal
pure
returns (uint256 dueRewards)
{
uint256 rewardPercentage = (rewardType == LotteryRewardType.FRONTEND) ? FRONTEND_REWARD : STAKING_REWARD;
dueRewards = (ticketsSold * ticketPrice).getPercentage(rewardPercentage);
}
Assuming ticket prize is 1.5 Dai.
Manual Review
We suggest protocol to have some robust mechanism for claimRewards operation for rewardType = Staking.
The text was updated successfully, but these errors were encountered:
All reactions