Mystery Box

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

H-1 Contract Insolvency Risk During Reward Claiming in `claimSingleReward()`

Vulnerability Details

The contract faces insolvency during the reward claiming process when multiple users claim high-value rewards like Silver (0.5 ether) or Gold (1 ether). The contract’s initial balance is only 0.1 ether from the constructor, and users only deposit 0.1 ether when buying boxes. If multiple high-tier rewards are claimed, the contract may not have sufficient funds to pay out all rewards, leading to failed transactions.

Impact

The contract runs out of ether when multiple users claim high-value rewards, causing failed reward payouts.
Users are unable to withdraw their rewards, leading to contract failure and a loss of trust.

Tools Used

Unit test

POC

Add this code to your test suite:

function testPlayerCanClaim() public {
//
vm.startPrank(user1);
mysteryBox.buyBox{value: 0.1 ether}();
uint r = mysteryBox.openBox();
console2.log("REWARD:", r);
mysteryBox.claimSingleReward(0);
//
vm.startPrank(user1);
mysteryBox.buyBox{value: 0.1 ether}();
uint a = mysteryBox.openBox();
console2.log("REWARD:", a);
mysteryBox.claimSingleReward(1);
//
vm.startPrank(user2);
mysteryBox.buyBox{value: 0.1 ether}();
uint b = mysteryBox.openBox();
console2.log("REWARD:", b);
mysteryBox.claimSingleReward(0);
//
vm.startPrank(user2);
mysteryBox.buyBox{value: 0.1 ether}();
uint c = mysteryBox.openBox();
console2.log("REWARD:", c);
mysteryBox.claimSingleReward(1);
//
vm.startPrank(user2);
mysteryBox.buyBox{value: 0.1 ether}();
uint q = mysteryBox.openBox();
console2.log("REWARD:", q);
mysteryBox.claimSingleReward(2);
//
vm.startPrank(user3);
mysteryBox.buyBox{value: 0.1 ether}();
uint w = mysteryBox.openBox();
console2.log("REWARD:", w);
mysteryBox.claimSingleReward(0);
//
vm.startPrank(user3);
mysteryBox.buyBox{value: 0.1 ether}();
uint t = mysteryBox.openBox();
console2.log("REWARD:", t);
mysteryBox.claimSingleReward(1);
//
vm.startPrank(user4);
mysteryBox.buyBox{value: 0.1 ether}();
uint y = mysteryBox.openBox();
console2.log("REWARD:", y);
mysteryBox.claimSingleReward(0);
//
vm.startPrank(user4);
mysteryBox.buyBox{value: 0.1 ether}();
uint f = mysteryBox.openBox();
console2.log("REWARD:", f);
mysteryBox.claimSingleReward(1);
assertEq(mysteryBox.getBalance(), 0.8 ether);
assertEq(user3.balance, 1 ether);
}

Recommendations

Maintain a Reserve Fund: Ensure the contract has enough ether to cover all potential rewards before users can claim.
Adjust Reward Values: Align reward values with the deposits made by users to avoid excessive payouts.
Implement a Prize Pool: Accumulate funds from multiple users before allowing large payouts to ensure solvency.

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!