The MysteryBox contract lacks mechanisms to ensure that it maintains sufficient funds to cover all potential reward payouts. This could lead to a situation where users are unable to claim their earned rewards due to insufficient contract balance. The contract does not perform balance checks before distributing rewards, potentially leaving some users unable to receive their winnings if the contract becomes underfunded.
The MysteryBox contract has several functions that can lead to insufficient funds for reward payouts. The key vulnerable areas are:
In the constructor, the initial seed value is insufficient to cover the initial reward pool:
The SEEDVALUE (0.1 ether) is less than the total value of initial rewards (0.85 ether), potentially leading to claim failures from the start.
In the addReward
function, new rewards are added without providing corresponding value:
This can lead to the contract being unable to pay out these new rewards.
The openBox
function assigns rewards without checking the contract balance:
The claimAllRewards
function doesn't check if the contract has sufficient balance before attempting to transfer:
Similarly, claimSingleReward
also lacks a balance check:
These issues stem from the absence of proper reward record management and balance checks throughout the contract.
The lack of proper fund management and balance checks in the MysteryBox contract can lead to several severe consequences:
Immediate Insolvency: From the moment of deployment, the contract may be unable to fulfill its reward obligations due to insufficient initial funding. This undermines the core functionality and trustworthiness of the system from the start.
Broken User Expectations: Users who successfully open boxes and receive high-value rewards may find themselves unable to claim these rewards due to insufficient contract balance. This can lead to frustration, loss of trust, and potential reputational damage to the platform.
Unfair Reward Distribution: The "first-come, first-served" nature of the current implementation means that early claimants may receive their rewards while later claimants are left with nothing, even if they have legitimately earned rewards of equal or greater value.
Potential for Exploitation: Malicious actors could exploit this vulnerability by front-running transactions or timing their claims to drain the contract's balance, leaving other legitimate users unable to claim their rewards.
The cumulative effect of these impacts could be catastrophic for the project, potentially leading to its complete failure and loss of all invested funds and user trust.
To demonstrate the vulnerability of insufficient funds for reward payouts, we've created a test case that simulates a user obtaining a high-value reward and then attempting to claim it when the contract has insufficient balance. This test has been implemented in the MysteryBoxTest
contract:
This test case demonstrates the following:
A user buys a mystery box for 0.1 ether.
We manipulate the timestamp to ensure the user receives a high-value "Gold Coin" reward when opening the box. This simulates a legitimate scenario where a user gets lucky and receives a valuable reward.
The test verifies that the user indeed received the "Gold Coin" reward.
When the user attempts to claim the single reward (claimSingleReward
), the transaction reverts with "Transfer failed". This is because the contract doesn't have sufficient funds to pay out the high-value reward.
Similarly, when the user tries to claim all rewards (claimAllRewards
), the transaction also reverts due to insufficient funds.
This proof of concept clearly illustrates that the contract can assign rewards that it cannot pay out, leading to a situation where users are unable to claim their legitimately earned rewards due to insufficient contract balance.
To run this test, use the following command:
the test output is attached here:
The test will pass, confirming that the contract indeed fails to pay out rewards due to insufficient funds, despite users having legitimately earned these rewards through normal contract interactions.
Manual review of the smart contract code
Foundry for writing and running test cases to validate the vulnerability
To address the issue of insufficient funds for reward payouts, we recommend implementing the following measures:
Implement a Reserve System:
Create a reserve fund within the contract that sets aside a portion of each box purchase. This reserve should be used exclusively for paying out rewards, ensuring that the contract always has sufficient funds to cover potential winnings.
Implement a Dynamic Pricing System:
Adjust the box price dynamically based on the current reward pool and contract balance. Ensure that the price of boxes is always sufficient to maintain an adequate reserve for potential payouts.
Implement a Withdrawal Queue:
In cases where the contract temporarily lacks sufficient funds for immediate payout, implement a queue system for withdrawals. This allows users to claim their rewards in order as funds become available, rather than having their transactions revert.
Emergency Pause Mechanism:
Implement a mechanism that allows the contract owner to pause reward distributions in emergency situations, such as when the contract balance falls critically low.
By implementing these recommendations, the contract can better manage its funds, ensure it always has sufficient balance to pay out rewards, and provide a more reliable and fair experience for users. It's crucial to thoroughly test these implementations to ensure they work as intended and do not introduce new vulnerabilities.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.