Mystery Box

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

Insufficient Contract Balance to Pay Rewards

Description
The MysteryBox.sol#openBox() function allows users to open their mystery boxes and receive rewards based on the following probabilities:

  • 75% chance of getting "Coal"

  • 20% chance of getting a "Bronze Coin"

  • 4% chance of getting a "Silver Coin"

  • 1% chance of getting a "Gold Coin"

When a user opens a box, the number of boxes they own is reduced by 1. However, if a user wins a high-value reward (such as a Gold Coin) and tries to claim it through MysteryBox.sol#claimAllRewards(), the contract may not have enough balance to cover the payout. Given that each box costs only 0.1 ETH, it would take thousands of box purchases to accumulate enough ETH to pay out a single Gold Coin reward (1 ETH). As a result, the contract will revert the transaction, leaving the user unable to claim their prize.

function openBox() public {
// if contract does not have enough ether to send, it will revert
require(boxesOwned[msg.sender] > 0, "No boxes to open");
// Generate a random number between 0 and 99
uint256 randomValue = uint256(keccak256(abi.encodePacked(block.timestamp, msg.sender))) % 100;
// Determine the reward based on probability
if (randomValue < 75) {
// 75% chance to get Coal (0-74)
rewardsOwned[msg.sender].push(Reward("Coal", 0.1 ether));
} else if (randomValue < 95) {
// 20% chance to get Bronze Coin (75-94)
rewardsOwned[msg.sender].push(Reward("Bronze Coin", 0.1 ether));
} else if (randomValue < 99) {
// 4% chance to get Silver Coin (95-98)
rewardsOwned[msg.sender].push(Reward("Silver Coin", 0.5 ether));
} else {
// 1% chance to get Gold Coin (99)
rewardsOwned[msg.sender].push(Reward("Gold Coin", 1 ether));
}
boxesOwned[msg.sender] -= 1;
}

Impact
If a user wins a large number of Bronze Coins or a high-value Gold Coin, they will not be able to claim their rewards due to insufficient contract funds. Every attempt to claim the rewards will revert until the contract has enough balance, leading to frustration and loss of trust in the platform.

Proof of Concept

  1. Several users buy boxes, contributing a total of 0.50 ETH to the contract.

  2. A new user wins a Gold Coin (worth 1 ETH).

  3. The user attempts to withdraw their reward using claimAllRewards().

  4. The transaction reverts because the contract only holds 0.50 ETH and cannot cover the 1 ETH reward.

Recommendation
To mitigate this issue:

  1. Increase Box Price: Adjust the price of the mystery boxes to ensure the contract can cover potential high-value rewards.

  2. Limit High-Value Rewards: Restrict the issuance of high-value rewards unless the contract has sufficient balances.

  3. Implement a Reserve Mechanism: Set aside a portion of every box purchase to build a reserve that can cover large rewards.

Updates

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!