Root + Impact
Description
The throne could not be claimed by anyone because the claimThrone function reverts if the current king and the claimer are different. Since the address of the current king is address 0 at the initialization, the game is unplayable.
Moreover, the game can't be terminated or reset due to checks done on address 0 for the declareWinner function and on the state of the game for the resetGame function.
function claimThrone() external payable gameNotEnded nonReentrant {
...
require(
msg.sender == currentKing,
"Game: You are already the king. No need to re-claim."
);
...
}
function declareWinner() external gameNotEnded {
require(
currentKing != address(0),
"Game: No one has claimed the throne yet."
);
gameEnded = true;
...
}
function resetGame() external onlyOwner gameEndedOnly {}
Risk
Likelihood: This happen at the initialization of the smart contract
Impact: Game unplayable
Proof of Concept
function testUnplayableGame() public {
vm.prank(player1);
vm.expectRevert("Game: You are already the king. No need to re-claim.");
game.claimThrone{value: 0.5 ether}();
vm.expectRevert("Game: No one has claimed the throne yet.");
game.declareWinner();
vm.prank(deployer);
vm.expectRevert("Game: Game has not ended yet.");
game.resetGame();
}
Recommended Mitigation
function claimThrone() external payable gameNotEnded nonReentrant {
...
require(
- msg.sender == currentKing,
+ msg.sender != currentKing,
"Game: You are already the king. No need to re-claim."
);
...