Summary
The contract lacks event emission for critical state changes. Events are essential for tracking contract activity, debugging, and off-chain indexing.
Vulnerability Details
The EggstravaganzaNFT::setGameContract
function updates EggstravaganzaNFT::gameContract
variable without emitting an event:
function setGameContract(address _gameContract) external onlyOwner {
require(_gameContract != address(0), "Invalid game contract address");
@> gameContract = _gameContract;
}
The EggstravaganzaNFT::mintEgg
function mints an NFT but does not log the event:
function mintEgg(address to, uint256 tokenId) external returns (bool) {
require(msg.sender == gameContract, "Unauthorized minter");
_mint(to, tokenId);
@> totalSupply += 1;
return true;
}
The EggVault::setEggNFT
function set the NFT contract address without emitting an event:
function setEggNFT(address _eggNFTAddress) external onlyOwner {
require(_eggNFTAddress != address(0), "Invalid NFT address");
@> eggNFT = EggstravaganzaNFT(_eggNFTAddress);
}
The EggHuntGame::setEggFindThreshold
function set the new find threshold without emitting an event:
function setEggFindThreshold(uint256 newThreshold) external onlyOwner {
require(newThreshold <= 100, "Threshold must be <= 100");
@> eggFindThreshold = newThreshold;
}
Impact
Debugging and monitoring become difficult without transaction logs
Reduced transparency and observability in contract execution
Tools Used
Foundry
Aderyn
Recommendations
Introduce event logging for critical state changes to improve contract transparency and traceability. Modify the functions to emit these events and add the following event declarations:
src/EggstravaganzaNFT.sol:
+ event GameContractUpdated(address indexed newGameContract);
+ event EggMinted(address indexed to, uint256 indexed tokenId);
.
.
.
/// @notice Only the owner can set the game contract allowed to mint eggs.
function setGameContract(address _gameContract) external onlyOwner {
require(_gameContract != address(0), "Invalid game contract address");
gameContract = _gameContract;
+ emit GameContractUpdated(_gameContract);
}
/// @notice Public function to mint a new Eggstravaganza NFT.
/// Only the approved game contract can mint eggs.
function mintEgg(address to, uint256 tokenId) external returns (bool) {
require(msg.sender == gameContract, "Unauthorized minter");
_mint(to, tokenId);
totalSupply += 1;
+ emit EggMinted(to, tokenId);
return true;
}
src/EggVault.sol:
+ event EggNFTSet(address indexed newEggNFT);
/// @notice Set the NFT contract address.
function setEggNFT(address _eggNFTAddress) external onlyOwner {
require(_eggNFTAddress != address(0), "Invalid NFT address");
eggNFT = EggstravaganzaNFT(_eggNFTAddress);
+ emit EggNFTSet(_eggNFTAddress);
}
src/EggHuntGame.sol:
+ event EggFindThresholdUpdated(uint256 newThreshold);
.
.
.
function setEggFindThreshold(uint256 newThreshold) external onlyOwner {
require(newThreshold <= 100, "Threshold must be <= 100");
eggFindThreshold = newThreshold;
+ emit EggFindThresholdUpdated(newThreshold);
}