Mystery Box

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

Potential Fund Lock Due to Insufficient Balance for User Reward Claims

Summary

The MysteryBox contract has a potential issue where funds could become locked, preventing users from claiming their rewards. This situation arises when the contract's balance is insufficient to cover the rewards owed to users.

Vulnerability Details

The issue arises in the reward claiming functions (claimAllRewards and claimSingleReward) when users attempt to withdraw rewards, but the contract lacks sufficient funds to fulfill the claim.
Here’s how the issue can occur:
The contract allows users to win rewards that may add up to significant amounts (e.g., 1 ether). However, there is no guarantee that the contract has enough balance to pay out those rewards when the user attempts to claim them.
If the contract owner only deposited a small amount (e.g., 0.1 ether), but a user is entitled to a much larger reward (e.g., 1 ether), the following line in the reward claim function will fail:

(bool success,) = payable(msg.sender).call{value: totalValue}("");
require(success, "Transfer failed");

The transaction will fail because there are insufficient funds in the contract to complete the transfer.

Impact

Users may not be able to claim their rewards if the contract’s balance is insufficient. This leads to locked rewards that cannot be accessed, even though users are entitled to them.

Tools Used

Manual Review

Recommendations

Before allowing users to claim their rewards, the contract should check if the balance is sufficient to cover the reward amount. If not, an error message should be returned, and the reward should remain unclaimed until the balance is replenished.

claimAllRewards function

function claimAllRewards() public {
uint256 totalValue = 0;
for (uint256 i = 0; i < rewardsOwned[msg.sender].length; i++) {
totalValue += rewardsOwned[msg.sender][i].value;
}
require(totalValue > 0, "No rewards to claim");
+ require(address(this).balance >= totalValue, "Insufficient contract balance");
(bool success,) = payable(msg.sender).call{value: totalValue}("");
require(success, "Transfer failed");
delete rewardsOwned[msg.sender];
}

claimSingleReward function

function claimSingleReward(uint256 _index) public {
require(_index <= rewardsOwned[msg.sender].length, "Invalid index");
uint256 value = rewardsOwned[msg.sender][_index].value;
require(value > 0, "No reward to claim");
+ require(address(this).balance >= totalValue, "Insufficient contract balance");
(bool success,) = payable(msg.sender).call{value: value}("");
require(success, "Transfer failed");
delete rewardsOwned[msg.sender][_index];
}
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!