Olympus DAO contest - Rolezn's results

Version 3 of Olympus protocol, a decentralized floating currency.

General Information

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

Olympus DAO

Findings Distribution

Researcher Performance

Rank: 59/147

Findings: 2

Award: $95.72

🌟 Selected for report: 0

🚀 Solo Findings: 0

(1) Init functions are susceptible to front-running

Severity: Low

Most contracts use an init pattern (instead of a constructor) to initialize contract parameters. Unless these are enforced to be atomic with contact deployment via deployment script or factory contracts, they are susceptible to front-running race conditions where an attacker/griefer can front-run (cannot access control because admin roles are not initialized) to initially with their own (malicious) parameters upon detecting (if an event is emitted) which the contract deployer has to redeploy wasting gas and risking other transactions from interacting with the attacker-initialized contract.

Many init functions do not have an explicit event emission which makes monitoring such scenarios harder. All of them have re-init checks; while many are explicit some (those in auction contracts) have implicit reinit checks in initAccessControls() which is better if converted to an explicit check in the main init function itself. (details credit to: code-423n4/2021-09-sushimiso-findings#64)

Proof Of Concept

function initialize(uint256[] memory startObservations_, uint48 lastObservationTime_)

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L205

function initialize() external onlyRole("operator_admin") {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L598

function initialize(uint256[] memory startObservations_, uint48 lastObservationTime_)

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/PriceConfig.sol#L45

Ensure atomic calls to init functions along with deployment via robust deployment scripts or factory contracts. Emit explicit events for initializations of contracts. Enfore prevention of re-initializations via explicit setting/checking of boolean initialized variables in the main init function instead of downstream function checks.

(2) Use _safeMint instead of _mint

Severity: Low

According to openzepplin's ERC721, the use of _mint is discouraged, use _safeMint whenever possible. https://docs.openzeppelin.com/contracts/3.x/api/token/erc721#ERC721-_mint-address-uint256-

Proof Of Concept

_mint(wallet_, amount_);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/VOTES.sol#L36

Use _safeMint whenever possible instead of _mint

(3) Missing Checks for Address(0x0)

Severity: Low

Proof Of Concept

function _issueReward(address to_) internal {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Heart.sol#L111

Consider adding zero-address checks in the mentioned codebase.

(4) Safeapprove() Is Deprecated

Severity: Low

Deprecated in favor of safeIncreaseAllowance() and safeDecreaseAllowance(). If only setting the initial allowance to the value that means infinite, safeIncreaseAllowance() can be used instead

Proof Of Concept

ohm.safeApprove(address(MINTR), type(uint256).max);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/BondCallback.sol#L57

ohm.safeApprove(address(MINTR), type(uint256).max);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L167

Consider using safeIncreaseAllowance() / safeDecreaseAllowance() instead.

(5) Use Safetransfer Instead Of Transfer

Severity: Low

It is good to add a require() statement that checks the return value of token transfers or to use something like OpenZeppelin’s safeTransfer/safeTransferFrom unless one is sure the given token reverts in case of a failure. Failure to do so will cause silent failures of transfers and affect token accounting in contract.

Reference: This similar medium-severity (https://consensys.net/diligence/audits/2021/01/fei-protocol/#unchecked-return-value-for-iweth-transfer-call) finding from Consensys Diligence Audit of Fei Protocol.

Proof Of Concept

VOTES.transferFrom(msg.sender, address(this), userVotes);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L259

VOTES.transferFrom(address(this), msg.sender, userVotes);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L312

Consider using safeTransfer/safeTransferFrom or require() consistently.

(6) Variable Names That Consist Of All Capital Letters Should Be Reserved For Const/immutable Variables

Severity: Non-Critical

If the variable needs to be different based on which class it comes from, a view/pure function should be used instead.

Proof Of Concept

Keycode TRSRY_KEYCODE = TRSRY.KEYCODE();

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/BondCallback.sol#L68

Keycode TRSRY_KEYCODE = TRSRY.KEYCODE();

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/TreasuryCustodian.sol#L35

(7) Constants Should Be Defined Rather Than Using Magic Numbers

Severity: Non-Critical

Proof Of Concept

wallSpread_ > 10000 ||

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L245

if (thresholdFactor_ > 10000 || thresholdFactor_ < 100) revert RANGE_InvalidParams();

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L264

(totalEndorsementsForProposal[proposalId_] * 100) <

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L217

while (price_ >= 10) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L486

if (cushionFactor_ > 10000 || cushionFactor_ < 100) revert Operator_InvalidParams();

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L518

if (duration_ > uint256(7 days) || duration_ < uint256(1 days))

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L533

if (reserveFactor_ > 10000 || reserveFactor_ < 100) revert Operator_InvalidParams();

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L550

if (wait_ < 1 hours || threshold_ > observe_ || observe_ == 0)

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L565

(8) Event Is Missing Indexed Fields

Severity: Non-Critical

Each event should use three indexed fields if there are three or more fields. In addition, each event should have at least one indexed fields to allow easier filtering of logs.

Proof Of Concept

event PermissionsUpdated( Keycode indexed keycode_, Policy indexed policy_, bytes4 funcSelector_, bool granted_ );

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L203

event NewObservation(uint256 timestamp_, uint256 price_, uint256 movingAverage_);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L26

event WallUp(bool high_, uint256 timestamp_, uint256 capacity_);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L20

event WallDown(bool high_, uint256 timestamp_, uint256 capacity_);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L21

event CushionUp(bool high_, uint256 timestamp_, uint256 capacity_);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L22

event CushionDown(bool high_, uint256 timestamp_);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L23

event PricesChanged( uint256 wallLowPrice_, uint256 cushionLowPrice_, uint256 cushionHighPrice_, uint256 wallHighPrice_ );

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L24

event SpreadsChanged(uint256 cushionSpread_, uint256 wallSpread_);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L30

event ApprovedForWithdrawal(address indexed policy_, ERC20 indexed token_, uint256 amount_);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/TRSRY.sol#L20

event DebtIncurred(ERC20 indexed token_, address indexed policy_, uint256 amount_);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/TRSRY.sol#L27

event DebtRepaid(ERC20 indexed token_, address indexed policy_, uint256 amount_);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/TRSRY.sol#L28

event DebtSet(ERC20 indexed token_, address indexed policy_, uint256 amount_);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/TRSRY.sol#L29

event ProposalEndorsed(uint256 proposalId, address voter, uint256 amount);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L87

event ProposalActivated(uint256 proposalId, uint256 timestamp);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L88

event WalletVoted(uint256 proposalId, address voter, bool for_, uint256 userVotes);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L89

event RewardIssued(address to_, uint256 rewardAmount_);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Heart.sol#L29

event RewardUpdated(ERC20 token_, uint256 rewardAmount_);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Heart.sol#L30

event Swap( ERC20 indexed tokenIn_, ERC20 indexed tokenOut_, uint256 amountIn_, uint256 amountOut_ );

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L45

event CushionParamsChanged(uint32 duration_, uint32 debtBuffer_, uint32 depositInterval_);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L52

event RegenParamsChanged(uint32 wait_, uint32 threshold_, uint32 observe_);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L54

(9) Missing event for critical parameter change

Severity: Non-Critical

When changing state variables events are not emitted. Emitting events allows monitoring activities with off-chain monitoring tools.

Proof Of Concept

function changeKernel(

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L76

function setActiveStatus(

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L126

function setOperator(

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/BondCallback.sol#L190

function setSpreads(

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L498

function setThresholdFactor(

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L510

function setBondContracts(

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L586

function changeMovingAverageDuration(

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/PriceConfig.sol#L58

function changeObservationFrequency(

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/PriceConfig.sol#L69

(10) Implementation contract may not be initialized

OpenZeppelin recommends that the initializer modifier be applied to constructors. Per OZs Post implementation contract should be initialized to avoid potential griefs or exploits. https://forum.openzeppelin.com/t/uupsupgradeable-vulnerability-post-mortem/15680/5

Severity: Non-Critical

Proof Of Concept

contract Kernel

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L149

contract OlympusInstructions is Module

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/INSTR.sol#L10

contract OlympusMinter is Module

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/MINTR.sol#L8

contract OlympusPrice is Module

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L22

contract OlympusRange is Module

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L16

contract OlympusTreasury is Module, ReentrancyGuard

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/TRSRY.sol#L17

contract OlympusVotes is Module, ERC20

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/VOTES.sol#L11

contract BondCallback is Policy, ReentrancyGuard, IBondCallback

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/BondCallback.sol#L17

contract OlympusGovernance is Policy

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L51

contract OlympusHeart is IHeart, Policy, ReentrancyGuard

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Heart.sol#L21

contract Operator is IOperator, Policy, ReentrancyGuard

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L30

contract OlympusPriceConfig is Policy

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/PriceConfig.sol#L7

contract TreasuryCustodian is Policy

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/TreasuryCustodian.sol#L15

contract VoterRegistration is Policy

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/VoterRegistration.sol#L9

(11) Use a more recent version of Solidity

Severity: Non-Critical

Use a solidity version of at least 0.8.4 to get bytes.concat() instead of abi.encodePacked(<bytes>,<bytes>) Use a solidity version of at least 0.8.12 to get string.concat() instead of abi.encodePacked(<str>,<str>) Use a solidity version of at least 0.8.13 to get the ability to use using for with a list of free functions

Proof Of Concept

Found old version 0.8.0 of Solidity

https://github.com/code-423n4/2022-08-olympus/tree/main/src/interfaces/IBondCallback.sol#L2

Found old version 0.8.0 of Solidity

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/interfaces/IHeart.sol#L2

Found old version 0.8.0 of Solidity

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/interfaces/IOperator.sol#L2

Found old version 0.8.0 of Solidity

https://github.com/code-423n4/2022-08-olympus/tree/main/src/test/lib/bonds/interfaces/IBondCallback.sol#L2

Consider updating to a more recent solidity version.

(12) Public Functions Not Called By The Contract Should Be Declared External Instead

Severity: Non-Critical

Contracts are allowed to override their parents’ functions and change the visibility from external to public.

Proof Of Concept

function grantRole(

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L439

function revokeRole(

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L451

function mintOhm(

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/MINTR.sol#L33

function burnOhm(

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/MINTR.sol#L37

function updateMarket(

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L215

function withdrawReserves(

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/TRSRY.sol#L75

function transferFrom(

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/VOTES.sol#L51

(13) Large multiples of ten should use scientific notation

Severity: Non-Critical

Use (e.g. 1e6) rather than decimal literals (e.g. 100000), for better code readability.

Proof Of Concept

wallSpread_ > 10000 ||

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L245

cushionSpread_ > 10000 ||

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L247

if (thresholdFactor_ > 10000 || thresholdFactor_ < 100) revert RANGE_InvalidParams();

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L264

wallSpread_ > 10000 ||

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L245

cushionSpread_ > 10000 ||

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L247

if (thresholdFactor_ > 10000 || thresholdFactor_ < 100) revert RANGE_InvalidParams();

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L264

wallSpread_ > 10000 ||

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L245

cushionSpread_ > 10000 ||

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L247

if (thresholdFactor_ > 10000 || thresholdFactor_ < 100) revert RANGE_InvalidParams();

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L264

if (VOTES.balanceOf(msg.sender) * 10000 < VOTES.totalSupply() * SUBMISSION_REQUIREMENT)

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L164

if (configParams[4] > 10000 || configParams[4] < 100) revert Operator_InvalidParams();

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L111

if (cushionFactor_ > 10000 || cushionFactor_ < 100) revert Operator_InvalidParams();

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L518

if (reserveFactor_ > 10000 || reserveFactor_ < 100) revert Operator_InvalidParams();

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L550

if (configParams[4] > 10000 || configParams[4] < 100) revert Operator_InvalidParams();

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L111

if (cushionFactor_ > 10000 || cushionFactor_ < 100) revert Operator_InvalidParams();

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L518

if (reserveFactor_ > 10000 || reserveFactor_ < 100) revert Operator_InvalidParams();

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L550

if (configParams[4] > 10000 || configParams[4] < 100) revert Operator_InvalidParams();

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L111

if (cushionFactor_ > 10000 || cushionFactor_ < 100) revert Operator_InvalidParams();

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L518

if (reserveFactor_ > 10000 || reserveFactor_ < 100) revert Operator_InvalidParams();

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L550

(14) Use of Block.Timestamp

Severity: Non-Critical

Block timestamps have historically been used for a variety of applications, such as entropy for random numbers (see the Entropy Illusion for further details), locking funds for periods of time, and various state-changing conditional statements that are time-dependent. Miners have the ability to adjust timestamps slightly, which can prove to be dangerous if block timestamps are used incorrectly in smart contracts.

Proof Of Concept

lastObservationTime = uint48(block.timestamp);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L143

if (updatedAt < block.timestamp - 3 * uint256(observationFrequency))

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L165

if (updatedAt < block.timestamp - uint256(observationFrequency))

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L171

if (startObservations_.length != numObs || lastObservationTime_ > uint48(block.timestamp))

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L215

lastActive: uint48(block.timestamp),

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L85

_range.high.lastActive = uint48(block.timestamp);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L136

_range.low.lastActive = uint48(block.timestamp);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L148

getProposalMetadata[proposalId] = ProposalMetadata( title_, msg.sender, block.timestamp, proposalURI_ );

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L168-L173

if (block.timestamp > proposal.submissionTimestamp + ACTIVATION_DEADLINE) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L212

if (block.timestamp < activeProposal.activationTimestamp + GRACE_PERIOD) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L227

activeProposal = ActivatedProposal(proposalId_, block.timestamp);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L231

if (block.timestamp < activeProposal.activationTimestamp + EXECUTION_TIMELOCK) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L272

lastBeat = block.timestamp;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Heart.sol#L63

if (block.timestamp < lastBeat + frequency()) revert Heart_OutOfCycle();

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Heart.sol#L94

lastBeat = block.timestamp - frequency();

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Heart.sol#L131

lastRegen: uint48(block.timestamp),

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L128

uint48(block.timestamp) >= RANGE.lastActive(true) + uint48(config_.regenWait) &&

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L210

uint48(block.timestamp) >= RANGE.lastActive(false) + uint48(config_.regenWait) &&

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L216

conclusion: uint48(block.timestamp + config_.cushionDuration),

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L404

_status.high.lastRegen = uint48(block.timestamp);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L708

_status.low.lastRegen = uint48(block.timestamp);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L720

Block timestamps should not be used for entropy or generating random numbers—i.e., they should not be the deciding factor (either directly or through some derivation) for winning a game or changing an important state.

Time-sensitive logic is sometimes required; e.g., for unlocking contracts (time-locking), completing an ICO after a few weeks, or enforcing expiry dates. It is sometimes recommended to use block.number and an average block time to estimate times; with a 10 second block time, 1 week equates to approximately, 60480 blocks. Thus, specifying a block number at which to change a contract state can be more secure, as miners are unable to easily manipulate the block number.

(1) <Array>.length Should Not Be Looked Up In Every Loop Of A For-loop

Severity: Gas Optimizations

The overheads outlined below are PER LOOP, excluding the first loop

storage arrays incur a Gwarmaccess (100 gas) memory arrays use MLOAD (3 gas) calldata arrays use CALLDATALOAD (3 gas)

Caching the length changes each of these to a DUP<N> (3 gas), and gets rid of the extra DUP<N> needed to store the stack offset

Proof Of Concept

for (uint256 step; step < instructions.length; ) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L278

(2) Using Calldata Instead Of Memory For Read-only Arguments In External Functions Saves Gas

Severity: Gas Optimizations

When a function with a memory array is called externally, the abi.decode() step has to use a for-loop to copy each index of the calldata to the memory index. Each iteration of this for-loop costs at least 60 gas (i.e. 60 * <mem_array>.length). Using calldata directly, obliviates the need for such a loop in the contract code and runtime execution. Structs have the same overhead as an array of length one

Proof Of Concept

function configureDependencies() external virtual returns (Keycode[] memory dependencies) {}

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L139

function requestPermissions() external view virtual returns (Permissions[] memory requests) {}

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L143

function _setPolicyPermissions( Policy policy_, Permissions[] memory requests_, bool grant_ ) internal {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L391

function getInstructions(uint256 instructionsId_) public view returns (Instruction[] memory) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/INSTR.sol#L37

function initialize(uint256[] memory startObservations_, uint48 lastObservationTime_)

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L205

function configureDependencies() external override returns (Keycode[] memory dependencies) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/BondCallback.sol#L48

function requestPermissions() external view override onlyKernel returns (Permissions[] memory requests) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/BondCallback.sol#L61

function batchToTreasury(ERC20[] memory tokens_) external onlyRole("callback_admin") {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/BondCallback.sol#L152

function configureDependencies() external override returns (Keycode[] memory dependencies) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L61

function requestPermissions() external view override onlyKernel returns (Permissions[] memory requests) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L70

function configureDependencies() external override returns (Keycode[] memory dependencies) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Heart.sol#L69

function requestPermissions() external view override returns (Permissions[] memory permissions) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Heart.sol#L77

function configureDependencies() external override returns (Keycode[] memory dependencies) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L154

function requestPermissions() external view override returns (Permissions[] memory requests) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L171

function configureDependencies() external override returns (Keycode[] memory dependencies) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/PriceConfig.sol#L18

function requestPermissions() external view override returns (Permissions[] memory permissions) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/PriceConfig.sol#L25

function initialize(uint256[] memory startObservations_, uint48 lastObservationTime_)

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/PriceConfig.sol#L45

function configureDependencies() external override returns (Keycode[] memory dependencies) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/TreasuryCustodian.sol#L27

function requestPermissions() external view override returns (Permissions[] memory requests) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/TreasuryCustodian.sol#L34

function revokePolicyApprovals(address policy_, ERC20[] memory tokens_) external {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/TreasuryCustodian.sol#L53

function configureDependencies() external override returns (Keycode[] memory dependencies) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/VoterRegistration.sol#L19

function requestPermissions() external view override returns (Permissions[] memory permissions) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/VoterRegistration.sol#L27

(3) Empty Blocks Should Be Removed Or Emit Something

Severity: Gas Optimizations

The code should be refactored such that they no longer exist, or the block should do something useful, such as emitting an event or reverting. If the contract is meant to be extended, the contract should be abstract and the function signatures be added without any default implementation. If the block is an empty if-statement block to avoid doing subsequent checks in the else-if/else conditions, the else-if/else conditions should be nested under the negation of the if-statement, because they involve different classes of checks, which may lead to the introduction of errors when the code is later modified (if(x){}else if(y){...}else{...} => if(!x){if(y){...}else{...}})

Proof Of Concept

constructor(Kernel kernel_) KernelAdapter(kernel_) {}

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L85

function KEYCODE() public pure virtual returns (Keycode) {}

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L95

function VERSION() external pure virtual returns (uint8 major, uint8 minor) {}

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L100

function INIT() external virtual onlyKernel {}

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L105

function configureDependencies() external virtual returns (Keycode[] memory dependencies) {}

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L139

function requestPermissions() external view virtual returns (Permissions[] memory requests) {}

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L143

(4) It Costs More Gas To Initialize Variables To Zero Than To Let The Default Of Zero Be Applied

Severity: Gas Optimizations

Proof Of Concept

for (uint256 i = 0; i < reqLength; ) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L397

(5) Multiple Address Mappings Can Be Combined Into A Single Mapping Of An Address To A Struct, Where Appropriate

Severity: Gas Optimizations

Saves a storage slot for the mapping. Depending on the circumstances and sizes of types, can avoid a Gsset (20000 gas) per mapping combined. Reads and subsequent writes can also be cheaper when a function requires both values and they both fit in the same storage slot.

Proof Of Concept

mapping(address => mapping(ERC20 => uint256)) public withdrawApproval; mapping(address => uint256)) public reserveDebt;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/TRSRY.sol#L33

mapping(address => uint256)) public userEndorsementsForProposal; mapping(address => uint256)) public userVotesForProposal; mapping(address => bool)) public tokenClaimsForProposal;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L102

(6) Multiplication/division By Two Should Use Bit Shifting

Severity: Gas Optimizations

<x> * 2 is equivalent to <x> << 1 and <x> / 2 is the same as <x> >> 1. The MUL and DIV opcodes cost 5 gas, whereas SHL and SHR only cost 3 gas

Proof Of Concept

int8 scaleAdjustment = int8(ohmDecimals) - int8(reserveDecimals) + (priceDecimals / 2);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L372

uint256 invCushionPrice = 10**(oracleDecimals * 2) / range.cushion.low.price;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L419

uint256 invWallPrice = 10**(oracleDecimals * 2) / range.wall.low.price;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L420

int8 scaleAdjustment = int8(reserveDecimals) - int8(ohmDecimals) + (priceDecimals / 2);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L427

) * (FACTOR_SCALE + RANGE.spread(true) * 2)) /

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L786

(7) Not Using The Named Return Variables When A Function Returns, Wastes Deployment Gas

Severity: Gas Optimizations

Proof Of Concept

function amountsForMarket(uint256 id_) external view override returns (uint256 in_, uint256 out_) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/BondCallback.sol#L173

(8) <x> += <y> Costs More Gas Than <x> = <x> + <y> For State Variables

Severity: Gas Optimizations

Proof Of Concept

_movingAverage += (currentPrice - earliestPrice) / numObs;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L136

_movingAverage -= (earliestPrice - currentPrice) / numObs;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L138

total += startObservations_[i];

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L222

reserveDebt[token_][msg.sender] += amount_;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/TRSRY.sol#L96

totalDebt[token_] += amount_;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/TRSRY.sol#L97

reserveDebt[token_][msg.sender] -= received;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/TRSRY.sol#L115

totalDebt[token_] -= received;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/TRSRY.sol#L116

if (oldDebt < amount_) totalDebt[token_] += amount_ - oldDebt;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/TRSRY.sol#L131

else totalDebt[token_] -= oldDebt - amount_;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/TRSRY.sol#L132

balanceOf[from_] -= amount_;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/VOTES.sol#L56

balanceOf[to_] += amount_;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/VOTES.sol#L58

_amountsPerMarket[id_][0] += inputAmount_;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/BondCallback.sol#L143

_amountsPerMarket[id_][1] += outputAmount_;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/BondCallback.sol#L144

totalEndorsementsForProposal[proposalId_] -= previousEndorsement;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L194

totalEndorsementsForProposal[proposalId_] += userVotes;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L198

yesVotesForProposal[activeProposal.proposalId] += userVotes;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L252

noVotesForProposal[activeProposal.proposalId] += userVotes;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L254

lastBeat += frequency();

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Heart.sol#L103

(9) Using Private Rather Than Public For Constants, Saves Gas

Severity: Gas Optimizations

If needed, the value can be read from the verified contract source code. Savings are due to the compiler not having to create non-payable getter functions for deployment calldata, and not adding another entry to the method ID table

Proof Of Concept

uint8 public constant decimals = 18;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L59

uint256 public constant FACTOR_SCALE = 1e4;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L65

uint256 public constant SUBMISSION_REQUIREMENT = 100; uint256 public constant ACTIVATION_DEADLINE = 2 weeks; uint256 public constant GRACE_PERIOD = 1 weeks; uint256 public constant ENDORSEMENT_THRESHOLD = 20; uint256 public constant EXECUTION_THRESHOLD = 33; uint256 public constant EXECUTION_TIMELOCK = 3 days;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L121-L137

uint32 public constant FACTOR_SCALE = 1e4;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L89

Set variable to private.

(10) Public Functions To External

Severity: Gas Optimizations

The following functions could be set external to save gas and improve code quality. External call cost is less expensive than of public functions.

Proof Of Concept

function KEYCODE() public pure virtual returns (Keycode) {}

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L95

function grantRole(Role role_, address addr_) public onlyAdmin {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L439

function revokeRole(Role role_, address addr_) public onlyAdmin {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L451

function KEYCODE() public pure override returns (Keycode) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/INSTR.sol#L23

function VERSION() public pure override returns (uint8 major, uint8 minor) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/INSTR.sol#L28

function getInstructions(uint256 instructionsId_) public view returns (Instruction[] memory) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/INSTR.sol#L37

function KEYCODE() public pure override returns (Keycode) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/MINTR.sol#L20

function mintOhm(address to_, uint256 amount_) public permissioned {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/MINTR.sol#L33

function burnOhm(address from_, uint256 amount_) public permissioned {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/MINTR.sol#L37

function KEYCODE() public pure override returns (Keycode) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L108

function getCurrentPrice() public view returns (uint256) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L154

function KEYCODE() public pure override returns (Keycode) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L110

function updateMarket(

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L215

function KEYCODE() public pure override returns (Keycode) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/TRSRY.sol#L47

function withdrawReserves(

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/TRSRY.sol#L75

function KEYCODE() public pure override returns (Keycode) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/VOTES.sol#L22

function transfer(address to_, uint256 amount_) public pure override returns (bool) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/VOTES.sol#L45

function transferFrom(

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/VOTES.sol#L51

function getMetadata(uint256 proposalId_) public view returns (ProposalMetadata memory) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L145

function getActiveProposal() public view returns (ActivatedProposal memory) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L151

function frequency() public view returns (uint256) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Heart.sol#L121

function getAmountOut(ERC20 tokenIn_, uint256 amountIn_) public view returns (uint256) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L749

function fullCapacity(bool high_) public view override returns (uint256) {

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L778

(11) Help The Optimizer By Saving A Storage Variable’s Reference Instead Of Repeatedly Fetching It

Severity: Gas Optimizations

To help the optimizer, declare a storage type variable and use it instead of repeatedly fetching the reference in a map or an array. The effect can be quite significant. As an example, instead of repeatedly calling someMap[someIndex], save its reference like this: SomeStruct storage someStruct = someMap[someIndex] and use it.

Proof Of Concept

if (address(getModuleForKeycode[keycode]) != address(0))

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L269

Module oldModule = getModuleForKeycode[keycode];

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L281

moduleDependents[keycode].push(policy_);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L309

getDependentIndex[keycode][policy_] = moduleDependents[keycode].length - 1;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L310

Policy[] storage dependents = moduleDependents[keycode];

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L415

uint256 origIndex = getDependentIndex[keycode][policy_];

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L417

delete getDependentIndex[keycode][policy_];

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L426

Instruction[] storage instructions = storedInstructions[instructionsId];

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/INSTR.sol#L46

uint256 earliestPrice = observations[nextObsIndex];

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L130

return observations[lastIndex];

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L186

kernel.executeAction(instructions[step].action, instructions[step].target);

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L279

(12) Use of non-uint64 state variable is less efficient than uint256

Severity: Gas Optimizations

Lower than uint256 size storage variables are less gas efficient. Using uint64 does not give any efficiency, actually, it is the opposite as EVM operates on default of 256-bit values so uint64 is more expensive in this case as it needs a conversion. It only gives improvements in cases where you can pack variables together, e.g. structs.

Proof Of Concept

uint32 public nextObsIndex;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L44

uint32 public numObservations;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L47

uint48 public observationFrequency;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L50

uint48 public movingAverageDuration;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L53

uint48 public lastObservationTime;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L56

uint8 public constant decimals = 18;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L59

uint8 ohmEthDecimals = _ohmEthPriceFeed.decimals();

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L84

uint8 reserveEthDecimals = _reserveEthPriceFeed.decimals();

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L87

uint32 numObs = numObservations;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L127

uint32 lastIndex = nextObsIndex == 0 ? numObservations - 1 : nextObsIndex - 1;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L185

uint48 lastActive;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/RANGE.sol#L45

uint8 public immutable ohmDecimals;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L83

uint8 public immutable reserveDecimals;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L86

uint32 public constant FACTOR_SCALE = 1e4;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L89

uint8 oracleDecimals = PRICE.decimals();

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L418

uint32 observe = _config.regenObserve;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L665

uint32 cushionFactor;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/interfaces/IOperator.sol#L13

uint32 cushionDuration;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/interfaces/IOperator.sol#L14

uint32 cushionDebtBuffer;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/interfaces/IOperator.sol#L15

uint32 cushionDepositInterval;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/interfaces/IOperator.sol#L16

uint32 reserveFactor;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/interfaces/IOperator.sol#L17

uint32 regenWait;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/interfaces/IOperator.sol#L18

uint32 regenThreshold;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/interfaces/IOperator.sol#L19

uint32 regenObserve;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/interfaces/IOperator.sol#L20

uint32 count;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/interfaces/IOperator.sol#L31

uint48 lastRegen;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/interfaces/IOperator.sol#L32

uint32 nextObservation;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/interfaces/IOperator.sol#L33

(13) Using Bools For Storage Incurs Overhead

Severity: Gas Optimizations

Booleans are more expensive than uint256 or any type that takes up a full word because each write operation emits an extra SLOAD to first read the slot's contents, replace the bits taken up by the boolean, and then write back. This is the compiler's defense against contract upgrades and pointer aliasing, and it cannot be disabled.

Proof Of Concept

bool public isActive;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L113

mapping(Keycode => mapping(Policy => mapping(bytes4 => bool))) public modulePermissions;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L181

mapping(address => mapping(Role => bool)) public hasRole;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L194

mapping(Role => bool) public isRole;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/Kernel.sol#L197

bool public initialized;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/modules/PRICE.sol#L62

mapping(address => mapping(uint256 => bool)) public approvedMarkets;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/BondCallback.sol#L24

mapping(uint256 => bool) public proposalHasBeenActivated;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L105

mapping(uint256 => mapping(address => bool)) public tokenClaimsForProposal;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Governance.sol#L117

bool public active;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Heart.sol#L33

bool public initialized;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L63

bool public active;

https://github.com/code-423n4/2022-08-olympus/tree/main/src/policies/Operator.sol#L66

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter