MyCut

AI First Flight #8
Beginner FriendlyFoundry
EXP
View results
Submission Details
Impact: low
Likelihood: low
Invalid

Unused custom Error

Root + Impact

Gas inefficiency due to storing and emitting string literals instead of custom errors.

Description

  • While the Pot contract correctly implements some custom errors (e.g., Pot__RewardNotFound), if there are any remaining require(condition, "String message") statements within the broader codebase (like the ContestManager), they will consume unnecessary gas. Solidity 0.8.4 introduced custom errors, which allow developers to define errors using the error keyword. Unlike string messages, custom errors do not require storing large strings in the contract bytecode, making them significantly cheaper to deploy and execute when a revert triggers.

Risk

  • Reason 1: It is a common leftover from older Solidity codebases (pre-0.8.4) or standard library imports.

  • Reason 2: Developers often default to require statements for quick debugging during development.

Impact

  • Impact 1: Increased deployment gas costs because string literals take up more bytes in the compiled bytecode.

  • Impact 2: Increased runtime gas costs when a transaction reverts, as the EVM has to allocate memory for the string array.


Proof of Concept

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {
IERC20
} from "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
import {Ownable} from "lib/openzeppelin-contracts/contracts/access/Ownable.sol";
contract Pot is Ownable(msg.sender) {
error Pot__RewardNotFound();
error Pot__InsufficientFunds(); -> "unused"
error Pot__StillOpenForClaim(); -> "unused"
address[] private i_players;
uint256[] private i_rewards;
address[] private claimants;
uint256 private immutable i_totalRewards;
uint256 private immutable i_deployedAt;
IERC20 private immutable i_token;
mapping(address => uint256) private playersToRewards;
uint256 private remainingRewards;
uint256 private constant managerCutPercent = 10;
constructor(
address[] memory players,
uint256[] memory rewards,
IERC20 token,
uint256 totalRewards
) {
i_players = players;
i_rewards = rewards;
i_token = token;
i_totalRewards = totalRewards;
remainingRewards = totalRewards;
i_deployedAt = block.timestamp;
// i_token.transfer(address(this), i_totalRewards);
for (uint256 i = 0; i < i_players.length; i++) {
playersToRewards[i_players[i]] = i_rewards[i];
}
}
function claimCut() public {
address player = msg.sender;
uint256 reward = playersToRewards[player];
if (reward <= 0) {
revert Pot__RewardNotFound();
}
playersToRewards[player] = 0;
remainingRewards -= reward;
claimants.push(player);
_transferReward(player, reward);
}
function closePot() external onlyOwner {
if (block.timestamp - i_deployedAt < 90 days) {
revert Pot__StillOpenForClaim();
}
if (remainingRewards > 0) {
uint256 managerCut = remainingRewards / managerCutPercent;
i_token.transfer(msg.sender, managerCut);
uint256 claimantCut = (remainingRewards - managerCut) /
i_players.length;
for (uint256 i = 0; i < claimants.length; i++) {
_transferReward(claimants[i], claimantCut);
}
}
}
function _transferReward(address player, uint256 reward) internal {
i_token.transfer(player, reward);
}
function getToken() public view returns (IERC20) {
return i_token;
}
function checkCut(address player) public view returns (uint256) {
return playersToRewards[player];
}
function getRemainingRewards() public view returns (uint256) {
return remainingRewards;
}
}

Recommended Mitigation

Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 8 hours ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!