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: 76/147
Findings: 2
Award: $86.95
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 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
54.3133 DAI - $54.31
There are 2 instances of this issue:
File: Kernel.sol 251: executor = target_; 253: admin = target_;
https://github.com/code-423n4/2022-08-olympus/blob/main/src/Kernel.sol
safeMint()
should be used rather than _mint()
wherever possibleThere are 1 instances of this issue:
File: modules/VOTES.sol 36: _mint(wallet_, amount_);
https://github.com/code-423n4/2022-08-olympus/blob/main/src/modules/VOTES.sol
indexed
fieldsThere are 23 instances of this issue:
File: policies/Governance.sol 86: event ProposalSubmitted(uint256 proposalId); 87: event ProposalEndorsed(uint256 proposalId, address voter, uint256 amount); 88: event ProposalActivated(uint256 proposalId, uint256 timestamp); 89: event WalletVoted(uint256 proposalId, address voter, bool for_, uint256 userVotes); 90: event ProposalExecuted(uint256 proposalId);
https://github.com/code-423n4/2022-08-olympus/blob/main/src/policies/Governance.sol
File: policies/Heart.sol 28: event Beat(uint256 timestamp_); 29: event RewardIssued(address to_, uint256 rewardAmount_); 30: event RewardUpdated(ERC20 token_, uint256 rewardAmount_);
https://github.com/code-423n4/2022-08-olympus/blob/main/src/policies/Heart.sol
File: policies/Operator.sol 51: event CushionFactorChanged(uint32 cushionFactor_); 52: event CushionParamsChanged(uint32 duration_, uint32 debtBuffer_, uint32 depositInterval_); 53: event ReserveFactorChanged(uint32 reserveFactor_); 54: event RegenParamsChanged(uint32 wait_, uint32 threshold_, uint32 observe_);
https://github.com/code-423n4/2022-08-olympus/blob/main/src/policies/Operator.sol
File: modules/INSTR.sol 11: event InstructionsStored(uint256 instructionsId);
https://github.com/code-423n4/2022-08-olympus/blob/main/src/modules/INSTR.sol
File: modules/PRICE.sol 26: event NewObservation(uint256 timestamp_, uint256 price_, uint256 movingAverage_); 27: event MovingAverageDurationChanged(uint48 movingAverageDuration_); 28: event ObservationFrequencyChanged(uint48 observationFrequency_);
https://github.com/code-423n4/2022-08-olympus/blob/main/src/modules/PRICE.sol
File: modules/RANGE.sol 20: event WallUp(bool high_, uint256 timestamp_, uint256 capacity_); 21: event WallDown(bool high_, uint256 timestamp_, uint256 capacity_); 22: event CushionUp(bool high_, uint256 timestamp_, uint256 capacity_); 23: event CushionDown(bool high_, uint256 timestamp_); 24: event PricesChanged(uint256 wallLowPrice_, uint256 cushionLowPrice_, uint256 cushionHighPrice_, uint256 wallHighPrice_); 30: event SpreadsChanged(uint256 cushionSpread_, uint256 wallSpread_); 31: event ThresholdFactorChanged(uint256 thresholdFactor_);
https://github.com/code-423n4/2022-08-olympus/blob/main/src/modules/RANGE.sol
constant
s should be defined rather than using magic numbersThere are 6 instances of this issue:
File: policies/BondCallback.sol 71: requests = new Permissions[](4);
https://github.com/code-423n4/2022-08-olympus/blob/main/src/policies/BondCallback.sol
File: policies/Operator.sol 111: if (configParams[4] > 10000 || configParams[4] < 100) revert Operator_InvalidParams(); 518: if (cushionFactor_ > 10000 || cushionFactor_ < 100) revert Operator_InvalidParams(); 550: if (reserveFactor_ > 10000 || reserveFactor_ < 100) revert Operator_InvalidParams();
https://github.com/code-423n4/2022-08-olympus/blob/main/src/policies/Operator.sol
File: modules/RANGE.sol 244: if (wallSpread_ > 10000 || wallSpread_ < 100 || cushionSpread_ > 10000 ||cushionSpread_ < 100 || cushionSpread_ > wallSpread_) revert RANGE_InvalidParams(); 264: if (thresholdFactor_ > 10000 || thresholdFactor_ < 100) revert RANGE_InvalidParams();
https://github.com/code-423n4/2022-08-olympus/blob/main/src/modules/RANGE.sol
There are 4 instances of this issue:
File: policies/TreasuryCustodian.sol 51: // TODO Currently allows anyone to revoke any approval EXCEPT activated policies. 52: // TODO must reorg policy storage to be able to check for deactivated policies. 56: // TODO Make sure `policy_` is an actual policy and not a random address.
https://github.com/code-423n4/2022-08-olympus/blob/main/src/policies/TreasuryCustodian.sol
File: policies/Operator.sol 657: /// TODO determine if this should use the last price from the MA or recalculate the current price, ideally last price is ok since it should have been just updated and should include check against secondary?
https://github.com/code-423n4/2022-08-olympus/blob/main/src/policies/Operator.sol
🌟 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
32.6351 DAI - $32.64
++i
/--i
costs less gas than i++
/i--
Saves 6 gas per instance/loop. There is inconsistency with the other contracts.
There are 7 instances of this issue:
File: utils/KernelUtils.sol 49: i++; 64: i++;
https://github.com/code-423n4/2022-08-olympus/blob/main/src/utils/KernelUtils.sol
File: policies/Operator.sol 488: decimals++; 670: _status.low.count++; 675: _status.low.count--; 686: _status.high.count++; 691: _status.low.count--;
https://github.com/code-423n4/2022-08-olympus/blob/main/src/policies/Operator.sol
constant
/non-immutable
variables to zero than to let the default of zero be appliedThere are 3 instances of this issue:
File: utils/KernelUtils.sol 43: for (uint256 i = 0; i < 5; ) { 58: for (uint256 i = 0; i < 32; ) {
https://github.com/code-423n4/2022-08-olympus/blob/main/src/utils/KernelUtils.sol
File: Kernel.sol 397: for (uint256 i = 0; i < reqLength; ) {
https://github.com/code-423n4/2022-08-olympus/blob/main/src/Kernel.sol
private
rather than public
for constants, saves gasIf needed, the values can be read from the verified contract source code, or if there are multiple values there can be a single getter function that returns a tuple of the values of all currently-public constants. Saves 3406-3606 gas in deployment gas due to the compiler not having to create non-payable getter functions for deployment calldata, not having to store the bytes of the value outside of where it's used, and not adding another entry to the method ID table
There are 1 instances of this issue:
File: modules/RANGE.sol 65: uint256 public constant FACTOR_SCALE = 1e4;
https://github.com/code-423n4/2022-08-olympus/blob/main/src/modules/RANGE.sol
calldata
instead of memory
for function parametersIf a reference type function parameter is read-only, it is cheaper in gas to use calldata instead of memory. Calldata is a non-modifiable, non-persistent area where function arguments are stored, and behaves mostly like memory. Try to use calldata as a data location because it will avoid copies and also makes sure that the data cannot be modified.
There are 3 instances of this issue:
File: policies/TreasuryCustodian.sol 53: function revokePolicyApprovals(address policy_, ERC20[] memory tokens_) external {
https://github.com/code-423n4/2022-08-olympus/blob/main/src/policies/TreasuryCustodian.sol
File: modules/RANGE.sol 79: ERC20[2] memory tokens_, 80: uint256[3] memory rangeParams_
https://github.com/code-423n4/2022-08-olympus/blob/main/src/modules/RANGE.sol
There are 6 instances of this issue:
File: modules/MINTR.sol 25: function VERSION() external pure override returns (uint8 major, uint8 minor) {
https://github.com/code-423n4/2022-08-olympus/blob/main/src/modules/MINTR.sol
File: modules/RANGE.sol 115: function VERSION() external pure override returns (uint8 major, uint8 minor) {
https://github.com/code-423n4/2022-08-olympus/blob/main/src/modules/RANGE.sol
File: modules/VOTES.sol 27: function VERSION() external pure override returns (uint8 major, uint8 minor) {
https://github.com/code-423n4/2022-08-olympus/blob/main/src/modules/VOTES.sol
File: modules/INSTR.sol 28: function VERSION() public pure override returns (uint8 major, uint8 minor) {
https://github.com/code-423n4/2022-08-olympus/blob/main/src/modules/INSTR.sol
File: modules/TRSRY.sol 51: function VERSION() external pure override returns (uint8 major, uint8 minor) {
https://github.com/code-423n4/2022-08-olympus/blob/main/src/modules/TRSRY.sol
File: policies/BondCallback.sol 173: function amountsForMarket(uint256 id_) external view override returns (uint256 in_, uint256 out_) {
https://github.com/code-423n4/2022-08-olympus/blob/main/src/policies/BondCallback.sol
public
functions not called by the contract should be declared external
insteadThere are 16 instances of this issue:
File: Kernel.sol 439: function grantRole(Role role_, address addr_) public onlyAdmin { 451: function revokeRole(Role role_, address addr_) public onlyAdmin {
https://github.com/code-423n4/2022-08-olympus/blob/main/src/Kernel.sol
File: modules/TRSRY.sol 75: function withdrawReserves(address to_, ERC20 token_, uint256 amount_) public {
https://github.com/code-423n4/2022-08-olympus/blob/main/src/modules/TRSRY.sol
File: modules/INSTR.sol 23: function KEYCODE() public pure override returns (Keycode) { 28: function VERSION() public pure override returns (uint8 major, uint8 minor) { 37: function getInstructions(uint256 instructionsId_) public view returns (Instruction[] memory) {
https://github.com/code-423n4/2022-08-olympus/blob/main/src/modules/INSTR.sol
File: modules/VOTES.sol 22: function KEYCODE() public pure override returns (Keycode) { 45: function transfer(address to_, uint256 amount_) public pure override returns (bool) { 51: function transferFrom(address from_, address to_, uint256 amount_) public override permissioned returns (bool) {
https://github.com/code-423n4/2022-08-olympus/blob/main/src/modules/VOTES.sol
File: modules/RANGE.sol 110: function KEYCODE() public pure override returns (Keycode) { 215: function updateMarket(bool high_, uint256 market_, uint256 marketCapacity_) public permissioned {
https://github.com/code-423n4/2022-08-olympus/blob/main/src/modules/RANGE.sol
File: modules/MINTR.sol 20: function KEYCODE() public pure override returns (Keycode) { 33: function mintOhm(address to_, uint256 amount_) public permissioned { 37: function burnOhm(address from_, uint256 amount_) public permissioned {
https://github.com/code-423n4/2022-08-olympus/blob/main/src/modules/MINTR.sol
File: policies/Governance.sol 145: function getMetadata(uint256 proposalId_) public view returns (ProposalMetadata memory) { 151: function getActiveProposal() public view returns (ActivatedProposal memory) {
https://github.com/code-423n4/2022-08-olympus/blob/main/src/policies/Governance.sol
<x> += <y>
costs more gas than <x> = <x> + <y>
for state variablesThere are 16 instances of this issue:
File: modules/VOTES.sol 56: balanceOf[from_] -= amount_; 58: balanceOf[to_] += amount_;
https://github.com/code-423n4/2022-08-olympus/blob/main/src/modules/VOTES.sol
File: policies/BondCallback.sol 143: _amountsPerMarket[id_][0] += inputAmount_; 144: _amountsPerMarket[id_][1] += outputAmount_;
https://github.com/code-423n4/2022-08-olympus/blob/main/src/policies/BondCallback.sol
File: modules/TRSRY.sol 96: reserveDebt[token_][msg.sender] += amount_; 97: totalDebt[token_] += amount_; 115: reserveDebt[token_][msg.sender] -= received; 116: totalDebt[token_] -= received; 132: else totalDebt[token_] -= oldDebt - amount_;
https://github.com/code-423n4/2022-08-olympus/blob/main/src/modules/TRSRY.sol
File: policies/Governance.sol 194: totalEndorsementsForProposal[proposalId_] -= previousEndorsement; 198: totalEndorsementsForProposal[proposalId_] += userVotes; 252: yesVotesForProposal[activeProposal.proposalId] += userVotes; 254: noVotesForProposal[activeProposal.proposalId] += userVotes;
https://github.com/code-423n4/2022-08-olympus/blob/main/src/policies/Governance.sol
File: modules/PRICE.sol 136: _movingAverage += (currentPrice - earliestPrice) / numObs; 138: _movingAverage -= (earliestPrice - currentPrice) / numObs; 222: total += startObservations_[i];
https://github.com/code-423n4/2022-08-olympus/blob/main/src/modules/PRICE.sol
payable
Marking a function as payable reduces gas cost since the compiler does not have to check whether a payment was provided or not. This change will save around 21 gas per function call.
There are 4 instances of this issue:
File: Kernel.sol 235: function executeAction(Actions action_, address target_) external onlyExecutor { 439: function grantRole(Role role_, address addr_) public onlyAdmin { 451: function revokeRole(Role role_, address addr_) public onlyAdmin {
https://github.com/code-423n4/2022-08-olympus/blob/main/src/Kernel.sol
File: policies/BondCallback.sol 190: function setOperator(Operator operator_) external onlyRole("callback_admin") {
https://github.com/code-423n4/2022-08-olympus/blob/main/src/policies/BondCallback.sol
x <= y
with x < y + 1
, and x >= y
with x > y - 1
In the EVM, there is no opcode for >= or <=. When using greater than or equal, two operations are performed: > and =. Using strict comparison operators hence saves gas
There are 5 instances of this issue:
File: Operator.sol 209: if (uint48(block.timestamp) >= RANGE.lastActive(true) + uint48(config_.regenWait) && _status.high.count >= config_.regenThreshold) { 215: if ( uint48(block.timestamp) >= RANGE.lastActive(false) + uint48(config_.regenWait) && _status.low.count >= config_.regenThreshold ) { _regenerate(false); } 486: while (price_ >= 10) { 667: if (currentPrice >= movingAverage) { 683: if (currentPrice <= movingAverage) {
https://github.com/code-423n4/2022-08-olympus/blob/main/src/policies/Operator.sol