* @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.");
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;
...
}
function test_audit_missingPreviousKingPayout() public {
vm.prank(player1);
game.claimThrone{value: INITIAL_CLAIM_FEE}();
assertEq(game.currentKing(), player1);
uint256 player1_balance_before_player2Claim = player1.balance;
console2.log("player1_balance_before_player2Claim: ", player1_balance_before_player2Claim);
vm.prank(player2);
game.claimThrone{value: INITIAL_CLAIM_FEE * 110/100} ();
assertEq(game.currentKing(), player2);
uint256 player1_balance_after_player2Claim = player1.balance;
console2.log("player1_balance_after_player2Claim: ", player1_balance_after_player2Claim);
assertEq(player1_balance_before_player2Claim, player1_balance_after_player2Claim);
}
The test passed indicating that no payout was received by player1 as the previous king from player2 even after player2 called claimThrone
and became the currentKing
.
contract Game is Ownable {
// --- State Variables ---
...
// Game Parameters (Configurable by Owner)
uint256 public initialClaimFee; // The starting fee for a new game round
uint256 public feeIncreasePercentage; // Percentage by which the claimFee increases after each successful claim (e.g., 10 for 10%)
uint256 public platformFeePercentage; // Percentage of the claimFee that goes to the contract owner (deployer)
+ uint256 public previousKingFeePercentage;
...
constructor(
uint256 _initialClaimFee,
uint256 _gracePeriod,
uint256 _feeIncreasePercentage,
uint256 _platformFeePercentage,
+ uint256 _previousKingFeePercentage
) Ownable(msg.sender) { // Set deployer as owner
require(_initialClaimFee > 0, "Game: Initial claim fee must be greater than zero.");
require(_gracePeriod > 0, "Game: Grace period must be greater than zero.");
require(_feeIncreasePercentage <= 100, "Game: Fee increase percentage must be 0-100.");
require(_platformFeePercentage <= 100, "Game: Platform fee percentage must be 0-100.");
+ require(_previousKingFeePercentage <= 100, "Game: Previous king fee percentage must be 0-100.");
initialClaimFee = _initialClaimFee;
initialGracePeriod = _gracePeriod;
feeIncreasePercentage = _feeIncreasePercentage;
platformFeePercentage = _platformFeePercentage;
+ previousKingFeePercentage = _previousKingFeePercentage;
...
}
...
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;
// Calculate platform fee
currentPlatformFee = (sentAmount * platformFeePercentage) / 100;
+ // To implement project intended payout scheme to previous king
+ // with previousKingFeePercentage as global state variable defined via constructor
+ // and later on adjustable by owner under updateClaimFeeParameters
+ if (currentKing != address(0)) {
+ previousKingPayout = (sentAmount * previousKingFeePercentage) / 100;
+ // could also implement as fix percentage if don't want to create new global state variable
+ // previousKingPayout = (sentAmount * 10) / 100;
+ (bool success, ) = currentKing.call{value: previousKingPayout}("");
+ require(success, "Game: Failed to pay previous king.");
+ }
// Defensive check to ensure platformFee doesn't exceed available amount after previousKingPayout
if (currentPlatformFee > (sentAmount - previousKingPayout)) {
currentPlatformFee = sentAmount - previousKingPayout;
}
platformFeesBalance = platformFeesBalance + currentPlatformFee;
// Remaining amount goes to the pot
- amountToPot = sentAmount - currentPlatformFee;
+ amountToPot = sentAmount - currentPlatformFee - previousKingPayout;
pot = pot + amountToPot;
...
}
function updateClaimFeeParameters(
uint256 _newInitialClaimFee,
uint256 _newFeeIncreasePercentage
+ uint256 _newPreviousKingFeePercentage
) external onlyOwner isValidPercentage(_newFeeIncreasePercentage) {
require(_newInitialClaimFee > 0, "Game: New initial claim fee must be greater than zero.");
initialClaimFee = _newInitialClaimFee;
feeIncreasePercentage = _newFeeIncreasePercentage;
+ previousKingFeePercentage = _newPreviousKingFeePercentage
- emit ClaimFeeParametersUpdated(_newInitialClaimFee, _newFeeIncreasePercentage);
+ emit ClaimFeeParametersUpdated(_newInitialClaimFee, _newFeeIncreasePercentage, _newPreviousKingFeePercentage);
}
}