Issue | Instances | |
---|---|---|
GAS-1 | Use assembly to check for address(0) |
8 |
GAS-2 | Using bools for storage incurs overhead | 9 |
GAS-3 | Cache array length outside of loop | 8 |
GAS-4 | State variables should be cached in stack variables rather than re-reading them from storage | 10 |
GAS-5 | Use calldata instead of memory for function arguments that do not get mutated | 1 |
GAS-6 | Use Custom Errors | 73 |
GAS-7 | Don't initialize variables with default value | 23 |
GAS-8 | Long revert strings | 35 |
GAS-9 | Functions guaranteed to revert when called by normal users can be marked payable |
7 |
GAS-10 | ++i costs less gas than i++ , especially when it's used in for -loops (--i /i-- too) |
17 |
GAS-11 | Using private rather than public for constants, saves gas |
30 |
GAS-12 | Use != 0 instead of > 0 for unsigned integer comparison | 27 |
GAS-13 | internal functions not called by the contract should be removed |
1 |
Saves 6 gas per instance
Instances (8):
File: Ethos-Core/contracts/ActivePool.sol
93: require(_treasuryAddress != address(0), "Treasury cannot be 0 address");
File: Ethos-Core/contracts/LUSDToken.sol
312: assert(sender != address(0));
313: assert(recipient != address(0));
321: assert(account != address(0));
329: assert(account != address(0));
337: assert(owner != address(0));
338: assert(spender != address(0));
348: _recipient != address(0) &&
Use uint256(1) and uint256(2) for true/false to avoid a Gwarmaccess (100 gas), and to avoid Gsset (20000 gas) when changing from ‘false’ to ‘true’, after having been ‘true’ in the past. See source.
Instances (9):
File: Ethos-Core/contracts/ActivePool.sol
32: bool public addressesSet = false;
File: Ethos-Core/contracts/CollateralConfig.sol
18: bool public initialized = false;
File: Ethos-Core/contracts/LQTY/CommunityIssuance.sol
21: bool public initialized = false;
File: Ethos-Core/contracts/LUSDToken.sol
37: bool public mintingPaused = false;
62: mapping (address => bool) public troveManagers;
63: mapping (address => bool) public stabilityPools;
64: mapping (address => bool) public borrowerOperations;
File: Ethos-Vault/contracts/ReaperVaultV2.sol
49: bool public emergencyShutdown;
File: Ethos-Vault/contracts/abstract/ReaperBaseStrategyV4.sol
30: bool public emergencyExit;
If not cached, the solidity compiler will always read the length of the array during each iteration. That is, if it is a storage array, this is an extra sload operation (100 additional extra gas for each iteration except for the first) and if it is a memory array, this is an extra mload operation (3 additional gas for each iteration except for the first).
Instances (8):
File: Ethos-Core/contracts/CollateralConfig.sol
56: for(uint256 i = 0; i < _collaterals.length; i++) {
File: Ethos-Core/contracts/LQTY/LQTYStaking.sol
206: for (uint i = 0; i < assets.length; i++) {
228: for (uint i = 0; i < collaterals.length; i++) {
File: Ethos-Core/contracts/StabilityPool.sol
640: for (uint i = 0; i < assets.length; i++) {
810: for (uint i = 0; i < collaterals.length; i++) {
831: for (uint i = 0; i < collaterals.length; i++) {
File: Ethos-Core/contracts/TroveManager.sol
808: for (vars.i = 0; vars.i < _troveArray.length; vars.i++) {
882: for (vars.i = 0; vars.i < _troveArray.length; vars.i++) {
[GAS-4] State variables should be cached in stack variables rather than re-reading them from storage
The instances below point to the second+ access of a state variable within a function. Caching of a state variable replaces each Gwarmaccess (100 gas) with a much cheaper stack read. Other less obvious fixes/optimizations include having local memory caches of state variable structs, or having local caches of state variable contracts/addresses.
Saves 100 gas per instance
Instances (10):
File: Ethos-Core/contracts/ActivePool.sol
181: IDefaultPool(defaultPoolAddress).pullCollateralFromActivePool(_collateral, _amount);
184: ICollSurplusPool(collSurplusPoolAddress).pullCollateralFromActivePool(_collateral, _amount);
299: ILQTYStaking(lqtyStakingAddress).increaseF_Collateral(_collateral, vars.stakingSplit);
305: IStabilityPool(stabilityPoolAddress).updateRewardSum(_collateral, vars.stabilityPoolSplit);
File: Ethos-Core/contracts/LQTY/CommunityIssuance.sol
113: lastDistributionTime = block.timestamp.add(distributionPeriod);
116: emit LogRewardPerSecond(rewardPerSecond);
File: Ethos-Core/contracts/StabilityPool.sol
577: emit EpochUpdated(currentEpoch);
579: emit ScaleUpdated(currentScale);
754: compoundedDeposit = initialDeposit.mul(P).div(snapshot_P).div(SCALE_FACTOR);
754: compoundedDeposit = initialDeposit.mul(P).div(snapshot_P).div(SCALE_FACTOR);
Mark data types as calldata
instead of memory
where possible. This makes it so that the data is not automatically loaded into memory. If the data passed into the function does not need to be changed (like updating values in an array), it can be passed in as calldata
. The one exception to this is if the argument must later be passed into another function that takes an argument that specifies memory
storage.
Instances (1):
File: Ethos-Core/contracts/TroveManager.sol
715: function batchLiquidateTroves(address _collateral, address[] memory _troveArray) public override {
Source Instead of using error strings, to reduce deployment and runtime cost, you should use Custom Errors. This would save both deployment and runtime cost.
Instances (73):
File: Ethos-Core/contracts/ActivePool.sol
85: require(!addressesSet, "Can call setAddresses only once");
93: require(_treasuryAddress != address(0), "Treasury cannot be 0 address");
107: require(numCollaterals == _erc4626vaults.length, "Vaults array length must match number of collaterals");
111: require(IERC4626(vault).asset() == collateral, "Vault asset must be collateral");
127: require(_bps <= 10_000, "Invalid BPS value");
133: require(_driftBps <= 500, "Exceeds max allowed value of 500 BPS");
145: require(_treasurySplit + _SPSplit + _stakingSplit == 10_000, "Splits must add up to 10000 BPS");
File: Ethos-Core/contracts/BorrowerOperations.sol
525: require(collateralConfig.isCollateralAllowed(_collateral), "BorrowerOps: Invalid collateral address");
529: require(IERC20(_collateral).balanceOf(_user) >= _collAmount, "BorrowerOperations: Insufficient user collateral balance");
530: require(IERC20(_collateral).allowance(_user, address(this)) >= _collAmount, "BorrowerOperations: Insufficient collateral allowance");
534: require(_collTopUp == 0 || _collWithdrawal == 0, "BorrowerOperations: Cannot withdraw and add coll");
538: require(_collTopUp != 0 || _collWithdrawal != 0 || _LUSDChange != 0, "BorrowerOps: There must be either a collateral change or a debt change");
543: require(status == 1, "BorrowerOps: Trove does not exist or is closed");
548: require(status != 1, "BorrowerOps: Trove is active");
552: require(_LUSDChange > 0, "BorrowerOps: Debt increase requires non-zero debtChange");
568: require(_collWithdrawal == 0, "BorrowerOps: Collateral withdrawal not permitted Recovery Mode");
617: require(_newICR >= _MCR, "BorrowerOps: An operation that would result in ICR < MCR is not permitted");
621: require(_newICR >= _CCR, "BorrowerOps: Operation must leave trove with ICR >= CCR");
625: require(_newICR >= _oldICR, "BorrowerOps: Cannot decrease your Trove's ICR in Recovery Mode");
629: require(_newTCR >= _CCR, "BorrowerOps: An operation that would result in TCR < CCR is not permitted");
637: require(_debtRepayment <= _currentDebt.sub(LUSD_GAS_COMPENSATION), "BorrowerOps: Amount repaid must not be larger than the Trove's debt");
641: require(msg.sender == stabilityPoolAddress, "BorrowerOps: Caller is not Stability Pool");
645: require(_lusdToken.balanceOf(_borrower) >= _debtRepayment, "BorrowerOps: Caller doesnt have enough LUSD to make repayment");
File: Ethos-Core/contracts/CollateralConfig.sol
51: require(!initialized, "Can only initialize once");
52: require(_collaterals.length != 0, "At least one collateral required");
53: require(_MCRs.length == _collaterals.length, "Array lengths must match");
54: require(_CCRs.length == _collaterals.length, "Array lenghts must match");
66: require(_MCRs[i] >= MIN_ALLOWED_MCR, "MCR below allowed minimum");
69: require(_CCRs[i] >= MIN_ALLOWED_CCR, "CCR below allowed minimum");
91: require(_MCR <= config.MCR, "Can only walk down the MCR");
92: require(_CCR <= config.CCR, "Can only walk down the CCR");
94: require(_MCR >= MIN_ALLOWED_MCR, "MCR below allowed minimum");
97: require(_CCR >= MIN_ALLOWED_CCR, "CCR below allowed minimum");
129: require(collateralConfig[_collateral].allowed, "Invalid collateral address");
File: Ethos-Core/contracts/LQTY/CommunityIssuance.sol
70: require(!initialized, "issuance has been initialized");
102: require(amount != 0, "cannot fund 0");
133: require(msg.sender == stabilityPoolAddress, "CommunityIssuance: caller is not SP");
File: Ethos-Core/contracts/LQTY/LQTYStaking.sol
262: require(msg.sender == borrowerOperationsAddress, "LQTYStaking: caller is not BorrowerOps");
File: Ethos-Core/contracts/LUSDToken.sol
362: require(msg.sender == borrowerOperationsAddress, "LUSDToken: Caller is not BorrowerOperations");
377: require(msg.sender == stabilityPoolAddress, "LUSD: Caller is not the StabilityPool");
390: require(msg.sender == governanceAddress, "LUSDToken: Caller is not Governance");
394: require(!mintingPaused, "LUSDToken: Minting is currently paused");
File: Ethos-Core/contracts/StabilityPool.sol
849: require( msg.sender == address(activePool), "StabilityPool: Caller is not ActivePool");
853: require(msg.sender == address(troveManager), "StabilityPool: Caller is not TroveManager");
865: require(ICR >= collMCR, "StabilityPool: Cannot withdraw while there are troves with ICR < MCR");
File: Ethos-Vault/contracts/ReaperVaultERC4626.sol
270: require(y != 0, "Division by 0");
File: Ethos-Vault/contracts/ReaperVaultV2.sol
150: require(!emergencyShutdown, "Cannot add strategy during emergency shutdown");
151: require(_strategy != address(0), "Invalid strategy address");
152: require(strategies[_strategy].activation == 0, "Strategy already added");
153: require(address(this) == IStrategy(_strategy).vault(), "Strategy's vault does not match");
154: require(address(token) == IStrategy(_strategy).want(), "Strategy's want does not match");
155: require(_feeBPS <= PERCENT_DIVISOR / 5, "Fee cannot be higher than 20 BPS");
156: require(_allocBPS + totalAllocBPS <= PERCENT_DIVISOR, "Invalid allocBPS value");
180: require(strategies[_strategy].activation != 0, "Invalid strategy address");
181: require(_feeBPS <= PERCENT_DIVISOR / 5, "Fee cannot be higher than 20 BPS");
193: require(strategies[_strategy].activation != 0, "Invalid strategy address");
197: require(totalAllocBPS <= PERCENT_DIVISOR, "Invalid BPS value");
261: require(queueLength != 0, "Queue must not be empty");
267: require(params.activation != 0, "Invalid strategy address");
321: require(!emergencyShutdown, "Cannot deposit during emergency shutdown");
322: require(_amount != 0, "Invalid amount");
324: require(pool + _amount <= tvlCap, "Vault is full");
364: require(_shares != 0, "Invalid amount");
436: require(loss <= allocation, "Strategy loss cannot be greater than allocation");
497: require(strategy.activation != 0, "Unauthorized strategy");
568: require(_withdrawMaxLoss <= PERCENT_DIVISOR, "Invalid BPS value");
619: require(degradation <= DEGRADATION_COEFFICIENT, "Degradation cannot be more than 100%");
629: require(newTreasury != address(0), "Invalid address");
639: require(_token != address(token), "!token");
File: Ethos-Vault/contracts/abstract/ReaperBaseStrategyV4.sol
81: require(_multisigRoles.length == 3, "Invalid number of multisig roles");
96: require(msg.sender == vault, "Only vault can withdraw");
97: require(_amount != 0, "Amount cannot be zero");
98: require(_amount <= balanceOf(), "Ammount must be less than balance");
Instances (23):
File: Ethos-Core/contracts/ActivePool.sol
108: for(uint256 i = 0; i < numCollaterals; i++) {
File: Ethos-Core/contracts/CollateralConfig.sol
56: for(uint256 i = 0; i < _collaterals.length; i++) {
File: Ethos-Core/contracts/LQTY/LQTYStaking.sol
206: for (uint i = 0; i < assets.length; i++) {
228: for (uint i = 0; i < collaterals.length; i++) {
240: for (uint i = 0; i < numCollaterals; i++) {
File: Ethos-Core/contracts/StabilityPool.sol
351: for (uint i = 0; i < numCollaterals; i++) {
397: for (uint i = 0; i < numCollaterals; i++) {
640: for (uint i = 0; i < assets.length; i++) {
810: for (uint i = 0; i < collaterals.length; i++) {
831: for (uint i = 0; i < collaterals.length; i++) {
859: for (uint i = 0; i < numCollaterals; i++) {
File: Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol
35: uint16 private constant LENDER_REFERRAL_CODE_NONE = 0;
117: for (uint256 i = 0; i < numSteps; i = i.uncheckedInc()) {
165: for (uint256 i = 0; i < numSteps; i = i.uncheckedInc()) {
File: Ethos-Vault/contracts/ReaperVaultV2.sol
128: for (uint256 i = 0; i < numStrategists; i = i.uncheckedInc()) {
264: for (uint256 i = 0; i < queueLength; i = i.uncheckedInc()) {
369: uint256 totalLoss = 0;
371: uint256 vaultBalance = 0;
372: for (uint256 i = 0; i < queueLength; i = i.uncheckedInc()) {
File: Ethos-Vault/contracts/abstract/ReaperBaseStrategyV4.sol
77: for (uint256 i = 0; i < numStrategists; i = i.uncheckedInc()) {
100: uint256 amountFreed = 0;
112: uint256 debt = 0;
117: uint256 repayment = 0;
Instances (35):
File: Ethos-Core/contracts/ActivePool.sol
107: require(numCollaterals == _erc4626vaults.length, "Vaults array length must match number of collaterals");
133: require(_driftBps <= 500, "Exceeds max allowed value of 500 BPS");
File: Ethos-Core/contracts/BorrowerOperations.sol
525: require(collateralConfig.isCollateralAllowed(_collateral), "BorrowerOps: Invalid collateral address");
529: require(IERC20(_collateral).balanceOf(_user) >= _collAmount, "BorrowerOperations: Insufficient user collateral balance");
530: require(IERC20(_collateral).allowance(_user, address(this)) >= _collAmount, "BorrowerOperations: Insufficient collateral allowance");
534: require(_collTopUp == 0 || _collWithdrawal == 0, "BorrowerOperations: Cannot withdraw and add coll");
538: require(_collTopUp != 0 || _collWithdrawal != 0 || _LUSDChange != 0, "BorrowerOps: There must be either a collateral change or a debt change");
543: require(status == 1, "BorrowerOps: Trove does not exist or is closed");
552: require(_LUSDChange > 0, "BorrowerOps: Debt increase requires non-zero debtChange");
568: require(_collWithdrawal == 0, "BorrowerOps: Collateral withdrawal not permitted Recovery Mode");
617: require(_newICR >= _MCR, "BorrowerOps: An operation that would result in ICR < MCR is not permitted");
621: require(_newICR >= _CCR, "BorrowerOps: Operation must leave trove with ICR >= CCR");
625: require(_newICR >= _oldICR, "BorrowerOps: Cannot decrease your Trove's ICR in Recovery Mode");
629: require(_newTCR >= _CCR, "BorrowerOps: An operation that would result in TCR < CCR is not permitted");
637: require(_debtRepayment <= _currentDebt.sub(LUSD_GAS_COMPENSATION), "BorrowerOps: Amount repaid must not be larger than the Trove's debt");
641: require(msg.sender == stabilityPoolAddress, "BorrowerOps: Caller is not Stability Pool");
645: require(_lusdToken.balanceOf(_borrower) >= _debtRepayment, "BorrowerOps: Caller doesnt have enough LUSD to make repayment");
File: Ethos-Core/contracts/LQTY/CommunityIssuance.sol
133: require(msg.sender == stabilityPoolAddress, "CommunityIssuance: caller is not SP");
File: Ethos-Core/contracts/LQTY/LQTYStaking.sol
262: require(msg.sender == borrowerOperationsAddress, "LQTYStaking: caller is not BorrowerOps");
266: require(currentStake > 0, 'LQTYStaking: User must have a non-zero stake');
270: require(_amount > 0, 'LQTYStaking: Amount must be non-zero');
File: Ethos-Core/contracts/LUSDToken.sol
362: require(msg.sender == borrowerOperationsAddress, "LUSDToken: Caller is not BorrowerOperations");
377: require(msg.sender == stabilityPoolAddress, "LUSD: Caller is not the StabilityPool");
390: require(msg.sender == governanceAddress, "LUSDToken: Caller is not Governance");
394: require(!mintingPaused, "LUSDToken: Minting is currently paused");
File: Ethos-Core/contracts/StabilityPool.sol
849: require( msg.sender == address(activePool), "StabilityPool: Caller is not ActivePool");
853: require(msg.sender == address(troveManager), "StabilityPool: Caller is not TroveManager");
865: require(ICR >= collMCR, "StabilityPool: Cannot withdraw while there are troves with ICR < MCR");
870: require(_initialDeposit > 0, 'StabilityPool: User must have a non-zero deposit');
874: require(_amount > 0, 'StabilityPool: Amount must be non-zero');
File: Ethos-Vault/contracts/ReaperVaultV2.sol
150: require(!emergencyShutdown, "Cannot add strategy during emergency shutdown");
321: require(!emergencyShutdown, "Cannot deposit during emergency shutdown");
436: require(loss <= allocation, "Strategy loss cannot be greater than allocation");
619: require(degradation <= DEGRADATION_COEFFICIENT, "Degradation cannot be more than 100%");
File: Ethos-Vault/contracts/abstract/ReaperBaseStrategyV4.sol
98: require(_amount <= balanceOf(), "Ammount must be less than balance");
If a function modifier such as onlyOwner
is used, the function will revert if a normal user tries to pay the function. Marking the function as payable
will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided.
Instances (7):
File: Ethos-Core/contracts/ActivePool.sol
125: function setYieldingPercentage(address _collateral, uint256 _bps) external onlyOwner {
132: function setYieldingPercentageDrift(uint256 _driftBps) external onlyOwner {
138: function setYieldClaimThreshold(address _collateral, uint256 _threshold) external onlyOwner {
144: function setYieldDistributionParams(uint256 _treasurySplit, uint256 _SPSplit, uint256 _stakingSplit) external onlyOwner {
214: function manualRebalance(address _collateral, uint256 _simulatedAmountLeavingPool) external onlyOwner {
File: Ethos-Core/contracts/LQTY/CommunityIssuance.sol
101: function fund(uint amount) external onlyOwner {
120: function updateDistributionPeriod(uint256 _newDistributionPeriod) external onlyOwner {
Saves 5 gas per loop
Instances (17):
File: Ethos-Core/contracts/ActivePool.sol
108: for(uint256 i = 0; i < numCollaterals; i++) {
File: Ethos-Core/contracts/CollateralConfig.sol
56: for(uint256 i = 0; i < _collaterals.length; i++) {
File: Ethos-Core/contracts/LQTY/LQTYStaking.sol
206: for (uint i = 0; i < assets.length; i++) {
228: for (uint i = 0; i < collaterals.length; i++) {
240: for (uint i = 0; i < numCollaterals; i++) {
File: Ethos-Core/contracts/LUSDToken.sol
286: _nonces[owner]++, deadline))));
File: Ethos-Core/contracts/StabilityPool.sol
351: for (uint i = 0; i < numCollaterals; i++) {
397: for (uint i = 0; i < numCollaterals; i++) {
640: for (uint i = 0; i < assets.length; i++) {
810: for (uint i = 0; i < collaterals.length; i++) {
831: for (uint i = 0; i < collaterals.length; i++) {
859: for (uint i = 0; i < numCollaterals; i++) {
File: Ethos-Core/contracts/TroveManager.sol
608: for (vars.i = 0; vars.i < _n && vars.user != firstUser; vars.i++) {
690: for (vars.i = 0; vars.i < _n; vars.i++) {
808: for (vars.i = 0; vars.i < _troveArray.length; vars.i++) {
882: for (vars.i = 0; vars.i < _troveArray.length; vars.i++) {
File: Ethos-Vault/contracts/ReaperVaultERC4626.sol
273: if (x % y != 0) q++;
If 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
Instances (30):
File: Ethos-Core/contracts/ActivePool.sol
30: string constant public NAME = "ActivePool";
File: Ethos-Core/contracts/BorrowerOperations.sol
21: string constant public NAME = "BorrowerOperations";
File: Ethos-Core/contracts/CollateralConfig.sol
21: uint256 constant public MIN_ALLOWED_MCR = 1.1 ether; // 110%
25: uint256 constant public MIN_ALLOWED_CCR = 1.5 ether; // 150%
File: Ethos-Core/contracts/LQTY/CommunityIssuance.sol
19: string constant public NAME = "CommunityIssuance";
File: Ethos-Core/contracts/LQTY/LQTYStaking.sol
23: string constant public NAME = "LQTYStaking";
File: Ethos-Core/contracts/StabilityPool.sol
150: string constant public NAME = "StabilityPool";
197: uint public constant SCALE_FACTOR = 1e9;
File: Ethos-Core/contracts/TroveManager.sol
48: uint constant public SECONDS_IN_ONE_MINUTE = 60;
53: uint constant public MINUTE_DECAY_FACTOR = 999037758833783000;
54: uint constant public override REDEMPTION_FEE_FLOOR = DECIMAL_PRECISION / 1000 * 5; // 0.5%
55: uint constant public MAX_BORROWING_FEE = DECIMAL_PRECISION / 100 * 5; // 5%
61: uint constant public BETA = 2;
File: Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol
24: address public constant VELO_ROUTER = 0xa132DAB612dB5cB9fC9Ac426A0Cc215A3423F9c9;
25: ILendingPoolAddressesProvider public constant ADDRESSES_PROVIDER =
27: IAaveProtocolDataProvider public constant DATA_PROVIDER =
29: IRewardsController public constant REWARDER = IRewardsController(0x6A0406B8103Ec68EE9A713A073C7bD587c5e04aD);
File: Ethos-Vault/contracts/ReaperVaultV2.sol
40: uint256 public constant DEGRADATION_COEFFICIENT = 10**18; // The unit for calculating profit degradation.
41: uint256 public constant PERCENT_DIVISOR = 10000;
73: bytes32 public constant DEPOSITOR = keccak256("DEPOSITOR");
74: bytes32 public constant STRATEGIST = keccak256("STRATEGIST");
75: bytes32 public constant GUARDIAN = keccak256("GUARDIAN");
76: bytes32 public constant ADMIN = keccak256("ADMIN");
File: Ethos-Vault/contracts/abstract/ReaperBaseStrategyV4.sol
23: uint256 public constant PERCENT_DIVISOR = 10_000;
24: uint256 public constant UPGRADE_TIMELOCK = 48 hours; // minimum 48 hours for RF
25: uint256 public constant FUTURE_NEXT_PROPOSAL_TIME = 365 days * 100;
49: bytes32 public constant KEEPER = keccak256("KEEPER");
50: bytes32 public constant STRATEGIST = keccak256("STRATEGIST");
51: bytes32 public constant GUARDIAN = keccak256("GUARDIAN");
52: bytes32 public constant ADMIN = keccak256("ADMIN");
Instances (27):
File: Ethos-Core/contracts/ActivePool.sol
278: if (vars.netAssetMovement > 0) {
File: Ethos-Core/contracts/BorrowerOperations.sol
128: assert(MIN_NET_DEBT > 0);
197: assert(vars.compositeDebt > 0);
301: assert(msg.sender == _borrower || (msg.sender == stabilityPoolAddress && _collTopUp > 0 && _LUSDChange == 0));
337: if (!_isDebtIncrease && _LUSDChange > 0) {
552: require(_LUSDChange > 0, "BorrowerOps: Debt increase requires non-zero debtChange");
File: Ethos-Core/contracts/LQTY/LQTYStaking.sol
152: if (_LQTYamount > 0) {
181: if (totalLQTYStaked > 0) {collFeePerLQTYStaked = _collFee.mul(DECIMAL_PRECISION).div(totalLQTYStaked);}
191: if (totalLQTYStaked > 0) {LUSDFeePerLQTYStaked = _LUSDFee.mul(DECIMAL_PRECISION).div(totalLQTYStaked);}
266: require(currentStake > 0, 'LQTYStaking: User must have a non-zero stake');
270: require(_amount > 0, 'LQTYStaking: Amount must be non-zero');
File: Ethos-Core/contracts/LUSDToken.sol
279: if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
File: Ethos-Core/contracts/StabilityPool.sol
591: assert(newP > 0);
870: require(_initialDeposit > 0, 'StabilityPool: User must have a non-zero deposit');
874: require(_amount > 0, 'StabilityPool: Amount must be non-zero');
File: Ethos-Core/contracts/TroveManager.sol
424: if (singleLiquidation.collSurplus > 0) {
452: if (_LUSDInStabPool > 0) {
551: require(totals.totalDebtInSequence > 0);
563: if (totals.totalCollSurplus > 0) {
754: require(totals.totalDebtInSequence > 0);
766: if (totals.totalCollSurplus > 0) {
916: if (_LUSD > 0) {
920: if (_collAmount > 0) {
1224: assert(totalStakesSnapshot[_collateral] > 0);
1414: assert(newBaseRate > 0); // Base rate is always non-zero after redemption
File: Ethos-Vault/contracts/ReaperVaultV2.sol
502: } else if (_roi > 0) {
518: } else if (vars.available > 0) {
If the functions are required by an interface, the contract should inherit from that interface and use the override
keyword
Instances (1):
File: Ethos-Core/contracts/BorrowerOperations.sol
432: function _getUSDValue(uint _coll, uint _price, uint256 _collDecimals) internal pure returns (uint) {
Issue | Instances | |
---|---|---|
NC-1 | Missing checks for address(0) when assigning values to address state variables |
26 |
NC-2 | require() / revert() statements should have descriptive reason strings |
10 |
NC-3 | Return values of approve() not checked |
5 |
NC-4 | TODO Left in the code | 2 |
NC-5 | Event is missing indexed fields |
93 |
NC-6 | Functions not used internally could be marked external | 2 |
NC-7 | Typos | 32 |
Instances (26):
File: Ethos-Core/contracts/ActivePool.sol
96: collateralConfigAddress = _collateralConfigAddress;
97: borrowerOperationsAddress = _borrowerOperationsAddress;
98: troveManagerAddress = _troveManagerAddress;
99: stabilityPoolAddress = _stabilityPoolAddress;
100: defaultPoolAddress = _defaultPoolAddress;
101: collSurplusPoolAddress = _collSurplusPoolAddress;
103: lqtyStakingAddress = _lqtyStakingAddress;
File: Ethos-Core/contracts/BorrowerOperations.sol
146: stabilityPoolAddress = _stabilityPoolAddress;
147: gasPoolAddress = _gasPoolAddress;
152: lqtyStakingAddress = _lqtyStakingAddress;
File: Ethos-Core/contracts/LQTY/CommunityIssuance.sol
75: stabilityPoolAddress = _stabilityPoolAddress;
File: Ethos-Core/contracts/LQTY/LQTYStaking.sol
88: troveManagerAddress = _troveManagerAddress;
89: borrowerOperationsAddress = _borrowerOperationsAddress;
90: activePoolAddress = _activePoolAddress;
File: Ethos-Core/contracts/LUSDToken.sol
102: troveManagerAddress = _troveManagerAddress;
106: stabilityPoolAddress = _stabilityPoolAddress;
110: borrowerOperationsAddress = _borrowerOperationsAddress;
114: governanceAddress = _governanceAddress;
117: guardianAddress = _guardianAddress;
149: governanceAddress = _newGovernanceAddress;
156: guardianAddress = _newGuardianAddress;
170: troveManagerAddress = _newTroveManagerAddress;
174: stabilityPoolAddress = _newStabilityPoolAddress;
178: borrowerOperationsAddress = _newBorrowerOperationsAddress;
File: Ethos-Core/contracts/TroveManager.sol
266: borrowerOperationsAddress = _borrowerOperationsAddress;
271: gasPoolAddress = _gasPoolAddress;
Instances (10):
File: Ethos-Core/contracts/TroveManager.sol
250: require(msg.sender == owner);
551: require(totals.totalDebtInSequence > 0);
716: require(_troveArray.length != 0);
754: require(totals.totalDebtInSequence > 0);
1450: require(redemptionFee < _collateralDrawn);
1523: require(msg.sender == borrowerOperationsAddress);
1527: require(msg.sender == address(redemptionHelper));
1531: require(msg.sender == borrowerOperationsAddress || msg.sender == address(redemptionHelper));
1535: require(Troves[_borrower][_collateral].status == Status.active);
1539: require (TroveOwnersArrayLength > 1 && sortedTroves.getSize(_collateral) > 1);
Not all IERC20 implementations revert()
when there's a failure in approve()
. The function signature has a boolean return value and they indicate errors that way instead. By not checking the return value, operations that should have marked as failed, may potentially go through without actually approving anything
Instances (5):
File: Ethos-Core/contracts/LUSDToken.sol
231: _approve(msg.sender, spender, amount);
238: _approve(sender, msg.sender, _allowances[sender][msg.sender].sub(amount, "ERC20: transfer amount exceeds allowance"));
243: _approve(msg.sender, spender, _allowances[msg.sender][spender].add(addedValue));
248: _approve(msg.sender, spender, _allowances[msg.sender][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
289: _approve(owner, spender, amount);
TODOs may signal that a feature is missing or not ready for audit, consider resolving the issue and removing the TODO comment
Instances (2):
File: Ethos-Core/contracts/StabilityPool.sol
335: /* TODO tess3rac7 unused var, but previously included in ETHGainWithdrawn event log.
380: /* TODO tess3rac7 unused var, but previously included in ETHGainWithdrawn event log.
Index event fields make the field more quickly accessible to off-chain tools that parse events. However, note that each index field costs extra gas during emission, so it's not necessarily best to index the maximum allowed per event (three fields). Each event should use three indexed fields if there are three or more fields, and gas usage is not particularly of concern for the events in question. If there are fewer than three fields, all of the fields should be indexed.
Instances (93):
File: Ethos-Core/contracts/ActivePool.sol
58: event CollateralConfigAddressChanged(address _newCollateralConfigAddress);
59: event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);
60: event TroveManagerAddressChanged(address _newTroveManagerAddress);
61: event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);
62: event ActivePoolLUSDDebtUpdated(address _collateral, uint _LUSDDebt);
63: event ActivePoolCollateralBalanceUpdated(address _collateral, uint _amount);
64: event YieldingPercentageUpdated(address _collateral, uint256 _bps);
65: event YieldingPercentageDriftUpdated(uint256 _driftBps);
66: event YieldClaimThresholdUpdated(address _collateral, uint256 _threshold);
67: event YieldDistributionParamsUpdated(uint256 _treasurySplit, uint256 _SPSplit, uint256 _stakingSplit);
File: Ethos-Core/contracts/BorrowerOperations.sol
92: event CollateralConfigAddressChanged(address _newCollateralConfigAddress);
93: event TroveManagerAddressChanged(address _newTroveManagerAddress);
94: event ActivePoolAddressChanged(address _activePoolAddress);
95: event DefaultPoolAddressChanged(address _defaultPoolAddress);
96: event StabilityPoolAddressChanged(address _stabilityPoolAddress);
97: event GasPoolAddressChanged(address _gasPoolAddress);
98: event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);
99: event PriceFeedAddressChanged(address _newPriceFeedAddress);
100: event SortedTrovesAddressChanged(address _sortedTrovesAddress);
101: event LUSDTokenAddressChanged(address _lusdTokenAddress);
102: event LQTYStakingAddressChanged(address _lqtyStakingAddress);
104: event TroveCreated(address indexed _borrower, address _collateral, uint arrayIndex);
105: event TroveUpdated(address indexed _borrower, address _collateral, uint _debt, uint _coll, uint stake, BorrowerOperation operation);
106: event LUSDBorrowingFeePaid(address indexed _borrower, address _collateral, uint _LUSDFee);
File: Ethos-Core/contracts/CollateralConfig.sol
37: event CollateralWhitelisted(address _collateral, uint256 _decimals, uint256 _MCR, uint256 _CCR);
38: event CollateralRatiosUpdated(address _collateral, uint256 _MCR, uint256 _CCR);
File: Ethos-Core/contracts/LQTY/CommunityIssuance.sol
50: event OathTokenAddressSet(address _oathTokenAddress);
51: event LogRewardPerSecond(uint _rewardPerSecond);
52: event StabilityPoolAddressSet(address _stabilityPoolAddress);
53: event TotalOATHIssuedUpdated(uint _totalOATHIssued);
File: Ethos-Core/contracts/LQTY/LQTYStaking.sol
49: event LQTYTokenAddressSet(address _lqtyTokenAddress);
50: event LUSDTokenAddressSet(address _lusdTokenAddress);
51: event TroveManagerAddressSet(address _troveManager);
52: event BorrowerOperationsAddressSet(address _borrowerOperationsAddress);
53: event ActivePoolAddressSet(address _activePoolAddress);
54: event CollateralConfigAddressSet(address _collateralConfigAddress);
56: event StakeChanged(address indexed staker, uint newStake);
57: event StakingGainsWithdrawn(address indexed staker, uint LUSDGain, address[] _assets, uint[] _amounts);
58: event F_CollateralUpdated(address _collateral, uint _F_Collateral);
59: event F_LUSDUpdated(uint _F_LUSD);
60: event TotalLQTYStakedUpdated(uint _totalLQTYStaked);
61: event CollateralSent(address _account, address _collateral, uint _amount);
62: event StakerSnapshotsUpdated(address _staker, address[] _assets, uint[] _amounts, uint _F_LUSD);
File: Ethos-Core/contracts/LUSDToken.sol
78: event TroveManagerAddressChanged(address _troveManagerAddress);
79: event StabilityPoolAddressChanged(address _newStabilityPoolAddress);
80: event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);
81: event GovernanceAddressChanged(address _governanceAddress);
82: event GuardianAddressChanged(address _guardianAddress);
File: Ethos-Core/contracts/StabilityPool.sol
233: event StabilityPoolCollateralBalanceUpdated(address _collateral, uint _newBalance);
234: event StabilityPoolLUSDBalanceUpdated(uint _newBalance);
236: event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);
237: event CollateralConfigAddressChanged(address _newCollateralConfigAddress);
238: event TroveManagerAddressChanged(address _newTroveManagerAddress);
239: event ActivePoolAddressChanged(address _newActivePoolAddress);
240: event DefaultPoolAddressChanged(address _newDefaultPoolAddress);
241: event LUSDTokenAddressChanged(address _newLUSDTokenAddress);
242: event SortedTrovesAddressChanged(address _newSortedTrovesAddress);
243: event PriceFeedAddressChanged(address _newPriceFeedAddress);
244: event CommunityIssuanceAddressChanged(address _newCommunityIssuanceAddress);
246: event P_Updated(uint _P);
247: event S_Updated(address _collateral, uint _S, uint128 _epoch, uint128 _scale);
248: event G_Updated(uint _G, uint128 _epoch, uint128 _scale);
249: event EpochUpdated(uint128 _currentEpoch);
250: event ScaleUpdated(uint128 _currentScale);
252: event DepositSnapshotUpdated(address indexed _depositor, uint _P, address[] _assets, uint[] _amounts, uint _G);
253: event UserDepositChanged(address indexed _depositor, uint _newDeposit);
255: event CollateralGainWithdrawn(address indexed _depositor, address _collateral, uint _collAmount);
256: event LQTYPaidToDepositor(address indexed _depositor, uint _LQTY);
257: event CollateralSent(address _collateral, address _to, uint _amount);
File: Ethos-Core/contracts/TroveManager.sol
186: event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);
187: event CollateralConfigAddressChanged(address _newCollateralConfigAddress);
188: event PriceFeedAddressChanged(address _newPriceFeedAddress);
189: event LUSDTokenAddressChanged(address _newLUSDTokenAddress);
190: event ActivePoolAddressChanged(address _activePoolAddress);
191: event DefaultPoolAddressChanged(address _defaultPoolAddress);
192: event StabilityPoolAddressChanged(address _stabilityPoolAddress);
193: event GasPoolAddressChanged(address _gasPoolAddress);
194: event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);
195: event SortedTrovesAddressChanged(address _sortedTrovesAddress);
196: event LQTYTokenAddressChanged(address _lqtyTokenAddress);
197: event LQTYStakingAddressChanged(address _lqtyStakingAddress);
198: event RedemptionHelperAddressChanged(address _redemptionHelperAddress);
200: event Liquidation(address _collateral, uint _liquidatedDebt, uint _liquidatedColl, uint _collGasCompensation, uint _LUSDGasCompensation);
201: event TroveUpdated(address indexed _borrower, address _collateral, uint _debt, uint _coll, uint _stake, TroveManagerOperation _operation);
202: event TroveLiquidated(address indexed _borrower, address _collateral, uint _debt, uint _coll, TroveManagerOperation _operation);
203: event BaseRateUpdated(uint _baseRate);
204: event LastFeeOpTimeUpdated(uint _lastFeeOpTime);
205: event TotalStakesUpdated(address _collateral, uint _newTotalStakes);
206: event SystemSnapshotsUpdated(address _collateral, uint _totalStakesSnapshot, uint _totalCollateralSnapshot);
207: event LTermsUpdated(address _collateral, uint _L_Collateral, uint _L_LUSDDebt);
208: event TroveSnapshotsUpdated(address _collateral, uint _L_Collateral, uint _L_LUSDDebt);
209: event TroveIndexUpdated(address _borrower, address _collateral, uint _newIndex);
210: event Redemption(
Instances (2):
File: Ethos-Core/contracts/TroveManager.sol
1045: function getNominalICR(address _borrower, address _collateral) public view override returns (uint) {
1440: function getRedemptionFee(uint _collateralDrawn) public view override returns (uint) {
Instances (32):
File: Ethos-Core/contracts/ActivePool.sol
- 49: uint256 public yieldingPercentageDrift = 100; // rebalance iff % is off by more than 100 BPS
+ 49: uint256 public yieldingPercentageDrift = 100; // rebalance if % is off by more than 100 BPS
File: Ethos-Core/contracts/BorrowerOperations.sol
- 127: // This makes impossible to open a trove with zero withdrawn LUSD
+ 127: // This makes it impossible to open a trove with zero withdrawn LUSD
- 230: // Pull collateral, move it to the Active Pool, and mint the LUSDAmount to the borrower
+ 230: // Pull collateral, move it to the Active Pool, and mint the LUSD amount to the borrower
- 241: // Send more collateral to an existing trove
+ 241: // Send more collateral to an existing Trove
- 253: // Withdraw collateral from a trove
+ 253: // Withdraw collateral from a Trove
- 258: // Withdraw LUSD tokens from a trove: mint new LUSD tokens to the owner, and increase the trove's debt accordingly
+ 258: // Withdraw LUSD tokens from a Trove: mint new LUSD tokens to the owner, and increase the Trove's debt accordingly
- 305: // Get the collChange based on whether or not collateral was sent in the transaction
+ 305: // Get the collChange based on whether or not collateral was sent in the transaction (i.e. if the Stability Pool is sending collateral to a Trove)
File: Ethos-Core/contracts/CollateralConfig.sol
- 23: // Smallest allowed value for Critical system collateral ratio.
+ 23: // Smallest allowed value for the critical system collateral ratio.
- 34: address[] public collaterals; // for returning entire list of allowed collaterals
+ 34: address[] public collaterals; // for returning the entire list of allowed collaterals.
File: Ethos-Core/contracts/LQTY/LQTYStaking.sol
- 140: // Unstake the LQTY and send the it back to the caller, along with their accumulated LUSD & collateral gains.
+ 140: // Unstake the LQTY and send it back to the caller, along with their accumulated LUSD & collateral gains
- 146: // Grab any accumulated ETH and LUSD gains from the current stake
+ 146: // Grab any accumulated collateral and LUSD gains from the current stake
- 170: // Send accumulated LUSD and ETH gains to the caller
+ 170: // Send accumulated LUSD and collateral gains to the caller
File: Ethos-Core/contracts/LUSDToken.sol
- 73: // Copied from LQTYToken.sol; since we deleted that file, we use LUSDToken's initialization
+ 73: // Copied from LQTYToken.sol; since we deleted that file, we use LQTYToken's initialization
- 183: // --- Functions for intra-Liquity calls ---
+ 183: // --- Functions for intra-Liquity calls --- // TODO: remove this comment
- 308: // --- Internal operations ---
+ 308: // Warning: sanity checks (for sender and recipient) should have been done before calling these internal functions
- 309: // Warning: sanity checks (for sender and recipient) should have been done before calling these internal functions
+ 309: // --- 'require' functions ---
- 344: // --- 'require' functions ---
+ 344: // only latest borrowerOps version can mint
- 361: // only latest borrowerOps version can mint
+ 361: // old versions of the protocol may still burn
- 366: // old versions of the protocol may still burn
+ 366: // only latest stabilityPool can accept new deposits
- 376: // only latest stabilityPool can accept new deposits
+ 376: // old versions of the protocol may still:
- 381: // old versions of the protocol may still:
+ 381: // 1. send lusd gas reserve to liquidator
- 382: // 1. send lusd gas reserve to liquidator
+ 382: // 2. be able to return users their lusd from the stability pool
- 383: // 2. be able to return users their lusd from the stability pool
+ 383: // --- Optional functions ---
397: // --- Optional functions ---
File: Ethos-Core/contracts/StabilityPool.sol
- 728: // Internal function, used to calculcate compounded deposits.
+ 728: // Internal function, used to calculate compounded deposits.
File: Ethos-Core/contracts/TroveManager.sol
- 41: // A doubly linked list of Troves, sorted by their sorted by their collateral ratios
+ 41: // A doubly linked list of Troves, sorted by their collateral ratios
- 114: // Array of all active trove addresses - used to to compute an approximate hint off-chain, for the sorted list insertion
+ 114: // Array of all active trove addresses - used to compute an approximate hint off-chain, for the sorted list insertion
File: Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol
- 1: // SPDX-License-Identifier: BUSL1.1
+ 1: // SPDX-License-Identifier: BSL-1.0
File: Ethos-Vault/contracts/ReaperVaultERC4626.sol
- 224: // Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
+ 224: // Allows an on-chain or off-chain user to simulate the effects of their redemption at the current block,
File: Ethos-Vault/contracts/ReaperVaultV2.sol
- 32: uint256 lastReport; // block.timestamp of the last time a report occured
+ 32: uint256 lastReport; // block.timestamp of the last time a report occurred
- 434: // Loss can only be up the amount of capital allocated to the strategy
+ 434: // Loss can only be up to the amount of capital allocated to the strategy
File: Ethos-Vault/contracts/abstract/ReaperBaseStrategyV4.sol
- 24: uint256 public constant UPGRADE_TIMELOCK = 48 hours; // minimum 48 hours for RF
+ 24: uint256 public constant UPGRADE_TIMELOCK = 48 hours; // minimum 48 hours for RFP
Issue | Instances | |
---|---|---|
L-1 | abi.encodePacked() should not be used with dynamic types when passing the result to a hash function such as keccak256() |
1 |
L-2 | Do not use deprecated library functions | 1 |
L-3 | Empty Function Body - Consider commenting why | 2 |
L-4 | Initializers could be front-run | 8 |
L-5 | Unsafe ERC20 operation(s) | 4 |
[L-1] abi.encodePacked()
should not be used with dynamic types when passing the result to a hash function such as keccak256()
Use abi.encode()
instead which will pad items to 32 bytes, which will prevent hash collisions (e.g. abi.encodePacked(0x123,0x456)
=> 0x123456
=> abi.encodePacked(0x1,0x23456)
, but abi.encode(0x123,0x456)
=> 0x0...1230...456
). "Unless there is a compelling reason, abi.encode
should be preferred". If there is only one argument to abi.encodePacked()
it can often be cast to bytes()
or bytes32()
instead.
If all arguments are strings and or bytes, bytes.concat()
should be used instead
Instances (1):
File: Ethos-Core/contracts/LUSDToken.sol
283: bytes32 digest = keccak256(abi.encodePacked('\x19\x01',
Instances (1):
File: Ethos-Vault/contracts/abstract/ReaperBaseStrategyV4.sol
74: IERC20Upgradeable(want).safeApprove(vault, type(uint256).max);
Instances (2):
File: Ethos-Vault/contracts/ReaperVaultERC4626.sol
24: ) ReaperVaultV2(_token, _name, _symbol, _tvlCap, _treasury, _strategists, _multisigRoles) {}
File: Ethos-Vault/contracts/abstract/ReaperBaseStrategyV4.sol
61: constructor() initializer {}
Initializers could be front-run, allowing an attacker to either set their own values, take ownership of the contract, and in the best case forcing a re-deployment
Instances (8):
File: Ethos-Core/contracts/CollateralConfig.sol
46: function initialize(
File: Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol
62: function initialize(
67: ) public initializer {
70: __ReaperBaseStrategy_init(_vault, want, _strategists, _multisigRoles);
File: Ethos-Vault/contracts/abstract/ReaperBaseStrategyV4.sol
61: constructor() initializer {}
63: function __ReaperBaseStrategy_init(
69: __UUPSUpgradeable_init();
70: __AccessControlEnumerable_init();
Instances (4):
File: Ethos-Core/contracts/LQTY/CommunityIssuance.sol
103: OathToken.transferFrom(msg.sender, address(this), amount);
127: OathToken.transfer(_account, _OathAmount);
File: Ethos-Core/contracts/LQTY/LQTYStaking.sol
135: lusdToken.transfer(msg.sender, LUSDGain);
171: lusdToken.transfer(msg.sender, LUSDGain);
Issue | Instances | |
---|---|---|
M-1 | Centralization Risk for trusted owners | 21 |
Contracts have owners with privileged rights to perform admin tasks and need to be trusted to not perform malicious updates or drain funds.
Instances (21):
File: Ethos-Core/contracts/ActivePool.sol
26: contract ActivePool is Ownable, CheckContract, IActivePool {
125: function setYieldingPercentage(address _collateral, uint256 _bps) external onlyOwner {
132: function setYieldingPercentageDrift(uint256 _driftBps) external onlyOwner {
138: function setYieldClaimThreshold(address _collateral, uint256 _threshold) external onlyOwner {
144: function setYieldDistributionParams(uint256 _treasurySplit, uint256 _SPSplit, uint256 _stakingSplit) external onlyOwner {
214: function manualRebalance(address _collateral, uint256 _simulatedAmountLeavingPool) external onlyOwner {
File: Ethos-Core/contracts/BorrowerOperations.sol
18: contract BorrowerOperations is LiquityBase, Ownable, CheckContract, IBorrowerOperations {
File: Ethos-Core/contracts/CollateralConfig.sol
15: contract CollateralConfig is ICollateralConfig, CheckContract, Ownable {
50: ) external override onlyOwner {
89: ) external onlyOwner checkCollateral(_collateral) {
File: Ethos-Core/contracts/LQTY/CommunityIssuance.sol
14: contract CommunityIssuance is ICommunityIssuance, Ownable, CheckContract, BaseMath {
67: onlyOwner
101: function fund(uint amount) external onlyOwner {
120: function updateDistributionPeriod(uint256 _newDistributionPeriod) external onlyOwner {
File: Ethos-Core/contracts/LQTY/LQTYStaking.sol
18: contract LQTYStaking is ILQTYStaking, Ownable, CheckContract, BaseMath {
76: onlyOwner
File: Ethos-Core/contracts/StabilityPool.sol
146: contract StabilityPool is LiquityBase, Ownable, CheckContract, IStabilityPool {
File: Ethos-Core/contracts/TroveManager.sol
18: contract TroveManager is LiquityBase, /*Ownable,*/ CheckContract, ITroveManager {
File: Ethos-Vault/contracts/ReaperVaultV2.sol
21: contract ReaperVaultV2 is ReaperAccessControl, ERC20, IERC4626Events, AccessControlEnumerable, ReentrancyGuard {
21: contract ReaperVaultV2 is ReaperAccessControl, ERC20, IERC4626Events, AccessControlEnumerable, ReentrancyGuard {
File: Ethos-Vault/contracts/abstract/ReaperBaseStrategyV4.sol
15: ReaperAccessControl,