Last Man Standing

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

Unnecessary State Updates & Redundant Event Emissions Causing Gas Waste and Log Pollution

Root + Impact

Root Cause: No “no-op” guard and redundant events on identical updates -> Impact: Excessive SSTORE gas, bloated logs, and potential griefing through forced expensive transactions and log spam

Description

  • Several owner-only functions in Game.sol update configuration parameters without first checking if the new values differ from the current ones and unconditionally emit events—even when nothing changes:

  • updateGracePeriod(uint256 _newGracePeriod)

  • updateClaimFeeParameters(uint256 _newInitialClaimFee, uint256 _newFeeIncreasePercentage)

  • updatePlatformFeePercentage(uint256 _newPlatformFeePercentage)

  • Each identical update triggers:

  1. An SSTORE write, costing up to ~20 000 gas per slot.

  2. An event emission, which stores data in the transaction log—incurring additional gas and polluting the logs with meaningless entries.

function updateGracePeriod(uint256 _newGracePeriod) external onlyOwner {
require(_newGracePeriod > 0, "Game: New grace period must be greater than zero.");
@> // ❌ No-op guard: allows identical values
gracePeriod = _newGracePeriod; // Unnecessary SSTORE
emit GracePeriodUpdated(_newGracePeriod); // Redundant event
}
function updateClaimFeeParameters(uint256 _newInitialClaimFee, uint256 _newFeeIncreasePercentage)
external onlyOwner isValidPercentage(_newFeeIncreasePercentage)
{
require(_newInitialClaimFee > 0, "Game: New initial claim fee must be greater than zero.");
@> // ❌ No-op guard
initialClaimFee = _newInitialClaimFee; // Unnecessary SSTORE
feeIncreasePercentage = _newFeeIncreasePercentage; // Unnecessary SSTORE
emit ClaimFeeParametersUpdated(_newInitialClaimFee, _newFeeIncreasePercentage); // Redundant event
}
function updatePlatformFeePercentage(uint256 _newPlatformFeePercentage)
external onlyOwner isValidPercentage(_newPlatformFeePercentage)
{
@> // ❌ No-op guard
platformFeePercentage = _newPlatformFeePercentage; // Unnecessary SSTORE
emit PlatformFeePercentageUpdated(_newPlatformFeePercentage); // Redundant event
}
  • State Update: Always writes to storage, even if the value hasn’t changed.

  • Event Emission: Always logs an update event, regardless of whether any meaningful change occurred.

Risk

Likelihood: High

  • Over time or via malicious governance spamming, these no-op calls and redundant events lead to significant gas waste, bloated archives, harder log filtering, and can be weaponized to grief users by driving up block gas usage.

Impact: Gas

  • Gas Waste: Useless SSTOREs and log writes burn hundreds of millions of gas over repeated calls.

  • Log Pollution: Spamming events makes it difficult to distinguish genuine configuration changes from noise.

  • Governance Griefing: A malicious owner or proposal can force network participants to pay for irrelevant updates, creating friction and distrust.

  • Audit Overhead: Event logs become cluttered, complicating on-chain analytics and forensic audits.

Tools Used:

  • Foundry Test Suite

  • Chat-GPT AI Assistance (Report Grammar Check & Improvements)

  • Manual Review

Proof of Concept

function test_missingChecksForUnnecessary_identical_values_update() public {
uint256 gracePeriod = game.gracePeriod();
uint256 claimFee = game.claimFee();
uint256 feeIncreasePercentage = game.feeIncreasePercentage();
uint256 platformFeePercentage = game.platformFeePercentage();
vm.startPrank(deployer);
game.updateGracePeriod(GRACE_PERIOD);
vm.stopPrank();
vm.startPrank(deployer);
game.updateClaimFeeParameters(INITIAL_CLAIM_FEE, FEE_INCREASE_PERCENTAGE);
vm.stopPrank();
vm.startPrank(deployer);
game.updatePlatformFeePercentage(PLATFORM_FEE_PERCENTAGE);
vm.stopPrank();
assertEq(game.gracePeriod(), gracePeriod);
assertEq(game.claimFee(), claimFee);
assertEq(game.feeIncreasePercentage(), feeIncreasePercentage);
assertEq(game.platformFeePercentage(), platformFeePercentage);
}

step 1: go to test/Game.t.sol file

step 2: paste the above code ⬆️

step 3: run the test suite unit

forge test --mt test_missingChecksForUnnecessary_identical_values_update

step 4: See the Output

Measure gas before/after inserting no-op guards will show per-call savings of ~20 000–40 000 gas plus log data costs.

Scenario:

An automated governance script inadvertently re-submits a parameter-change proposal with the same values. Each execution:

  1. Writes the same value into storage, burning ~20 000 gas per slot.

  2. Emits the update event, adding extra log data and gas cost (~375 gas + data).

A malicious owner could spam these calls to inflate gas consumption and pollute event logs, making off-chain analytics and filtering more difficult.

Recommended Mitigation

Add “No-Op” Guards

+ require(_newGracePeriod != gracePeriod, "Game: Grace period unchanged.");
gracePeriod = _newGracePeriod;
emit GracePeriodUpdated(_newGracePeriod);

Conditionally Emit Events
Only emit if the storage write actually occurs and state updates.

Updates

Appeal created

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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

Give us feedback!