Rock Paper Scissors

First Flight #38
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: low
Invalid

Repeated Admin Check Logic in Multiple Functions Should Use a Modifier

Summary

The RockPaperScissors contract repeats the require(msg.sender == adminAddress, ...) check in multiple functions (setAdminAddress, withdrawTokens, setGameTimeout), reducing code maintainability. A custom modifier would centralize this logic.

Vulnerability Details

The RockPaperScissors contract uses the require(msg.sender == adminAddress, "Only admin can set new admin") check (or similar variations) in at least three functions: setAdminAddress, withdrawTokens, and setGameTimeout. This repetition of admin access control logic increases the risk of inconsistency if the admin address or error message needs to change. For example, updating the admin check would require modifying each instance individually, which is error-prone and violates the DRY (Don’t Repeat Yourself) principle. Centralizing the logic in a modifier would improve readability and maintainability.

Impact

  • Reduced code readability due to repeated admin check logic across multiple functions.

  • Increased maintenance burden, as changes to the admin address or error message require updating at least three function instances, risking inconsistencies.

  • Potential for bugs if one instance is overlooked during updates (e.g., using a different error message or condition).

  • No security impact, but violates best practices for clean, maintainable smart contract code, justifying low severity.

Tools Used

Manual Code Review

Recommendations

Introduce a custom onlyAdmin modifier to centralize the admin access check, replacing repeated require(msg.sender == adminAddress, ...) statements. Apply the modifier to all admin-only functions to improve readability and maintainability.

modifier onlyAdmin() {
require(msg.sender == adminAddress, "Only admin can call this function");
_;
}
- function setAdminAddress(address _newAdmin) external {
- require(msg.sender == adminAddress, "Only admin can set new admin");
+ function setAdminAddress(address _newAdmin) external onlyAdmin {
adminAddress = _newAdmin;
}
- function withdrawTokens(address _to, uint256 _amount) external {
- require(msg.sender == adminAddress, "Only admin can withdraw tokens");
+ function withdrawTokens(address _to, uint256 _amount) external onlyAdmin {
winningToken.transfer(_to, _amount);
}
- function setGameTimeout(uint256 _gameId, uint256 _timeout) external {
- require(msg.sender == adminAddress, "Only admin can set game timeout");
+ function setGameTimeout(uint256 _gameId, uint256 _timeout) external onlyAdmin {
games[_gameId].timeoutInterval = _timeout;
}
Updates

Appeal created

m3dython Lead Judge 2 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational

Code suggestions or observations that do not pose a direct security risk.

m3dython Lead Judge 2 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational

Code suggestions or observations that do not pose a direct security risk.

Support

FAQs

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