Platform: Code4rena
Start Date: 06/03/2023
Pot Size: $36,500 USDC
Total HM: 8
Participants: 93
Period: 3 days
Judge: cccz
Total Solo HM: 3
Id: 218
League: ETH
Rank: 28/93
Findings: 1
Award: $169.80
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: adriro
Also found by: 0x1f8b, 0xAgro, 0xSmartContract, 0xfuje, 0xkazim, 0xnev, Aymen0909, Bason, Cyfrin, DadeKuma, LethL, Madalad, MohammedRizwan, Rolezn, SAAJ, SunSec, Udsen, Yukti_Chinta, ast3ros, bin2chen, brgltd, bshramin, btk, bugradar, catellatech, cryptostellar5, descharre, dontonka, erictee, fatherOfBlocks, georgits, glcanvas, hl_, horsefacts, igingu, juancito, lukris02, martin, nadin, nomoi, peanuts, pipoca, sakshamguruji, seeu, slvDev, tnevler, zaskoh
169.7989 USDC - $169.80
Context:
/// @param rewardType 0 - staking reward, 1 - frontend reward.
L72
Recommendation:
https://github.com/code-423n4/2023-03-wenwin/blob/main/src/interfaces/ILottery.sol#L44
It should be like this:
/// @param rewardType 0 - frontend reward, 1 - staking reward.
Context:
Recommendation: Check that _maxFailedAttempts and _maxRequestDelay is not too small.
Context:
uint256 private constant MAX_MAX_FAILED_ATTEMPTS = 10;
L19
Recommendation:
Change to uint256 private constant MAX_FAILED_ATTEMPTS = 10;
Context:
modifier requireValidTicket(uint256 ticket) {
L44 (Change to uint120. Here ticket is uint120)uint256 ticket,
L18 (Change to uint120)Description:
According TicketUtils.sol /// Ticket is represented as uint120 packed ticket:
Context:
nonJackpotFixedRewards = packFixedRewards(lotterySetupParams.fixedRewards);
L91
Description:
The user can make a mistake in the order of rewards.
Recommendation:
Check that each next reward is greater than the previous one.
Context:
uint16 reward = uint16(rewards[winTier] / divisor);
L170currentNetProfit += int256(unclaimedJackpotTickets * winAmount[drawId][selectionSize]);
L275unclaimedTickets[currentDraw][referrer].referrerTicketCount += uint128(numberOfTickets);
L69unclaimedTickets[currentDraw][player].playerTicketCount += uint128(numberOfTickets);
L71newProfit = oldProfit + int256(ticketsSalesToPot);
L48newProfit -= int256(expectedRewardsOut);
L55excessPotInt -= int256(fixedJackpotSize);
L64excessPot = excessPotInt > 0 ? uint256(excessPotInt) : 0;
L65Description: While Solidity 0.8.x checks for overflows on arithmetic operations, it does not do so for casting.
Recommendation: Use OpenZeppelin’s SafeCast library to prevent unexpected overflows.
Context:
return rewardPerTokenStored;
L51return rewardPerTokenStored + (unclaimedRewards * 1e18 / _totalSupply);
L58return balanceOf(account) * (rewardPerToken() - userRewardPerTokenPaid[account]) / 1e18 + rewards[account];
L62return _baseJackpot(initialPot);
L122return 0;
L124return extracted * (10 ** (IERC20Metadata(address(rewardToken)).decimals() - 1));
L128return drawRewardSize(currentDraw, winTier);
L235return LotteryMath.calculateReward(
L239return totalTicketsSoldPrevDraw.getPercentage(PercentageMath.ONE_PERCENT);
L119return totalTicketsSoldPrevDraw.getPercentage(PercentageMath.ONE_PERCENT * 75 / 100);
L123return totalTicketsSoldPrevDraw.getPercentage(PercentageMath.ONE_PERCENT * 50 / 100);
L127return playerRewardFirstDraw > decrease ? (playerRewardFirstDraw - decrease) : 0;
L158return rewardsToReferrersPerDraw[Math.min(rewardsToReferrersPerDraw.length - 1, drawId)];
L162return number * percentage / PERCENTAGE_BASE;
L18return number * int256(percentage) / int256(PERCENTAGE_BASE);
L23return (ticketSize == selectionSize) && (ticket == uint256(0));
L32Recommendation:
Choose named return variable or return statement. It is unnecessary to use both.
Context:
function requestRandomnessFromUnderlyingSource() internal override returns (uint256 requestId) {
L28 (requestRandomnessFromUnderlyingSource should start with_)function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override {
L32 (fulfillRandomWords should start with_)uint256 internal immutable firstDrawSchedule;
L26 (firstDrawSchedule should start with_)uint256 private immutable nonJackpotFixedRewards;
L34 (nonJackpotFixedRewards should start with_)uint256 private constant BASE_JACKPOT_PERCENTAGE = 30_030; // 30.03%
L36 (BASE_JACKPOT_PERCENTAGE should start with_)function packFixedRewards(uint256[] memory rewards) private view returns (uint256 packed) {
L164 (packFixedRewards should start with_)uint256 private claimedStakingRewardAtTicketId;
L25 (claimedStakingRewardAtTicketId should start with_)mapping(address => uint256) private frontendDueTicketSales;
L26 (frontendDueTicketSales should start with_)mapping(uint128 => mapping(uint120 => uint256)) private unclaimedCount;
L27 (unclaimedCount should start with_)function registerTicket(
L181 (registerTicket should start with_)function receiveRandomNumber(uint256 randomNumber) internal override onlyWhenExecutingDraw {
L203 (receiveRandomNumber should start with_)function drawRewardSize(uint128 drawId, uint8 winTier) private view returns (uint256 rewardSize) {
L238 (drawRewardSize should start with_)function dueTicketsSoldAndReset(address beneficiary) private returns (uint256 dueTickets) {
L249 (dueTicketsSoldAndReset should start with_)function claimWinningTicket(uint256 ticketId) private onlyTicketOwner(ticketId) returns (uint256 claimedAmount) {
L259 (claimWinningTicket should start with_)function returnUnclaimedJackpotToThePot() private {
L271 (returnUnclaimedJackpotToThePot should start with_)function requireFinishedDraw(uint128 drawId) internal view override {
L279 (requireFinishedDraw should start with_)function mintNativeTokens(address mintTo, uint256 amount) internal override {
L285 (mintNativeTokens should start with_)function markAsClaimed(uint256 ticketId) internal {
L19 (markAsClaimed should start with_)address internal immutable authorizedConsumer;
L8 (authorizedConsumer should start with _)mapping(uint256 => RandomnessRequest) internal requests;
L9 (requests should start with _)function fulfill(uint256 requestId, uint256 randomNumber) internal {
L33 (fulfill should start with _)function requestRandomnessFromUnderlyingSource() internal virtual returns (uint256 requestId);
L48 (requestRandomnessFromUnderlyingSource should start with _)uint256 private constant MAX_MAX_FAILED_ATTEMPTS = 10;
L19 (MAX_MAX_FAILED_ATTEMPTS should start with_)uint256 private constant MAX_REQUEST_DELAY = 5 hours;
L20 (MAX_REQUEST_DELAY should start with_)function requestRandomNumber() internal {
L38 (requestRandomNumber should start with_)function receiveRandomNumber(uint256 randomNumber) internal virtual;
L58 (receiveRandomNumber should start with_)function requestRandomNumberFromSource() private {
L106 (requestRandomNumberFromSource should start with_)function referralRegisterTickets(
L52 (referralRegisterTickets should start with_)function mintNativeTokens(address mintTo, uint256 amount) internal virtual;
L74 (mintNativeTokens should start with_)function referralDrawFinalize(uint128 drawFinalized, uint256 ticketsSoldDuringDraw) internal {
L87 (referralDrawFinalize should start with_)function getMinimumEligibleReferralsFactorCalculation(uint256 totalTicketsSoldPrevDraw)
L111 (getMinimumEligibleReferralsFactorCalculation should start with_)function requireFinishedDraw(uint128 drawId) internal view virtual;
L134 (requireFinishedDraw should start with_)function claimPerDraw(uint128 drawId) private returns (uint256 claimedReward) {
L136 (claimPerDraw should start with_)function playerRewardsPerDraw(uint128 drawId) internal view returns (uint256 rewards) {
L156 (playerRewardsPerDraw should start with_)function referrerRewardsPerDraw(uint128 drawId) internal view returns (uint256 rewards) {
L161 (referrerRewardsPerDraw should start with_)Description:
The above codes don't follow Solidity's standard naming convention.
Context:
modifier requireJackpotInitialized() {
L104 (modifier definition can not go after constructor)function onRandomNumberFulfilled(uint256 randomNumber) external override {
L46 (external function can not go after intenal function)function claimReferralReward(uint128[] memory drawIds) external override returns (uint256 claimedReward) {
L76 (external function can not go after internal function)Description:
According to official solidity documentation functions should be grouped according to their visibility and ordered:
constructor
receive function (if exists)
fallback function (if exists)
external
public
internal
private
Within a grouping, place the view and pure functions last.
Recommendation:
Put the functions in the correct order according to the documentation.
Context:
stakedToken.transferFrom(msg.sender, address(this), amount);
L34 (check amount > 0)stakedToken.transfer(msg.sender, amount);
L47 (check amount > 0)rewardToken.safeTransfer(beneficiary, claimedAmount);
L156 (check claimedAmount > 0)rewardToken.safeTransfer(msg.sender, claimedAmount);
L175 (check claimedAmount > 0)#0 - thereksfour
2023-03-12T09:24:27Z
3 L 2 INFO 5 NC DOWN: 1 LOW
#1 - c4-judge
2023-03-12T09:24:31Z
thereksfour marked the issue as grade-b
#2 - c4-judge
2023-03-12T11:13:36Z
thereksfour marked the issue as grade-a
#3 - c4-sponsor
2023-03-14T10:17:22Z
0xluckydev marked the issue as sponsor confirmed
#4 - thereksfour
2023-03-18T04:29:54Z
4 L 2 INFO A