Eggstravaganza

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

`endGame()` Can Be Called Prematurely, Breaking Game Fairness

Summary

The endGame() function in EggHuntGame.sol does not enforce that the configured game duration (endTime) has passed. This allows the game owner to end the game early at any time, potentially breaking game fairness and player trust.

Vulnerability Details

The startGame(duration) function sets startTime and calculates endTime based on the duration provided by the owner. However, the endGame() function can be called at any time, regardless of whether the game duration has completed.

function endGame() external onlyOwner {
require(gameActive, "Game not active");
gameActive = false;
emit GameEnded(block.timestamp);
}

Since there is no check like require(block.timestamp >= endTime), the owner can prematurely end the game and prevent other players from continuing their egg hunts.

This breaks the implied game rules and could be exploited in a scenario where rewards are distributed based on egg counts or other performance metrics.

Impact

  • Fairness Violation: Players expect the game to run for its full duration.

  • Potential Abuse: Malicious owner can end the game early to benefit specific participants.

  • Reduced Trust: Players may lose confidence if game behaviour is inconsistent with stated rules.

Tools Used

  • Manual Code Review

  • Foundry Test Suite

PoC

// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
import "forge-std/Test.sol";
import "../src/EggstravaganzaNFT.sol";
import "../src/EggVault.sol";
import "../src/EggHuntGame.sol";
contract EggGameTest is Test {
EggstravaganzaNFT nft;
EggVault vault;
EggHuntGame game;
function setUp() public {
// Deploy the contracts.
nft = new EggstravaganzaNFT("Eggstravaganza", "EGG");
vault = new EggVault();
game = new EggHuntGame(address(nft), address(vault));
// Set the allowed game contract for minting eggs in the NFT.
nft.setGameContract(address(game));
// Configure the vault with the NFT contract.
vault.setEggNFT(address(nft));
}
/// @notice This test demonstrates that the game owner can end the game
/// before the configured `endTime` has been reached, violating expected game duration.
function test_endGameBeforeEndTimeReached() public {
// Capture the current blockchain timestamp
uint256 currentTime = block.timestamp;
// Start the game with a 100-second duration
game.startGame(100);
// Verify the game is active and timestamps are initialized correctly
assertTrue(game.gameActive());
assertEq(game.startTime(), currentTime);
assertEq(game.endTime(), currentTime + 100);
// The status should reflect that the game is active
string memory status = game.getGameStatus();
assertEq(status, "Game is active");
// Ensure current time is still before the intended endTime
assertLt(block.timestamp, game.endTime());
// Owner ends the game early — before endTime has been reached
game.endGame();
// Confirm that game is no longer active
assertFalse(game.gameActive());
// Status should now reflect that the game is not active
status = game.getGameStatus();
assertEq(status, "Game is not active");
// Final assertion to prove the game ended early
assertLt(block.timestamp, game.endTime());
}
}

Recommendations

Add a timestamp check to ensure the game cannot be ended before its configured end time:

function endGame() external onlyOwner {
require(gameActive, "Game not active");
+ require(block.timestamp >= endTime, "Game still active");
gameActive = false;
emit GameEnded(block.timestamp);
}
Updates

Lead Judging Commences

m3dython Lead Judge about 2 months ago
Submission Judgement Published
Invalidated
Reason: Design choice
Assigned finding tags:

Trusted Owner

Owner is trusted and is not expected to interact in ways that would compromise security

Appeal created

0xbyteknight Submitter
about 2 months ago
m3dython Lead Judge about 2 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.