Ethos Reserve contest - LethL's results

A CDP-backed stablecoin platform designed to generate yield on underlying assets to establish a sustainable DeFi stable interest rate.

General Information

Platform: Code4rena

Start Date: 16/02/2023

Pot Size: $144,750 USDC

Total HM: 17

Participants: 154

Period: 19 days

Judge: Trust

Total Solo HM: 5

Id: 216

League: ETH

Ethos Reserve

Findings Distribution

Researcher Performance

Rank: 153/154

Findings: 1

Award: $42.07

Gas:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Summary

IssueInstances
Gas-1<x> += <y> costs more gas than <x> = <x> + <y> for state variables9
Gas-2Use of Named Returns for Local Variables Saves Gas35
Gas-3Using a ternary operator instead of an "if-else" statement5
Gas-4Expressions for constant values such as a call to keccak256(), should use immutable rather than constant8
Gas-5Pre-calculate the hardcoded hash with keccak256() before and only use the result to save gas10
Gas-6Using require instead of assert20

[Gas-1] <x> += <y> costs more gas than <x> = <x> + <y> for state variables

Using x = x+y instead of x += y can help to save gas. Similarly, using <x> -= <y> costs more gas than <x> = <x> - <y>.

Instances(9):

File: Ethos-Vault/contracts/ReaperVaultV2.sol 168: totalAllocBPS += _allocBPS; 194: totalAllocBPS -= strategies[_strategy].allocBPS; 196: totalAllocBPS += _allocBPS; 214: totalAllocBPS -= strategies[_strategy].allocBPS; 396: totalAllocated -= actualWithdrawn; 445: totalAllocBPS -= bpsChange; 452: totalAllocated -= loss; 515: totalAllocated -= vars.debtPayment; 521: totalAllocated += vars.credit;

Link to Code

[Gas-2] Use of Named Returns for Local Variables Saves Gas

Using named return values as temporary local variables can help you conserve gas.

For example, the following code block can be refactored as follows:

File: Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol 230: function balanceOfPool() public view returns (uint256 supply) { 231: (supply, , , , , , , , ) = IAaveProtocolDataProvider(DATA_PROVIDER).getUserReserveData( 232: address(want), 233: address(this) 234: ); 235: }

Link to Code

Instances(35)

File: Ethos-Core/contracts/BorrowerOperations.sol 421: uint LUSDFee = _troveManager.getBorrowingFee(_LUSDAmount); 433: uint usdValue = _price.mul(_coll).div(10**_collDecimals); 468: uint newColl = (_isCollIncrease) ? _troveManager.increaseTroveColl(_borrower, _collateral, _collChange) 470: uint newDebt = (_isDebtIncrease) ? _troveManager.increaseTroveDebt(_borrower, _collateral, _debtChange) 677: uint newNICR = LiquityMath._computeNominalCR(newColl, newDebt, _collateralDecimals); 699: uint newICR = LiquityMath._computeCR(newColl, newDebt, _price, _collateralDecimals); 715: uint newColl = _coll; 716: uint newDebt = _debt; 744: uint newTCR = LiquityMath._computeCR(totalColl, totalDebt, _price, _collateralDecimals);

Link to Code

File: Ethos-Core/contracts/TroveManager.sol 1049: uint NICR = LiquityMath._computeNominalCR(currentCollateral, currentLUSDDebt, collDecimals); 1062: uint ICR = LiquityMath._computeCR(currentCollateral, currentLUSDDebt, _price, collDecimals); 1070: uint currentCollateral = Troves[_borrower][_collateral].coll.add(pendingCollateralReward); 1071: uint currentLUSDDebt = Troves[_borrower][_collateral].debt.add(pendingLUSDDebtReward); 1132: uint pendingCollateralReward = stake.mul(rewardPerUnitStaked).div(10**collDecimals); 1147: uint pendingLUSDDebtReward = stake.mul(rewardPerUnitStaked).div(10**collDecimals); 1202: uint newStake = _computeNewStake(_collateral, Troves[_borrower][_collateral].coll); 1214: uint stake; 1362: uint256 collDecimals = collateralConfig.getCollateralDecimals(_collateral); 1411: uint newBaseRate = decayedBaseRate.add(redeemedLUSDFraction.div(BETA)); 1449: uint redemptionFee = _redemptionRate.mul(_collateralDrawn).div(DECIMAL_PRECISION); 1569: uint newColl = Troves[_borrower][_collateral].coll.add(_collIncrease); 1576: uint newColl = Troves[_borrower][_collateral].coll.sub(_collDecrease); 1583: uint newDebt = Troves[_borrower][_collateral].debt.add(_debtIncrease); 1590: uint newDebt = Troves[_borrower][_collateral].debt.sub(_debtDecrease);

Link to Code

File: Ethos-Core/contracts/StabilityPool.sol 453: uint LQTYPerUnitStaked = LQTYNumerator.div(_totalLUSDDeposits); 688: uint LQTYGain = _getLQTYGainFromSnapshots(initialDeposit, snapshots); 707: uint LQTYGain = initialDeposit.mul(firstPortion.add(secondPortion)).div(P_Snapshot).div(DECIMAL_PRECISION); 724: uint compoundedDeposit = _getCompoundedDepositFromSnapshots(initialDeposit, snapshots); 744: uint compoundedDeposit;

Link to Code

File: Ethos-Core/contracts/LQTY/LQTYStaking.sol 219: uint LUSDGain = stakes[_user].mul(F_LUSD.sub(F_LUSD_Snapshot)).div(DECIMAL_PRECISION);

Link to Code

File: Ethos-Vault/contracts/ReaperVaultERC4626.sol 272: uint256 q = x / y;

Link to Code

Ethos-Vault/contracts/ReaperVaultV2.sol 463: uint256 performanceFee = (gain * strategies[strategy].feeBPS) / PERCENT_DIVISOR; 660: bytes32[] memory cascadingAccessRoles = new bytes32[](5);

Link to Code

Ethos-Vault/contracts/abstract/ReaperBaseStrategyV4.sol 204: bytes32[] memory cascadingAccessRoles = new bytes32[](5);

Link to Code

Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol 231: (uint256 supply, , , , , , , , ) = IAaveProtocolDataProvider(DATA_PROVIDER).getUserReserveData(

Link to Code

[Gas-3] Using a ternary operator instead of an "if-else" statement

For simple "if-else" statements that are easy to read, replacing a "if-else" statement with a ternary operator can help you save gas.

Instances(5):

File: Ethos-Core/contracts/BorrowerOperations.sol 490: if (_isDebtIncrease) { 649: if (_isRecoveryMode) {

Link to Code

File: Ethos-Vault/contracts/ReaperVaultV2.sol 331: if (totalSupply() == 0) { 534: if (vars.lockedProfitBeforeLoss > vars.loss) { 604: if (_active) {

Link to Code

[Gas-4] Expressions for constant values such as a call to keccak256(), should use immutable rather than constant

The consequence of this is that the keccak256() operation is carried out each time the variable is utilized, leading to a rise in gas costs compared to just storing the calculated hash. By making it immutable, the hashing will only be done during contract deployment, which will reduce gas consumption.

Instances(8):

File: Ethos-Vault/contracts/ReaperVaultV2.sol 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");

Link to Code

File: Ethos-Vault/contracts/abstract/ReaperBaseStrategyV4.sol 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");

Link to Code

[Gas-5] Pre-calculate the hardcoded hash with keccak256() before and only use the result to save gas

Performing the hardcoded keccak256() hash calculation every time the contract is deployed or a function is called is less gas-efficient than pre-calculating the hash beforehand and using only its result.

For example, the following code block can be refactored as follows:

File: Ethos-Core/contracts/LUSDToken.sol 123: _HASHED_NAME = 0xabccaf2943f70764a048255e50e07d10e3c94973a6c6ba8b8ea62b1155209b01; // keccak256(bytes(_NAME)); 124: _HASHED_VERSION = 0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6; // keccak256(bytes(_VERSION)); 126: _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(_TYPE_HASH, 127: 0xabccaf2943f70764a048255e50e07d10e3c94973a6c6ba8b8ea62b1155209b01, // keccak256(bytes(_NAME)); 128: 0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6); // keccak256(bytes(_VERSION));

Link to Code

Instances(10):

File: Ethos-Core/contracts/LUSDToken.sol 120: bytes32 hashedName = keccak256(bytes(_NAME)); 121: bytes32 hashedVersion = keccak256(bytes(_VERSION));

Link to Code

File: Ethos-Vault/contracts/ReaperVaultV2.sol 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");

Link to Code

File: Ethos-Vault/contracts/abstract/ReaperBaseStrategyV4.sol 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");

Link to Code

[Gas-6] Using require instead of assert

When the condition is false, assert tends to consume all remaining gas and undo all changes made. But require refunds all remaining gas fees we offered to pay above and beyond, reverting all changes.

Instances(20):

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)); 331: assert(_collWithdrawal <= vars.coll);

Link to Code

File: Ethos-Core/contracts/TroveManager.sol 417: assert(_LUSDInStabPool != 0); 1224: assert(totalStakesSnapshot[_collateral] > 0); 1279: assert(closedStatus != Status.nonExistent && closedStatus != Status.active); 1342: assert(troveStatus != Status.nonExistent && troveStatus != Status.active); 1348: assert(index <= idxLast); 1414: assert(newBaseRate > 0); // Base rate is always non-zero after redemption 1489: assert(decayedBaseRate <= DECIMAL_PRECISION); // The baseRate can decay to 0

Link to Code

File: Ethos-Core/contracts/StabilityPool.sol 526: assert(_debtToOffset <= _totalLUSDDeposits); 551: assert(_LUSDLossPerUnitStaked <= DECIMAL_PRECISION); 591: assert(newP > 0);

Link to Code

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));

Link to Code

#0 - c4-judge

2023-03-09T18:26:58Z

trust1995 marked the issue as grade-b

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