Last Man Standing

First Flight #45
Beginner FriendlyFoundrySolidity
100 EXP
View results
Submission Details
Impact: high
Likelihood: high
Invalid

Owner Can Set Platform Fee to 100%, Draining All Player Funds

Root + Impact

Description

  • Normal behavior:
    The platform fee should be a reasonable percentage of the claim fee, ensuring that most of the funds go to the prize pot for players to compete for.

    Specific issue:
    The contract allows the owner to set platformFeePercentage to any value up to 100%. If the owner sets it to 100%, all claim fees are diverted to the owner, and the prize pot remains empty. This makes it impossible for players to win any reward, violating the intended game mechanics and fairness.

// src/Game.sol
function updatePlatformFeePercentage(uint256 _newPlatformFeePercentage)
external
onlyOwner
isValidPercentage(_newPlatformFeePercentage)
{
platformFeePercentage = _newPlatformFeePercentage; // @> No cap, can be set to 100
emit PlatformFeePercentageUpdated(_newPlatformFeePercentage);
}

Risk

Likelihood:

  • This will occur whenever the owner sets the platform fee to 100%.

Impact:

  • All player funds are drained to the owner.

  • The prize pot is always empty, making the game unwinnable and unfair.

  • Players may lose trust and the protocol could face reputational or legal risk.

Proof of Concept

The following scenario demonstrates the bug:

  1. The owner calls updatePlatformFeePercentage(100).

  2. A player claims the throne and pays the claim fee.

  3. All of the claim fee is credited to platformFeesBalance (owner), and nothing is added to the pot.

  4. No player can ever win a prize.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Test} from "forge-std/Test.sol";
import {Game} from "../src/Game.sol";
contract GameC4PlatformFeeTest is Test {
Game public game;
address public deployer;
address public player1;
uint256 public constant INITIAL_CLAIM_FEE = 0.1 ether;
uint256 public constant GRACE_PERIOD = 1 days;
uint256 public constant FEE_INCREASE_PERCENTAGE = 10;
uint256 public constant PLATFORM_FEE_PERCENTAGE = 5;
function setUp() public {
deployer = makeAddr("deployer");
player1 = makeAddr("player1");
vm.deal(deployer, 10 ether);
vm.deal(player1, 10 ether);
vm.startPrank(deployer);
game = new Game(
INITIAL_CLAIM_FEE,
GRACE_PERIOD,
FEE_INCREASE_PERCENTAGE,
PLATFORM_FEE_PERCENTAGE
);
vm.stopPrank();
}
function testOwnerCanDrainAllFeesWith100PercentPlatformFee() public {
// Owner sets platform fee to 100%
vm.startPrank(deployer);
game.updatePlatformFeePercentage(100);
vm.stopPrank();
// Player1 claims the throne
vm.startPrank(player1);
game.claimThrone{value: INITIAL_CLAIM_FEE}();
vm.stopPrank();
// All claim fee should go to platformFeesBalance, pot should be zero
assertEq(game.platformFeesBalance(), INITIAL_CLAIM_FEE, "All fees should go to owner");
assertEq(game.pot(), 0, "Pot should be zero");
}
}

Recommended Mitigation

Add a maximum cap to the platform fee (e.g., 30%) to prevent abuse:

+ uint256 public constant MAX_PLATFORM_FEE = 30; // 30% cap
function updatePlatformFeePercentage(uint256 _newPlatformFeePercentage)
external
onlyOwner
isValidPercentage(_newPlatformFeePercentage)
{
- platformFeePercentage = _newPlatformFeePercentage;
- emit PlatformFeePercentageUpdated(_newPlatformFeePercentage);
+ require(_newPlatformFeePercentage <= MAX_PLATFORM_FEE, "Game: Platform fee too high.");
+ platformFeePercentage = _newPlatformFeePercentage;
+ emit PlatformFeePercentageUpdated(_newPlatformFeePercentage);
}
Updates

Appeal created

inallhonesty Lead Judge about 1 month ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.