Platform: Code4rena
Start Date: 21/12/2023
Pot Size: $90,500 USDC
Total HM: 10
Participants: 39
Period: 18 days
Judge: LSDan
Total Solo HM: 5
Id: 315
League: ETH
Rank: 33/39
Findings: 1
Award: $21.90
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: IllIllI
Also found by: 0x11singh99, 0xA5DF, 0xMilenov, 0xTheC0der, 7ashraf, Bauchibred, EV_om, Kaysoft, Sathish9098, SpicyMeatball, cheatc0d3, erebus, hash, imare, immeas, joaovwfreire, lil_eth, lsaudit, oakcobalt, para8956, peanuts, rvierdiiev, slvDev, trachev
21.8971 USDC - $21.90
GovernorCompatibilityBravo
version 4.8.3There is 1 instance of this
According to Openzeppelin's security disclosure here: https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-5h3x-9wvq-w4m2
There is a security vulnerability with the GovernorCompatibilityBravo
contract particularly the propose(...)
function which is used in the GovernorOLAS
contract due to the order of the inherited contracts.
contract GovernorOLAS is Governor, GovernorSettings, GovernorCompatibilityBravo, GovernorVotes, GovernorVotesQuorumFraction, GovernorTimelockControl {
Due to the order of the parent contracts and how Solidity inheritance work, the super
keyword in the propose(...)
function below invokes the vulnerable GovernorCompatibilityBravo.propose(...)
function.
File: governance/contracts/GovernorOLAS.sol 45: function propose( 46: address[] memory targets, 47: uint256[] memory values, 48: bytes[] memory calldatas, 49: string memory description 50: ) public override(IGovernor, Governor, GovernorCompatibilityBravo) returns (uint256) 51: { 52: return super.propose(targets, values, calldatas, description); 53: }
References
Recommendation: Consider updating the openzeppelin library to version 4.9.3.
There are 3 instances of this.
ComponentRegistry#constructor._baseURI
shadows the parent's ERC721._baseURI
storage variable. Variable shadowing can easily lead to a security issue when one of the two variables is referenced instead of the other.File: registry/contracts/ComponentRegistry.sol 16:constructor(string memory _name, string memory _symbol, string memory _baseURI) 17: UnitRegistry(UnitType.Component) 18: ERC721(_name, _symbol) 19: { 20: baseURI = _baseURI;//@audit-info variable shadowing ERC721._baseURI 21: owner = msg.sender; 22: }
timelock
parameter of GovernorOLAS.sol#constructor(...)
shadows IGovernorTimelock.timelock
.see SWC-119 here: https://swcregistry.io/docs/SWC-119/
Recommendation: Consider renaming the ComponentRegistry#constructor._baseURI
constructor parameter.
open source libraries like OZ have undergone several security audits, have stood the test of time, have been battle tested so it is safer to use these libraries that also reduce development time and also makes the code modular.
There are 4 instances of this
There are 2 instancees of this:
There are 3 instances of this:
The GenericRegistry ERC721 contract implements the tokenByIndex(...)
function which is an ERC721Enumerable feature. Consider using Openzeppelin's ERC721Enumerable to avoid potential issues.
There is 1 instance of this:
There is 1 instances of this:
The errorname used in the if condition below is wrong. it should be something like "Unavailable" or "NotFound".
File: registries/contracts/GenericRegistry.sol 97: function tokenByIndex(uint256 id) external view virtual returns (uint256 unitId) { 98: unitId = id + 1; 99: if (unitId > totalSupply) { 100: revert Overflow(unitId, totalSupply);//@audit this is not overflow error 101: } }
Recommendation: use an error name that reflects the condition that happened in the function.
There is 1 instance of this
Since the _locked
storage variable is used for reentrancy guard, there is no need setting the value of _locked
in the initialize function of the Tokenomics function.
291: function initializeTokenomics( 292: address _olas, 293: address _treasury, 294: address _depository, 295: address _dispenser, 296: address _ve, 297: uint256 _epochLen, 298: address _componentRegistry, 299: address _agentRegistry, 300: address _serviceRegistry, 301: address _donatorBlacklist 302: ) external 303: { ... 264: _locked = 1;//@audit unnecessary state update since there is no reentrance risk in initialze function. ... 370: }
Recommendation: remove _locked
state update above.
There is 1 instance:
The Tokenomics.sol contract is the implementation contract for the TokenomicsProxy.sol proxy contract. The TokenomicsProxy.sol
is expected to call the initialize function of its Tokenomic.sol
implementation through a delegate call.
In a situation where the Tokenomics.sol
implementation contract is not separately initialized, anyone can initialize the Tokenomics.sol
implementation contract which could lead to potential security issue for the proxy contract for example if an implementation contract can be taken over and destroyed.
File: tokenomics/contracts/Tokenomics.sol 264: function initializeTokenomics( 265: address _olas, 266: address _treasury, 267: address _depository, 268: address _dispenser, 269: address _ve, 270: uint256 _epochLen, 271: address _componentRegistry, 272: address _agentRegistry, 273: address _serviceRegistry, 274: address _donatorBlacklist 275: ) external 276: { 277: // Check if the contract is already initialized 278: if (owner != address(0)) { 279: revert AlreadyInitialized(); 280: } 281: 282: // Check for at least one zero contract address 283: if (_olas == address(0) || _treasury == address(0) || _depository == address(0) || _dispenser == address(0) || 284: _ve == address(0) || _componentRegistry == address(0) || _agentRegistry == address(0) || 285: _serviceRegistry == address(0)) { 286: revert ZeroAddress(); 287: } ... 370:}
Recommendation : Use Openzepelin's initializable library, initializable modifier on the Tokenomics.sol#initialize(...)
founction and it's _disableInitializers()
function in the constructor of the Tokenomics.sol
implementation contract as below.
import { Initializable} from "OpenZeppelin/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol"; Tokenomics is Initializable { /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } function initialize(...) initializer public { ... } ... }
#0 - c4-pre-sort
2024-01-10T14:45:15Z
alex-ppg marked the issue as sufficient quality report
#1 - alex-ppg
2024-01-10T14:51:39Z
L-1 dupe of #357 L-6 dupe of #436
#2 - c4-judge
2024-01-18T18:28:19Z
dmvt marked the issue as grade-b