Description
The Game contract’s updateClaimFeeParameters function allows the owner to set feeIncreasePercentage to any value from 0 to 100 via the isValidPercentage modifier. Setting feeIncreasePercentage to 0 causes the claimFee to remain static in claimThrone (using claimFee = claimFee + (claimFee * feeIncreasePercentage) / 100), breaking the intended mechanic of an escalating claimFee.
function updateClaimFeeParameters(
uint256 _newInitialClaimFee,
uint256 _newFeeIncreasePercentage
) external onlyOwner isValidPercentage(_newFeeIncreasePercentage) {
require(_newInitialClaimFee > 0, "Game: New initial claim fee must be greater than zero.");
initialClaimFee = _newInitialClaimFee;
@> feeIncreasePercentage = _newFeeIncreasePercentage;
emit ClaimFeeParametersUpdated(_newInitialClaimFee, _newFeeIncreasePercentage);
}
modifier isValidPercentage(uint256 _percentage) {
@> require(_percentage <= 100, "Game: Percentage must be 0-100.");
_;
}
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.");
@> claimFee = claimFee + (claimFee * feeIncreasePercentage) / 100;
}
Risk
Likelihood:
Owner can set feeIncreasePercentage = 0 intentionally or by mistake, as the modifier allows it.
Persists after resetGame, affecting all rounds.
Impact:
Static claimFee removes the escalating cost, reducing game competitiveness and allowing spamming claims at low cost.
Lower pot growth.
Proof of Concept
function test_ZeroFeeIncreasePercentage() public {
vm.prank(deployer);
game.updateClaimFeeParameters(INITIAL_CLAIM_FEE, 0);
vm.prank(player1);
game.claimThrone{value: INITIAL_CLAIM_FEE}();
vm.prank(player2);
game.claimThrone{value: INITIAL_CLAIM_FEE}();
assertEq(game.claimFee(), 0.1 ether, "Claim fee remains static");
}
Recommended Mitigation
enforce a minimum percentage in the isValidPercentage modifier, ensuring the claimFee always increases.
This aligns with the game’s design and prevents static fees across all rounds.
modifier isValidPercentage(uint256 _percentage) {
- require(_percentage <= 100, "Game: Percentage must be 0-100.");
+ require(_percentage > 0 && _percentage <= 100, "Game: Percentage must be 1-100.");
_;
}