Summary
SantasList::collectPresent() and SantasList::buyPresent() does not emit an event, so the changes made by these will not be tracked and off-chain database will not be in proper sync with on-chain data.
Vulnerability Details
The function collectPresent and buyPresent updates the contract state but they lag event emission as a result of which the changes made on-chain are not tracked off-chain.
function collectPresent() external {
if (block.timestamp < CHRISTMAS_2023_BLOCK_TIME) {
revert SantasList__NotChristmasYet();
}
if (balanceOf(msg.sender) > 0) {
revert SantasList__AlreadyCollected();
}
if (s_theListCheckedOnce[msg.sender] == Status.NICE && s_theListCheckedTwice[msg.sender] == Status.NICE) {
_mintAndIncrement();
@>
return;
} else if (
s_theListCheckedOnce[msg.sender] == Status.EXTRA_NICE
&& s_theListCheckedTwice[msg.sender] == Status.EXTRA_NICE
) {
_mintAndIncrement();
i_santaToken.mint(msg.sender);
@>
return;
}
revert SantasList__NotNice();
}
function buyPresent(address presentReceiver) external {
i_santaToken.burn(presentReceiver);
_mintAndIncrement();
@>
}
Impact
When the state is initialized or modified, an event needs to be emitted. Any state that is initialized or modified without an event being emitted is not visible off-chain. This means that any off-chain service is not able to view changes.
Over here the changed made to state of contract by the collectPresent
and buyPresent
function will not be tracked off-chain as both the functions lags necessary event emission
Tools Used
Manual Review
Recommendations
Emit an event in the function for the necessary state changes.
+ event PresentCollected(address receiver, Status receiverStatus);
function collectPresent() external {
if (block.timestamp < CHRISTMAS_2023_BLOCK_TIME) {
revert SantasList__NotChristmasYet();
}
if (balanceOf(msg.sender) > 0) {
revert SantasList__AlreadyCollected();
}
if (s_theListCheckedOnce[msg.sender] == Status.NICE && s_theListCheckedTwice[msg.sender] == Status.NICE) {
_mintAndIncrement();
+ emit PresentCollected(msg.sender, Status.NICE);
return;
} else if (
s_theListCheckedOnce[msg.sender] == Status.EXTRA_NICE
&& s_theListCheckedTwice[msg.sender] == Status.EXTRA_NICE
) {
_mintAndIncrement();
i_santaToken.mint(msg.sender);
+ emit PresentCollected(msg.sender, Status.EXTRA_NICE);
return;
}
revert SantasList__NotNice();
}
+ event PresentBought(address from, address receiver);
function buyPresent(address presentReceiver) external {
i_santaToken.burn(presentReceiver);
_mintAndIncrement();
+ emit PresentBought(msg.sender, presentReceiver);
}