Platform: Code4rena
Start Date: 25/08/2022
Pot Size: $75,000 USDC
Total HM: 35
Participants: 147
Period: 7 days
Judge: 0xean
Total Solo HM: 15
Id: 156
League: ETH
Rank: 34/147
Findings: 4
Award: $584.04
π Selected for report: 1
π Solo Findings: 0
π Selected for report: GalloDaSballo
347.2615 DAI - $347.26
https://github.com/code-423n4/2022-08-olympus/blob/main/src/policies/VoterRegistration.sol#L45 https://github.com/code-423n4/2022-08-olympus/blob/main/src/policies/VoterRegistration.sol#L53
"voter_admin"
has the ability to mint/burn
any arbitrary amount of VOTES
. Creating a centralization risk that allows "voter_admin"
to pass or veto any proposal.
issueVotesTo()
to an arbitrary wallet and then vote no
on the proposal.
a. Could also issue set number of votes to arbitrary wallet so that Alice's proposal doesn't pass the 20% of totalSupply()
check to be voted on.Manual Review
I don't really see any good fixes for this so, consider documenting this so that users can know.
#0 - 0xLienid
2022-09-07T15:21:54Z
Permissioned wallets having access to permission-gated functions is intended functionality.
#1 - 0xean
2022-09-19T23:34:35Z
dupe of #380
11.0311 DAI - $11.03
https://github.com/code-423n4/2022-08-olympus/blob/main/src/modules/PRICE.sol#L161 https://github.com/code-423n4/2022-08-olympus/blob/main/src/modules/PRICE.sol#L170
Across these contracts, you are using Chainlink's latestRoundData
API, but there is only a check on updatedAt
. This could lead to stale prices according to the Chainlink documentation:
The result of latestRoundData
API will be used across various functions, therefore, a stale price from Chainlink can lead to loss of funds to end-users.
Manual Review
Consider adding the missing checks for stale data.
For example:
(uint80 roundID ,answer,, uint256 timestamp, uint80 answeredInRound) = AggregatorV3Interface(chainLinkAggregatorMap[underlying]).latestRoundData(); require(answer > 0, "Chainlink price <= 0"); require(answeredInRound >= roundID, "Stale price"); require(timestamp != 0, "Round not complete");
#0 - Oighty
2022-09-06T18:49:44Z
Agree. We'll add the additional checks.
π Selected for report: zzzitron
Also found by: 0x040, 0x1f8b, 0x52, 0x85102, 0xDjango, 0xNazgul, 0xNineDec, 0xSky, 0xSmartContract, 0xkatana, 8olidity, Aymen0909, Bahurum, BipinSah, Bnke0x0, CRYP70, CertoraInc, Ch_301, Chandr, Chom, CodingNameKiki, Deivitto, DimSon, Diraco, ElKu, EthLedger, Funen, GalloDaSballo, Guardian, IllIllI, JansenC, Jeiwan, Lambda, LeoS, Margaret, MasterCookie, PPrieditis, PaludoX0, Picodes, PwnPatrol, RaymondFam, ReyAdmirado, Rohan16, Rolezn, Ruhum, Sm4rty, StevenL, The_GUILD, TomJ, Tomo, Trust, Waze, __141345__, ajtra, ak1, apostle0x01, aviggiano, bin2chen, bobirichman, brgltd, c3phas, cRat1st0s, carlitox477, cccz, ch13fd357r0y3r, cloudjunky, cryptphi, csanuragjain, d3e4, datapunk, delfin454000, devtooligan, dipp, djxploit, durianSausage, eierina, enckrish, erictee, fatherOfBlocks, gogo, grGred, hansfriese, hyh, ignacio, indijanc, itsmeSTYJ, ladboy233, lukris02, martin, medikko, mics, natzuu, ne0n, nxrblsrpr, okkothejawa, oyc_109, p_crypt0, pfapostol, prasantgupta52, rajatbeladiya, rbserver, reassor, ret2basic, robee, rokinot, rvierdiiev, shenwilly, sikorico, sorrynotsorry, tnevler, tonisives, w0Lfrum, yixxas
161.3786 DAI - $161.38
Severity: Low
Context: RANGE.sol#L263
, PRICE.sol#L240
, PRICE.sol#L266
, Operator.sol#L516
, Operator.sol#L527
, Operator.sol#L548
, Operator.sol#L559
, Operator.sol#L586
, Heart.sol#L130
, Heart.sol#L135
, Heart.sol#L140
Description: When critical parameters of systems need to be changed, it is required to broadcast the change via event emission and recommended to enforce the changes after a time-delay. This is to allow system users to be aware of such critical changes and give them an opportunity to exit or adjust their engagement with the system accordingly. None of the onlyOwner functions that change critical protocol addresses/parameters have a timelock for a time-delayed change to alert: (1) users and give them a chance to engage/exit protocol if they are not agreeable to the changes (2) team in case of compromised owner(s) and give them a chance to perform incident response.
Recommendation: Users may be surprised when critical parameters are changed. Furthermore, it can erode users' trust since they canβt be sure the protocol rules wonβt be changed later on. Compromised owner keys may be used to change protocol addresses/parameters to benefit attackers. Without a time-delay, authorized owners have no time for any planned incident response.
Severity: Low
Context: Kernel.sol#L77
, Kernel.sol#L127
, Kernel.sol#L251
, Kernel.sol#L253
, TRSRY.sol#L122
, RANGE.sol#L242
, RANGE.sol#L263
, PRICE.sol#L240
, PRICE.sol#L266
, Operator.sol#L516
, Operator.sol#L527
, Operator.sol#L548
, Operator.sol#L559
, Operator.sol#L586
, BondCallback.sol#L190
, Heart.sol#L130
, Heart.sol#L135
, Heart.sol#L140
Description: Setter functions are missing checks to validate if the new value being set is the same as the current value already set in the contract. Such checks will showcase mismatches between on-chain and off-chain states.
Recommendation: This may hinder detecting discrepancies between on-chain and off-chain states leading to flawed assumptions of on-chain state and protocol behavior.
Severity: Low
Context: Kernel.sol#L77
, Kernel.sol#L251
, Kernel.sol#L253
, BondCallback.sol#L190
, Heart.sol#L140
Description: Lack of zero-address validation on address parameters may lead to transaction reverts, waste gas, require resubmission of transactions and may even force contract redeployments in certain cases within the protocol.
Recommendation: Consider adding explicit zero-address validation on input parameters of address type.
Severity: Low
Context: Kernel.sol#L77
, Kernel.sol#L127
, Kernel.sol#L251
, Kernel.sol#L253
, BondCallback.sol#L190
, Heart.sol#L130
, Heart.sol#L135
Description: Several functions update critical parameters that are missing event emission. These should be performed to ensure tracking of changes of such critical parameters.
Recommendation: Consider adding events to functions that change critical parameters.
Severity: Low
Context: PRICE.sol#L205
, Operator.sol#L598
, PriceConfig.sol#L45
Description: None of the initialize functions emit emit init-specific events. They all however have the initializer modifier (from Initializable) so that they can be called only once. Off-chain monitoring of calls to these critical functions is not possible.
Recommendation: It is recommended to emit events in your initialization functions.
Severity Informational
Context: VOTES#L47
Description: There is unreachable code that can be removed to clean up the code.
Recommendation: Consider removing the unreachable code to clean it up.
ERC20
Token Name "OlympusDAO Dummy Voting Tokens"
Severity Informational
Context: VOTES#L18
Description: This was probably meant as a joke during testing and should probably be renamed for production to not confuse users.
Recommendation:
Consider renaming the votes module ERC20
token name "OlympusDAO Dummy Voting Tokens"
to "OlympusDAO Voting Tokens"
.
Severity Informational
Context: Kernel.sol#L131
, PRICE.sol#L59
, TreasuryCustodian.sol#L20
, Operator.sol#L69-L72
, Heart.sol#L45
, PriceConfig.sol#L11
Description:
The linked variables do not conform to the standard naming convention of Solidity whereby functions and variable names(local and state) utilize the mixedCase
format unless variables are declared as constant
in which case they utilize the UPPER_CASE_WITH_UNDERSCORES
format. Internal/private functions and variables should lead with an _underscore
.
Recommendation: Consider naming conventions utilized by the linked statements are adjusted to reflect the correct type of declaration according to the Solidity style guide.
Severity: Informational
Context: Kernel.sol#L71
, Kernel.sol#L89
, Kernel.sol#L120
, Kernel.sol#L224-L230
, TRSRY.sol#L20-L39
, RANGE.sol#L20-L31
, PRICE.sol#L26-L28
, INSTR.sol#L11
, TreasuryCustodian.sol#L17
, Operator.sol#L45-L54
, Operator.sol#L188
, Governance.sol#L61-L137
Description: The best-practice layout for a contract should follow the following order: state variables, events, modifiers, constructor and functions. Function ordering helps readers identify which functions they can call and find constructor and fallback functions easier. Functions should be grouped according to their visibility and ordered as: constructor, receive function (if exists), fallback function (if exists), external, public, internal, private. Some constructs deviate from this recommended best-practice: Modifiers are in the middle of contracts. External/public functions are mixed with internal/private ones. Few events are declared in contracts while most others are in corresponding interfaces.
Recommendation: Consider adopting recommended best-practice for code structure and layout.
Severity: Informational
Context: RANGE.sol#L40
, RANGE.sol#L44
, RANGE.sol#L46-L48
, RANGE.sol#L61-L62
, RANGE.sol#L214
, RANGE.sol#L239-L240
, RANGE.sol#L261-L262
, PRICE.sol#L19-L20
, PRICE.sol#L31
, PRICE.sol#L39-L40
, PRICE.sol#L46
, PRICE.sol#L78
, PRICE.sol#L120
, PRICE.sol#L189
, PRICE.sol#L201
, PRICE.sol#L203
, PRICE.sol#L263-L264
, Operator.sol#L97
, Operator.sol#L199
, Operator.sol#L481
, Operator.sol#L657
, Operator.sol#L730
, Operator.sol#L734
, PriceConfig.sol#L41
, PriceConfig.sol#L43
, PriceConfig.sol#L66-L67
, Governance.sol#L119
, Governance.sol#L156
, Governance.sol#L158
, IBondCallback.sol#L7
, IOperator.sol#L13
, IOperator.sol#L15-L17
, IOperator.sol#L34
, IOperator.sol#L72-L73
, IOperator.sol#L79
, IOperator.sol#L84
, IOperator.sol#L90-L91
, IOperator.sol#L100
, IOperator.sol#L108
, IOperator.sol#L124
, IOperator.sol#L130
, IOperator.sol#L135
, IOperator.sol#L141
Description: Max line length must be no more than 120 but many comments are extended past this length.
Recommendation: Consider cutting down the line length below 120.
Severity: Informational
Context: Kernel.sol#L85
, Kernel.sol#L95
, Kernel.sol#L100
, Kernel.sol#L105
, Kernel.sol#L115
, Kernel.sol#L139
, Kernel.sol#L143
, TRSRY.sol#L45
, VOTES.sol#L19
, INSTR.sol#L20
, TreasuryCustodian.sol#L24
, PriceConfig.sol#L15
, Governance.sol#L59
, VoterRegistration.sol#L16
Description: It's best practice that when there is an empty block, to add a comment in the block explaining why it's empty.
Recommendation:
Consider adding /* Comment on why */
to the empty blocks.
Severity: Informational
Context: RANGE.sol#L245
, RANGE.sol#L247
, RANGE.sol#L264
, Operator.sol#L111
, Operator.sol#L518
, Operator.sol#L550
, Governance.sol#L164
Description: There are multiple occasions where certain numbers have been hardcoded, either in variables or in the code itself. Large numbers can become hard to read.
Recommendation: Consider using underscores for number literals to improve its readability.
Severity: Informational
Context: TreasuryCustodian.sol#L51-L52
, TreasuryCustodian.sol#L56
, Operator.sol#L657
Description: There should never be any TODOs in the code when deploying.
Recommendation: Consider finishing the TODOs before deploying.
Severity: Informational
Context: PRICE.sol#L126 (numbe => number)
, Operator.sol#L295 (deactive => deactivate)
, Operator.sol#L326 (deactive => deactivate)
Description: Spelling errors in comments can cause confusion to both users and developers.
Recommendation: Consider checking all misspellings to ensure they are corrected..
Severity: Informational
Context: All Contracts
Description: Some functions are missing @notice/@dev NatSpec comments for the function, @param for all/some of their parameters and @return for return values. Given that NatSpec is an important part of code documentation, this affects code comprehension, auditability and usability.
Recommendation: Consider adding in full NatSpec comments for all functions to have complete code documentation for future use.
Severity: Informational
Context: All Contracts
Description: Using very old versions of Solidity prevents benefits of bug fixes and newer security checks. Using the latest versions might make contracts susceptible to undiscovered compiler bugs.
Recommendation: Consider using the most recent version.
#0 - 0xLienid
2022-09-09T02:31:35Z
Valid, not going to add unnecessary code for 0x0 and equivalence checks since the system is permissioned. Olympus Dummy Token is a stand-in for internal testing. otherwise looks good.
π Selected for report: pfapostol
Also found by: 0x040, 0x1f8b, 0x85102, 0xDjango, 0xNazgul, 0xNineDec, 0xSmartContract, 0xkatana, Amithuddar, Aymen0909, Bnke0x0, CertoraInc, Chandr, CodingNameKiki, Deivitto, Dionysus, Diraco, ElKu, Fitraldys, Funen, GalloDaSballo, Guardian, IllIllI, JC, JansenC, Jeiwan, LeoS, Metatron, Noah3o6, RaymondFam, ReyAdmirado, Rohan16, RoiEvenHaim, Rolezn, Ruhum, Saintcode_, Shishigami, Sm4rty, SooYa, StevenL, Tagir2003, The_GUILD, TomJ, Tomo, Waze, __141345__, ajtra, apostle0x01, aviggiano, bobirichman, brgltd, c3phas, cRat1st0s, carlitox477, cccz, ch0bu, chrisdior4, d3e4, delfin454000, djxploit, durianSausage, erictee, exolorkistis, fatherOfBlocks, gogo, grGred, hyh, ignacio, jag, karanctf, kris, ladboy233, lukris02, m_Rassska, martin, medikko, natzuu, ne0n, newfork01, oyc_109, peiw, rbserver, ret2basic, robee, rokinot, rvierdiiev, sikorico, simon135, tnevler, zishansami
64.3735 DAI - $64.37
if (proposalHasBeenActivated[proposalId_] == true)
Context: Governance.sol#L230-L232
Description: Moving:
if (proposalHasBeenActivated[proposalId_] == true) { revert ProposalAlreadyActivated(); }
earlier in activateProposal()
will make it fail sooner and save gas.
Recommendation:
Consider moving if (proposalHasBeenActivated[proposalId_] == true)
earlier in activateProposal()
Immutable
Context: BondCallback.sol#L28
, BondCallback.sol#L32
Description:
Solidity 0.6.5
introduced immutable
as a major feature. It allows setting contract-level variables at construction time which gets stored in code rather than storage. Each call to it reads from storage, using a sload
costing 2100 gas cold or 100 gas warm. Setting it to immutable
will have each storage read of the state variable to be replaced by the instruction push32 value
, where value
is set during contract construction time and this costs only 3 gas.
Recommendation:
Set the state variable to immutable
.
Context: Operator.sol#L372
, Operator.sol#L427
Description:
The SHR
opcode is 3 gas cheaper than DIV
and also bypasses Solidity's division by 0 prevention overhead.
Recommendation: Consider using right shift instead of dividing by 2.
Context: Kernel.sol#L439
, Kernel.sol#L451
, TRSRY.sol#L75
, MINTR.sol#L33
, MINTR.sol#L37
, RANGE.sol#L215
, VOTES.sol#L45
, VOTES.sol#L51
, INSTR.sol#L37
, Governance.sol#L145
, Governance.sol#L151
Description: Several functions across multiple contracts have a public visibility and can be marked with external visibility to save gas.
Recommendation: Change the functions visibility to external to save gas.
calldata
Instead of memory
For Function ParametersContext: TreasuryCustodian.sol#L53
, BondCallback.sol#L152
Description: The dynamic array arr has the storage location memory. When the function gets called externally, the array values are kept in calldata and copied to memory during ABI decoding (using the opcode calldataload and mstore). And during the for loop, arr[i] accesses the value in memory using a mload.
Recommendation:
Use calldata
instead of memory
for function parameters to avoid using memory with array values when a function is getting called externally.
arr[i] = arr[i] + 1
is cheaper than arr[i] += 1
Context: TRSRY.sol#L96-L97
, TRSRY.sol#L131
, VOTES.sol#L58
, BondCallback.sol#L143-L144
, Governance.sol#L198
, Governance.sol#L252
, Governance.sol#254
Description: Due to stack operations this is 25 gas cheaper when dealing with arrays in storage, and 4 gas cheaper for memory arrays.
Recommendation:
Use arr[i] = arr[i] + 1
instead of arr[i] += 1
when dealing with arrays
++index
instead of index++
to increment a loop counterContext: KernelUtils.sol#L49
, KernelUtils.sol#L64
Description:
Due to reduced stack operations, using ++index
saves 5 gas per iteration.
Recommendation:
Use ++index
to increment a loop counter.
2**256 - 1 && type(uint256).max
When 2**255
Can Be UsedContext: TRSRY.sol#L147
, RANGE.sol#L88
, RANGE.sol#L95
, RANGE.sol#L221
, RANGE.sol#L230
, Operator.sol#L167
, Operator.sol#L477
, Operator.sol#L603
, BondCallback.sol#L57
, BondCallback.sol#L95
Description:
Infinity can also be represented via ``2255, it's hex representation is
0x8000000000000000000000000000000000000000000000000000000000000000while
2256 - 1is
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`. Then main difference is and where the gas savings come from is, zeros are cheaper than non-zero values in hex representation.
Recommendation:
Use 2**255
instead of 2**256 - 1
to save gas on deployment.
Context: All Contracts
Description:
You can cut out 10 opcodes in the creation-time EVM bytecode if you declare a constructor payable. Making the constructor payable eliminates the need for an initial check of msg.value == 0
and saves 21 gas on deployment with no security risks.
Recommendation: Set the constructor to payable.
Context: All Contracts
Description:
Contracts most called functions could simply save gas by function ordering via Method ID. Calling a function at runtime will be cheaper if the function is positioned earlier in the order (has a relatively lower Method ID) because 22 gas are added to the cost of a function for every position that came before it. The caller can save on gas if you prioritize most called functions. One could use This tool
to help find alternative function names with lower Method IDs while keeping the original name intact.
Recommendation:
Find a lower method ID name for the most called functions for example mostCalled()
vs. mostCalled_41q()
is cheaper by 44 gas.