Eggstravaganza

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

Error during token minting process after changing the game contract

Summary

The EggstravaganzaNFT contract allows its owner to update the associated game contract used for token minting. However, if a game has already been played and tokens have been minted, updating the game contract prevents any further token minting. As a result, the game can no longer function as intended, until the original game contract is not set again.

Vulnerability Details

As players discover more eggs, tokens are minted with sequential tokenId values (1, 2, 3, ...). If the EggstravaganzaNFT contract is updated in a new game contract that uses the same tokenId generation logic as the original EggHuntGame contract, it will attempt to mint tokens with tokenId values that already exist, leading to conflicts or errors.

Impact

Minting new tokens is not possible through a newly set game contract.

Proof of Code

Add the following code to the EggHuntGameTest.t.sol file within the EggGameTest contract.

function testChangingGameContractWhenGameWasPreviouslyPlayed() public {
uint256 duration = 100;
// start the game and win an egg
game.startGame(duration);
game.setEggFindThreshold(100);
vm.prank(alice);
game.searchForEgg();
assertEq(nft.totalSupply(), 1);
assertEq(nft.ownerOf(1), alice);
// create new game contract
EggHuntGame game2 = new EggHuntGame(address(nft), address(vault));
game2.setEggFindThreshold(100);
// change the game contract in NFT contract
nft.setGameContract(address(game2));
// start new game and try to win an egg
game2.startGame(duration);
vm.prank(alice);
vm.expectRevert(
abi.encodeWithSelector(
IERC721Errors.ERC721InvalidSender.selector,
address(0)
)
);
game2.searchForEgg();
}

Tools Used

  • Manual Review

  • Foundry

Recommended Mitigation

To resolve this issue, the definition of tokenId can be moved from the EggHuntGame contract to the EggstravaganzaNFT contract. The EggstravaganzaNFT::mintEgg function can then be modified to assign tokenId values based on the current total number of tokens minted. This ensures each new token receives a unique tokenId that increments with every minting.

File EggstravaganzaNFT.sol:

- function mintEgg(address to, uint256 tokenId) external returns (bool) {
+ function mintEgg(address to) external returns (bool) {
require(msg.sender == gameContract, "Unauthorized minter");
+ totalSupply += 1;
+ uint256 tokenId = totalSupply;
_mint(to, tokenId);
- totalSupply += 1;
return true;
}

File EggHuntGame.sol:

- eggNFT.mintEgg(msg.sender, eggCounter);
+ eggNFT.mintEgg(msg.sender);

File EggHuntGameTest.t.sol:

line 58:

- bool success = nft.mintEgg(alice, 1);
+ bool success = nft.mintEgg(alice);

line 68:

- nft.mintEgg(bob, 2);
+ nft.mintEgg(bob);

line 77:

- nft.mintEgg(address(vault), 10);
+ nft.mintEgg(address(vault));

line 197:

- nft.mintEgg(alice, 20);
+ nft.mintEgg(alice);

line 253:

- nft.mintEgg(alice, 30);
+ nft.mintEgg(alice);

This approach ensures that the NFT contract (EggstravaganzaNFT) retains full control over the generation of new tokenId values.

Updates

Lead Judging Commences

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

Game Status Authentication

Lack of game state validation checks

Support

FAQs

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