The game's rules, as described in the function comments, state that when a player claims the throne, a portion of their fee should be paid out to the previous king. This creates a key incentive for players to participate and become the king.
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;
}
function testOverthrownKingReceivesNoPayoutThroughoutGameLifecycle() public {
vm.prank(player1);
game.claimThrone{value: INITIAL_CLAIM_FEE}();
assertEq(game.currentKing(), player1, "Player 1 should be the king.");
uint256 player1BalanceBeforeOverthrow = player1.balance;
uint256 nextClaimFee = game.claimFee();
vm.prank(player2);
game.claimThrone{value: nextClaimFee}();
assertEq(game.currentKing(), player2, "Player 2 should now be the king.");
assertEq(
player1.balance,
player1BalanceBeforeOverthrow,
"FAIL: Player 1's balance changed immediately after being overthrown."
);
}
Implement the payout logic for the previous king. This involves adding a new state variable, previousKingPayoutPercentage
, to define the payout amount and modifying the claimThrone
function to calculate and transfer the funds.
// src/Game.sol
contract Game is Ownable {
// ...
uint256 public feeIncreasePercentage;
uint256 public platformFeePercentage;
+ uint256 public previousKingPayoutPercentage; // Percentage of claimFee for the previous king
// ...
constructor(
uint256 _initialClaimFee,
uint256 _gracePeriod,
uint256 _feeIncreasePercentage,
- uint256 _platformFeePercentage
+ uint256 _platformFeePercentage,
+ uint256 _previousKingPayoutPercentage
) Ownable(msg.sender) {
// ...
require(_platformFeePercentage <= 100, "Game: Platform fee percentage must be 0-100.");
+ require(_previousKingPayoutPercentage < 100, "Game: Payout percentage must be less than 100.");
+ require((_platformFeePercentage + _previousKingPayoutPercentage) < 100, "Game: Combined fees must be less than 100.");
// ...
platformFeePercentage = _platformFeePercentage;
+ previousKingPayoutPercentage = _previousKingPayoutPercentage;
// ...
}
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;
+ address previousKing = currentKing;
+
+ // Calculate payouts
+ uint256 currentPlatformFee = (sentAmount * platformFeePercentage) / 100;
+ uint256 previousKingPayout = (sentAmount * previousKingPayoutPercentage) / 100;
+
+ // Update platform fee balance
+ platformFeesBalance += currentPlatformFee;
+
+ // Pay the previous king if one exists
+ if (previousKing != address(0) && previousKingPayout > 0) {
+ (bool success, ) = payable(previousKing).call{value: previousKingPayout}("");
+ require(success, "Game: Failed to pay previous king.");
+ }
+
+ // Remaining amount goes to the pot
+ uint256 amountToPot = sentAmount - currentPlatformFee - previousKingPayout;
+ pot += amountToPot;
- // Calculate platform fee
- currentPlatformFee = (sentAmount * platformFeePercentage) / 100;
-
- // 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;
- pot = pot + amountToP
// Update game state
currentKing = msg.sender;
lastClaimTime = block.timestamp;
// ...