Mystery Box

First Flight #25
Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: medium
Valid

Lack of Reward Pool Check in buyBox() Allows Over-purchase of Boxes

Summary

The buyBox() function in the MysteryBox contract does not check the availability of rewards in the pool, allowing users to buy boxes even when there may not be enough rewards left. This can lead to a situation where users purchase boxes that cannot be opened, leading to potential frustration and financial loss for users.

Vulnerability Details

The buyBox() function currently allows users to purchase boxes without verifying whether there are any rewards available in the rewardPool. Since the reward pool could run out of rewards, users might continue to purchase boxes that they cannot open due to the lack of available rewards. This oversight could lead to user dissatisfaction and potential misuse of the system, where users are charged for boxes but are unable to receive rewards.

Example Scenario:

  1. Initial Setup:

    • The rewardPool contains a finite number of rewards.

  2. Execution:

    • Users continue calling buyBox() even after all the rewards have been claimed from the rewardPool.

  3. Outcome:

    • Users purchase boxes without receiving rewards, as the reward pool is empty. This leads to a situation where users pay for boxes that cannot be opened due to the lack of available rewards.

Impact:

  • Over-purchasing: Users can purchase more boxes than there are rewards in the pool, leading to a situation where boxes cannot be opened because the rewards are exhausted.

  • User Dissatisfaction: Users who purchase boxes and are unable to open them due to the lack of rewards could become frustrated, potentially resulting in financial loss for the users.

  • Unintended System Behavior: Without checks on the availability of rewards, the system does not properly limit the number of boxes sold based on the remaining rewards, leading to uncontrolled box purchases.

Steps to Reproduce the Issue:

  1. Step 1: The rewardPool contains a limited number of rewards (e.g., 10 rewards).

  2. Step 2: Users continue to call buyBox() even after all rewards have been claimed.

  3. Expected Outcome: The transaction should revert when there are no more rewards available.

  4. Actual Outcome: The transaction succeeds, users purchase boxes, but there are no rewards left to claim, leading to an unfulfilled purchase.

Tools Used

Manual review

Recommendations

Add a dynamic check to ensure the availability of rewards before allowing users to purchase boxes:

+++ function getNumberOfRewards() public view returns (uint256) {
+++ return rewardPool.length; // The number of available boxes should match the number of rewards in the pool
+++ }
function buyBox() public payable {
require(msg.value == boxPrice, "Incorrect ETH sent");
+++ require(getAvailableBoxes() > 0, "No boxes available"); // Check if there are available boxes based on rewards
boxesOwned[msg.sender] += 1;
}

Additionally, when a box is opened, the corresponding reward should be removed from the reward pool to ensure that the number of rewards matches the number of boxes sold.

Reward Removal Logic:

function openBox() public {
require(boxesOwned[msg.sender] > 0, "No boxes to open");
require(rewardPool.length > 0, "No rewards available");
// Generate a random index and assign a reward from rewardPool
uint256 randomIndex = uint256(keccak256(abi.encodePacked(block.timestamp, msg.sender))) % rewardPool.length;
Reward memory selectedReward = rewardPool[randomIndex];
rewardsOwned[msg.sender].push(selectedReward);
// Remove the selected reward from the reward pool
rewardPool[randomIndex] = rewardPool[rewardPool.length - 1];
rewardPool.pop();
boxesOwned[msg.sender] -= 1;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge
about 1 year ago

Appeal created

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Protocol should have a higher initial balance to prevent prize withdrawing problems

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!