Root + Impact
Description
function updatePlatformFeePercentage(uint256 _newPlatformFeePercentage) external onlyOwner
isValidPercentage(_newPlatformFeePercentage)
Risk
Likelihood:
Impact:
Proof of Concept
This POC shows how the pot value decreases after the platformfees are updated in the middle of the game.
pragma solidity ^0.8.20;
import {Test, console2} from "forge-std/Test.sol";
import {Game} from "../src/Game.sol";
contract GameTest is Test {
Game public game;
address public deployer;
address public player1;
address public player2;
address public player3;
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");
player2 = makeAddr("player2");
player3 = makeAddr("player3");
vm.deal(deployer, 10 ether);
vm.deal(player1, 10 ether);
vm.deal(player2, 10 ether);
vm.deal(player3, 10 ether);
vm.prank(deployer);
game = new Game(
INITIAL_CLAIM_FEE,
GRACE_PERIOD,
FEE_INCREASE_PERCENTAGE,
PLATFORM_FEE_PERCENTAGE
);
}
function test_claimmthrone() external{
vm.prank(player1);
game.claimThrone{value: 1 ether}();
vm.prank(deployer);
game.updatePlatformFeePercentage(99);
vm.prank(player2);
game.claimThrone{value:1.02 ether}();
vm.prank(player3);
game.claimThrone{value: 1.1 ether}();
}
}
Output:
GameTest::test_claimmthrone()
├─ [0] VM::prank(player1: [0x7026B763CBE7d4E72049EA67E89326432a50ef84])
│ └─ ← [Return]
├─ [152621] Game::claimThrone{value: 1000000000000000000}()
│ ├─ emit ThroneClaimed(newKing: player1: [0x7026B763CBE7d4E72049EA67E89326432a50ef84], claimAmount: 1000000000000000000 [1e18], newClaimFee: 110000000000000000 [1.1e17], newPot: 950000000000000000 [9.5e17], timestamp: 1)
│ └─ ← [Stop]
├─ [0] VM::prank(deployer: [0xaE0bDc4eEAC5E950B67C6819B118761CaAF61946])
│ └─ ← [Return]
├─ [6838] Game::updatePlatformFeePercentage(99)
│ ├─ emit PlatformFeePercentageUpdated(newPlatformFeePercentage: 99)
│ └─ ← [Stop]
├─ [0] VM::prank(player2: [0xEb0A3b7B96C1883858292F0039161abD287E3324])
│ └─ ← [Return]
├─ [50121] Game::claimThrone{value: 1020000000000000000}()
│ ├─ emit ThroneClaimed(newKing: player2: [0xEb0A3b7B96C1883858292F0039161abD287E3324], claimAmount: 1020000000000000000 [1.02e18], newClaimFee: 121000000000000000 [1.21e17], newPot: 960200000000000000 [9.602e17], timestamp: 1)
│ └─ ← [Stop]
├─ [0] VM::prank(player3: [0xcC37919fDb8E2949328cDB49E8bAcCb870d0c9f3])
│ └─ ← [Return]
│ └─ ← [Stop]
├─ [0] VM::prank(deployer: [0xaE0bDc4eEAC5E950B67C6819B118761CaAF61946])
│ └─ ← [Return]
├─ [6838] Game::updatePlatformFeePercentage(99)
│ ├─ emit PlatformFeePercentageUpdated(newPlatformFeePercentage: 99)
│ └─ ← [Stop]
├─ [0] VM::prank(player2: [0xEb0A3b7B96C1883858292F0039161abD287E3324])
│ └─ ← [Return]
├─ [50121] Game::claimThrone{value: 1020000000000000000}()
│ ├─ emit ThroneClaimed(newKing: player2: [0xEb0A3b7B96C1883858292F0039161abD287E3324], claimAmount: 1020000000000000000 [1.02e18], newClaimFee: 121000000000000000 [1.21e17], newPot: 960200000000000000 [9.602e17], timestamp: 1)
│ └─ ← [Stop]
├─ [0] VM::prank(player3: [0xcC37919fDb8E2949328cDB49E8bAcCb870d0c9f3])
│ └─ ← [Return]
│ ├─ emit PlatformFeePercentageUpdated(newPlatformFeePercentage: 99)
│ └─ ← [Stop]
├─ [0] VM::prank(player2: [0xEb0A3b7B96C1883858292F0039161abD287E3324])
│ └─ ← [Return]
Recommended Mitigation:
By adding the modifier gameEndedOnly will mitigate the vunerability.
- function updateClaimFeeParameters(
- uint256 _newInitialClaimFee,
- uint256 _newFeeIncreasePercentage
- ) external onlyOwner isValidPercentage(_newFeeIncreasePercentage)
+ function updateClaimFeeParameters(
+ uint256 _newInitialClaimFee,
+ uint256 _newFeeIncreasePercentage
+ ) external ganeEndedOnly onlyOwner isValidPercentage(_newFeeIncreasePercentage)