The MysteryBox
contract allows new rewards to be dynamically added via the addReward
function, but the openBox
function uses hardcoded probabilities and reward types. This means that any new rewards added to the reward pool cannot actually be won by users opening mystery boxes. This creates a mismatch between the advertised reward pool and the rewards that are actually obtainable, potentially misleading users.
The vulnerability stems from two functions in the MysteryBox
contract:
The addReward
function allows new rewards to be added to the reward pool:
However, the openBox
function uses hardcoded probabilities and reward types:
The openBox
function only considers four specific rewards: Coal, Bronze Coin, Silver Coin, and Gold Coin. Any new rewards added through the addReward
function are stored in the rewardPool
array but are never distributed when users open boxes. This creates a discrepancy between the rewards that users can see in the reward pool and the rewards they can actually obtain.
The impact of this vulnerability is significant:
Misleading Users: Users may be enticed to buy mystery boxes based on the advertised reward pool, which includes dynamically added rewards. However, they have no chance of actually winning these new rewards, potentially leading to disappointment and feelings of being misled.
Economic Imbalance: If high-value rewards are added to the pool but cannot be won, it creates an artificial inflation of the perceived value of the mystery boxes without a corresponding increase in actual value distribution.
Wasted Gas: The addReward
function consumes gas to add new rewards to the pool, but this gas is essentially wasted since these rewards can never be distributed.
Scalability Issues: As more rewards are added over time, the contract will store an increasing amount of unused data, potentially leading to increased gas costs for certain operations.
Overall, this vulnerability undermines the core functionality and fairness of the mystery box system, potentially leading to both user dissatisfaction and economic inefficiencies.
To demonstrate this vulnerability, we can add a new test to the MysteryBoxTest
contract. This test will show that even after adding a new reward, users cannot receive it when opening boxes.
Add the following test function to the MysteryBoxTest
contract:
This test does the following:
Adds a new high-value "Platinum Coin" reward to the pool.
Verifies that the new reward is correctly added to the reward pool.
Buys and opens 1000 mystery boxes.
Checks the user's rewards to see if any "Platinum Coin" was received.
Asserts that no "Platinum Coin" was received, despite opening many boxes.
Verifies that the user did receive other rewards, showing that the box opening mechanism is functional.
To run this test, use the following command:
the test output is attached here:
This test will pass, demonstrating that even after adding a new reward and opening many boxes, it's impossible to receive the new reward. This proves that the reward distribution is indeed hardcoded and ignores dynamically added rewards.
Manual review of the smart contract code
Foundry for writing and running test cases to validate the vulnerability
To address this vulnerability and ensure that all rewards in the pool can be won, including newly added ones, we recommend the following approach:
Dynamic Reward Distribution:
Instead of using hardcoded probabilities and rewards, implement a system that uses the dynamic rewardPool
for distribution. This ensures that all rewards, including newly added ones, have a chance of being won.
Probability-based Reward System:
Implement a probability system for rewards where the probability of winning a reward is inversely proportional to its value. This approach ensures that the most valuable rewards have the lowest probability of being won, maintaining the excitement and rarity of high-value prizes.
Automatic Probability Adjustment:
When a new reward is added to the pool, automatically adjust the probabilities of all rewards. The system should ensure that the new reward's probability is set based on its value relative to other rewards in the pool.
Probability Normalization:
After adding new rewards or adjusting probabilities, implement a normalization step to ensure that the sum of all probabilities always equals 100%.
Owner Controls:
Provide functions for the owner to manually adjust probabilities if needed, but ensure that the system maintains the inverse relationship between value and probability.
Transparency:
Implement events that log when new rewards are added or probabilities are adjusted. This increases transparency and allows users to be aware of changes to the reward pool.
By implementing these recommendations, the contract will be able to incorporate new rewards dynamically into the distribution system, maintain appropriate probabilities based on reward values, and provide a fair and exciting experience for users while preserving the rarity of high-value rewards.
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.