Mystery Box

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

Reverts in the `claimAllRewards` and `claimSingleReward` functions due to insufficient contract balance.

Summary H-2

Reverts in the claimAllRewards and claimSingleReward functions due to insufficient contract balance.

Vulnerability Details

When the contract is deployed, the deployer sends a SEEDVALUE of 0.1 ether or more to the contract. The vulnerability arises when a user buys a mystery box using the buyBox function, paying 0.1 ether as the price for the box. Afterward, the user calls the openBox function, which determines the reward value of the purchased box. If the user wins a Gold Coin (worth 1 ether), and later tries to claim their reward by calling either the claimAllRewards or claimSingleReward function, the contract attempts to send 1 ether to the user. However, the contract only holds 0.2 ether (from the initial deployment deposit and the 0.1 ether from the user's purchase). Since the contract balance is insufficient to pay out the reward, the transaction reverts.

Impact

Users are unable to claim their rewards, particularly high-value rewards like the Gold Coin, due to the contract's insufficient balance. This leads to failed reward claims, undermining user trust and contract functionality.

POC

function testClaimAllRewards_NotEnoughContractBalance() public {
// User1 buys a two boxes
vm.deal(user1, 1 ether);
vm.startPrank(user1);
mysteryBox.buyBox{value: 0.1 ether}();
mysteryBox.buyBox{value: 0.1 ether}();
vm.warp(26);
// Open the box to win a reward
mysteryBox.openBox();
mysteryBox.openBox();
// Ensure the user has at least one reward
uint256 rewardCount = mysteryBox.getRewards().length;
assertGt(rewardCount, 0, "User should have at least one reward after opening a box");
/// call revert due to contract being out of balance
vm.expectRevert();
// Claim all rewards
mysteryBox.claimAllRewards();
uint256 totalValue = 0;
///////// calculate all reward value
for (uint256 i = 0; i < mysteryBox.getRewards().length; i++) {
totalValue += mysteryBox.getRewards()[i].value;
}
console.log("Contract Balance ", address(mysteryBox).balance);
console.log("Expected Reward Value", totalValue);
vm.stopPrank();
////// CONSOLE LOGS ///////////////
// Contract Balance 300000000000000000 ====> 0.3 ether
// Expected Reward Value 2000000000000000000 ======> 2.0 ether
}

Tools Used

Manual review

Recommendations

  1. Ensure the contract is initialized with a balance sufficient to cover all potential reward payouts.

  2. Implement a reserve fund mechanism to guarantee that rewards, particularly high-value ones, can always be paid out.

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!