Eggstravaganza

First Flight #37
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: low
Valid

Incorrect Game Status Reporting

Description

The getTimeRemaining() function in the contract is intended to return the remaining time in a game session. However, it fails to account for situations where a game is manually ended before the originally scheduled end time.

What is the getTimeRemaining() function?

Typically, getTimeRemaining() would be designed to calculate how much time is left in the game based on the current time (block.timestamp) and the game's endTime (the point in time when the game is supposed to end).

The basic logic might look like this:

function getTimeRemaining() public view returns (uint256) {
if (block.timestamp >= endTime) {
return 0;
} else {
return endTime - block.timestamp;
}
}

This function assumes that endTime represents when the game will automatically end (whether through a timer or another condition). It calculates the difference between the current time and the endTime to determine how much longer the game will last.

The Issue

The vulnerability arises when the game is manually ended before the endTime. For example, an admin might call an endGame() function or another method that ends the game, even though the game's endTime is still far in the future.

In such a case, the getTimeRemaining() function still relies on the original endTime and does not account for the manual intervention that ended the game early.

Example:

Let’s assume:

  • The game is supposed to last 1 hour (3600 seconds).

  • The game’s endTime is set to block.timestamp + 3600.

  • The game is manually ended after 30 minutes (1800 seconds).

Now, if a player calls getTimeRemaining(), it would return:

return endTime - block.timestamp; // 3600 - 1800 = 1800 seconds remaining

However, since the game was manually ended at the 1800-second mark (30 minutes), there should be no time remaining. But because the getTimeRemaining() function does not consider the manual game end, it gives the misleading value of 1800 seconds remaining.

Proof of Concept (PoC)

Here’s a proof of concept to illustrate how this vulnerability can manifest in the game. The following test simulates a situation where the game is manually ended before the original endTime.

function testIncorrectGameStatusReporting() public {
// Start the game with a duration of 3600 seconds (1 hour)
game.startGame(3600);
// Wait for 30 minutes (1800 seconds) to simulate game progress
vm.warp(block.timestamp + 1800);
// Manually end the game
game.endGame(); // Assume this is a function that ends the game early
// Now, check the time remaining, it should be 0 since the game was manually ended
uint256 timeRemaining = game.getTimeRemaining();
assertEq(timeRemaining, 0, "Time remaining should be 0 after manual game end");
// However, if we do not handle the manual end, the `getTimeRemaining` might still return a value of 1800.
}

Key Steps in the PoC:

  1. Start the Game: The game is started with a 1-hour duration.

  2. Simulate Game Progress: We simulate that 30 minutes have passed by using vm.warp(), which allows us to fast-forward time in the test.

  3. Manual Game End: The game is then manually ended using game.endGame().

  4. Check Time Remaining: After the game is manually ended, we check the time remaining with game.getTimeRemaining(). This should return 0 Since the game was manually ended. However, the vulnerability means it could return the wrong value (e.g., 1800), which is incorrect.

Impact

Why is this a bug?

While this vulnerability might seem minor at first, it has the potential to severely affect how the game is perceived and played, especially when it comes to transparency and player experience.

  1. Misleading Information: Players might think that they have more time to participate in the game or complete tasks when, in reality, the game has already ended. This can lead to confusion, frustration, and a poor player experience.

  2. Potential Abuse: If the game end time is incorrectly reported, malicious actors may use this to exploit the game, believing they still have time to act (such as searching for eggs in this case). This is especially important if the game's outcome is dependent on the time remaining.

  3. Inaccurate Statistics: Reporting incorrect time remaining can also mess with the game's statistics and reporting mechanisms. If any part of the game logic is time-dependent, such as rewards or leaderboard updates, they could be incorrectly calculated, leading to unfair outcomes.

  4. Compromising Admin Actions: Admins or game managers who manually end games need to rely on accurate time reporting. If they mistakenly believe the game is still ongoing when it isn’t, they might make decisions based on outdated or incorrect information, leading to further mismanagement of the game state.

Recommendations

The fix for this vulnerability is relatively straightforward: The getTimeRemaining() function needs to be updated to check whether the game has been manually ended. If the game was manually ended, the function should return 0 regardless of the endTime.

Updated getTimeRemaining() Function:

function getTimeRemaining() public view returns (uint256) {
// If the game is manually ended, return 0
if (gameEnded) {
return 0;
}
// If not ended manually, return time remaining based on endTime
if (block.timestamp >= endTime) {
return 0;
} else {
return endTime - block.timestamp;
}
}

In this example, gameEnded would be a boolean variable that gets set to true when an admin manually ends the game using a function like endGame(). This ensures that the game’s time remaining is reported accurately, even if the game ends prematurely.

Considerations for the Fix:

  • Ensure that the gameEnded state is updated whenever an admin calls endGame().

  • This update does not require a change in how the game’s endTime is set or managed, but rather adds an extra check to account for manual termination.

Conclusion

The issue with incorrect game status reporting arises from the failure to account for manually ended games in the getTimeRemaining() function. This leads to misleading time remaining values, which can confuse players, compromise game integrity, and lead to incorrect game outcomes.

By adding a check for manual game termination, we can ensure that the getTimeRemaining() function always reports accurate information, improving the fairness and transparency of the game.

Updates

Lead Judging Commences

m3dython Lead Judge 3 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Incomplete end game handling

Incorrect values reported when a game is ended early

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.