Root + Impact
The claimThrone() method lacks a mechanism to issue a small payout to the previous king
Description
According to the function NatSpec:
If there's a previous king, a small portion of the new claim fee is sent to them.
and the protocol requirements documentation, it is stated that:
### 2. King (Current King)
**Powers:**
* The last player to successfully `claimThrone()`.
* Receives a small payout from the next player's `claimFee` (if applicable).
* @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;
@> amountToPot = sentAmount - currentPlatformFee;
pot = pot + amountToPot;
It is ambiguously stated that a small payout should be issued to the previous king, if one exists. However, the current implementation of the claimThrone()
function lacks the logic to allocate a commission to the former king. As a result, the entire amount sent—excluding only the platform fee (a predefined percentage) — is added to the shared prize pot, which will be awarded to the declared winner. The commission intended for the previous king should be calculated using the previousKingPayout
variable, but this variable is currently initialized to 0
and does not participate in any of the pot-related calculations.
Risk
Likelihood: Medium
Impact:
-
The implementation does not meet the requirements of the game and its protocol.
-
Essential mechanics — such as the payout to the previous king — are either missing or incorrectly handled, which compromises the intended flow and fairness of the game logic.
Proof of Concept
N/A
Tools Used
Manual review
Recommended Mitigation
Complete mechanism for issuing a small payout to a current king in function claimThrone()
entirely:
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;
+ // Calculate previos king payout
+ previousKingPayout = (sentAmount * previosKingPayoutPercentage) / 100;
// Defensive check to ensure platformFee doesn't exceed available amount after previousKingPayout
if (currentPlatformFee > (sentAmount - previousKingPayout)) {
currentPlatformFee = sentAmount - previousKingPayout;
}
platformFeesBalance = platformFeesBalance + currentPlatformFee;
+ pendingWinnings[currentKing] = pendingWinnings[currentKing] + previousKingPayout;
// Remaining amount goes to the pot
- amountToPot = sentAmount - currentPlatformFee;
+ amountToPot = sentAmount - (currentPlatformFee + previousKingPayout);
pot = pot + amountToPot;