Description
The previousKingPayout
variable is declared but never assigned a value in the claimThrone
function. As a result, no reward is ever transferred to the previous king when a new player claims the throne. This breaks a core incentive mechanism of the game.
Risk
Impact:
Players who previously held the throne do not receive the expected financial reward when dethroned. This undermines the game’s economic model and significantly reduces player motivation to participate, as there is no tangible benefit in holding the throne if no payout is guaranteed upon losing it. Over time, this could lead to low engagement and a non-functional game economy.
Proof of Concept
Admin deploys the contract.
Player player1
pays the claim fee and successfully calls claimThrone
.
Player player2
pays the (increased) claim fee and calls claimThrone
, dethroning player1
.
Player player1
checks their balance or attempts to call withdrawWinnings()
— they receive zero payout despite being the previous king.
This confirms that no reward was allocated or credited to the previous king.
Recommended Mitigation
Since the original specification does not define the exact amount or percentage to be paid to the previous king, we recommend introducing a configurable previousKingFeePercentage
parameter set at deployment. This allows flexibility and transparency while ensuring the reward mechanism is enforceable.
The following changes are proposed:
1. Add State Variable
// Game Parameters (Configurable by Owner)
uint256 public initialClaimFee;
uint256 public feeIncreasePercentage;
uint256 public platformFeePercentage;
+ // Percentage of the claim fee allocated to the previous king
+ uint256 public previousKingFeePercentage;
uint256 public initialGracePeriod;
2. Update Constructor
constructor(
uint256 _initialClaimFee,
uint256 _gracePeriod,
uint256 _feeIncreasePercentage,
uint256 _platformFeePercentage,
+ uint256 _previousKingFeePercentage
) Ownable(msg.sender) {
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.");
+ require(_platformFeePercentage + _previousKingFeePercentage < 100,
+ "Game: Sum of platform and previous king fees must be less than 100%");
initialClaimFee = _initialClaimFee;
initialGracePeriod = _gracePeriod;
feeIncreasePercentage = _feeIncreasePercentage;
platformFeePercentage = _platformFeePercentage;
+ previousKingFeePercentage = _previousKingFeePercentage;
claimFee = initialClaimFee;
gracePeriod = initialGracePeriod;
lastClaimTime = block.timestamp;
gameRound = 1;
gameEnded = false;
}
3. Fix claimThrone
Logic
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 payout to the previous king
+ previousKingPayout = (sentAmount * previousKingFeePercentage) / 100;
// Calculate platform fee
currentPlatformFee = (sentAmount * platformFeePercentage) / 100;
+ // Pay the previous king (before updating current king!)
+ if (previousKingPayout > 0 && currentKing != address(0)) {
+ pendingWinnings[currentKing] += previousKingPayout;
+ }
// Prevent platform fee from exceeding available funds after previous king payout
if (currentPlatformFee > (sentAmount - previousKingPayout)) {
currentPlatformFee = sentAmount - previousKingPayout;
}
platformFeesBalance += currentPlatformFee;
// Remaining ETH goes to the pot
amountToPot = sentAmount - currentPlatformFee;
pot += amountToPot;
// Update game state
currentKing = msg.sender;
lastClaimTime = block.timestamp;
playerClaimCount[msg.sender]++;
totalClaims++;
// Increase fee for next claim
claimFee = claimFee + (claimFee * feeIncreasePercentage) / 100;
emit ThroneClaimed(msg.sender, sentAmount, claimFee, pot, block.timestamp);
}
Benefits of the Fix:
Introduces a transparent and configurable reward for the previous king.
Maintains fund safety with proper arithmetic and overflow checks.
Ensures fair distribution: previous king, platform, and pot.
Increases player engagement by restoring the intended economic incentive.