Incorrect checks in claimThrone function, making no one can enters
Description
The require(msg.sender == currentKing,)
checks whether the caller is the current king, but this checks is actually checking that caller must be the current king. At the initial contract deployment, currentKing
is not set anywhere, therefore this function only allows address(0)
caller.
function claimThrone() external payable gameNotEnded nonReentrant {
require(msg.value >= claimFee, "Game: Insufficient ETH sent to claim the throne.");
@> require(msg.sender == currentKing, "Game: You are already the king. No need to re-claim.");
uint256 sentAmount = msg.value;
uint256 previousKingPayout = 0;
uint256 currentPlatformFee = 0;
uint256 amountToPot = 0;
currentPlatformFee = (sentAmount * platformFeePercentage) / 100;
if (currentPlatformFee > (sentAmount - previousKingPayout)) {
currentPlatformFee = sentAmount - previousKingPayout;
}
platformFeesBalance = platformFeesBalance + currentPlatformFee;
amountToPot = sentAmount - currentPlatformFee;
pot = pot + amountToPot;
currentKing = msg.sender;
lastClaimTime = block.timestamp;
playerClaimCount[msg.sender] = playerClaimCount[msg.sender] + 1;
totalClaims = totalClaims + 1;
claimFee = claimFee + (claimFee * feeIncreasePercentage) / 100;
emit ThroneClaimed(
msg.sender,
sentAmount,
claimFee,
pot,
block.timestamp
);
}
Risk
Likelihood:
Impact:
Proof of Concept
function test_only_allow_zeroAddress(address _user) public {
vm.deal(_user, INITIAL_CLAIM_FEE);
vm.startPrank(_user);
if (_user == address(0)) {
game.claimThrone{value: INITIAL_CLAIM_FEE}();
return;
}
vm.expectRevert("Game: You are already the king. No need to re-claim.");
game.claimThrone{value: INITIAL_CLAIM_FEE}();
vm.stopPrank();
}
}
And surprisingly this test passes:
$ forge test --mt test_only_allow_zeroAddress
[⠊] Compiling...
[⠃] Compiling 2 files with Solc 0.8.30
[⠊] Solc 0.8.30 finished in 830.45ms
Compiler run successful!
Ran 1 test for test/Game.t.sol:GameTest
[PASS] test_only_allow_zeroAddress(address) (runs: 256, μ: 46466, ~: 46144)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 28.19ms (16.35ms CPU time)
Ran 1 test suite in 35.22ms (28.19ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)
Recommended Mitigation
/**
* @dev Allows a player to claim the throne by sending the required claim fee.
* If there's a previous king, a small portion of the new claim fee is sent to them.
* A portion also goes to the platform owner, and the rest adds to the pot.
*/
function claimThrone() external payable gameNotEnded nonReentrant {
require(msg.value >= claimFee, "Game: Insufficient ETH sent to claim the throne.");
// @audit-high
- require(msg.sender == currentKing, "Game: You are already the king. No need to re-claim.");
+ require(msg.sender != currentKing, "Game: You are already the king. No need to re-claim.");
uint256 sentAmount = msg.value;
uint256 previousKingPayout = 0;
uint256 currentPlatformFee = 0;
uint256 amountToPot = 0;