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
Rank: 142/154
Findings: 1
Award: $42.07
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: c3phas
Also found by: 0x3b, 0x6980, 0x73696d616f, 0xSmartContract, 0xackermann, 0xhacksmithh, 0xsomeone, Bnke0x0, Bough, Budaghyan, Darshan, DeFiHackLabs, Deivitto, GalloDaSballo, JCN, LethL, Madalad, MiniGlome, Morraez, P-384, PaludoX0, Phantasmagoria, Praise, RHaO-sec, Rageur, RaymondFam, ReyAdmirado, Rickard, Rolezn, SaeedAlipoor01988, Saintcode_, Sathish9098, TheSavageTeddy, Tomio, Viktor_Cortess, abiih, arialblack14, atharvasama, banky, codeislight, cryptonue, ddimitrov22, dec3ntraliz3d, descharre, dharma09, emmac002, favelanky, hl_, hunter_w3b, kaden, kodyvim, matrix_0wl, oyc_109, pavankv, scokaf, seeu, yamapyblack
42.0697 USDC - $42.07
Constants should be used for literal values written into the code, and immutable variables should be used for expressions, or values calculated in, or passed into the constructor.
https://github.com/code-423n4/2023-02-ethos/blob/d46ede81e35c1ed86242c9ba3c5c57d2ca2b57d8/Ethos-Vault/contracts/abstract/ReaperBaseStrategyv4.sol#L49 bytes32 public constant KEEPER = keccak256("KEEPER"); bytes32 public constant STRATEGIST = keccak256("STRATEGIST"); bytes32 public constant GUARDIAN = keccak256("GUARDIAN"); bytes32 public constant ADMIN = keccak256("ADMIN");
https://github.com/code-423n4/2023-02-ethos/blob/d46ede81e35c1ed86242c9ba3c5c57d2ca2b57d8/Ethos-Vault/contracts/ReaperVaultV2.sol#L73 bytes32 public constant DEPOSITOR = keccak256("DEPOSITOR"); bytes32 public constant STRATEGIST = keccak256("STRATEGIST"); bytes32 public constant GUARDIAN = keccak256("GUARDIAN"); bytes32 public constant ADMIN = keccak256("ADMIN");
Use a Solidity version of at least 0.8.12 to get string.concat() to be used instead of abi.encodePacked(<str>,<str>). https://github.com/code-423n4/2023-02-ethos/blob/d46ede81e35c1ed86242c9ba3c5c57d2ca2b57d8/Ethos-Core/contracts/HintHelpers.sol#L178
E.g.: totalAllocBPS += _allocBPS; https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L168 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L194 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L196 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L214
stratParams.allocBPS -= bpsChange; https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L444
stratParams.losses += loss; stratParams.allocated -= loss; https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L450
totalAllocated -= loss; https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L452
Each extra memory word of bytes past the original 32 incurs an MSTORE which costs 3 gas
"Ammount" appears to be misspelt which if corrected to "Amount" will bring the require string back down to 32 bytes and save gas: require(_amount <= balanceOf(), "Ammount must be less than balance"); https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/abstract/ReaperBaseStrategyv4.sol#L98
Require string "Upgrade cooldown not initiated or still ongoing" is 47 bytes https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/abstract/ReaperBaseStrategyv4.sol#L191
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L150 "Cannot add strategy during emergency shutdown" is 45 bytes
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L321 "Cannot deposit during emergency shutdown" is 40 bytes
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L436 "Strategy loss cannot be greater than allocation" is 47 bytes
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L619 "Degradation cannot be more than 100%" is 36 bytes
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/LUSDToken.sol#L136 "LUSD: Caller is not guardian or governance" is 42 bytes
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/LUSDToken.sol#L350 "LUSD: Cannot transfer tokens directly to the LUSD token contract or the zero address" is 84 bytes https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/LUSDToken.sol#L356 "LUSD: Cannot transfer tokens directly to the StabilityPool, TroveManager or BorrowerOps" is 87 bytes https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/LUSDToken.sol#L371 "LUSD: Caller is neither BorrowerOperations nor TroveManager nor StabilityPool" is 77 bytes
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/StabilityPool.sol#L865 "StabilityPool: Cannot withdraw while there are troves with ICR < MCR" is 68 bytes
Saves 6 gas per instance: https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol#L167 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L151 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L629 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/LUSDToken.sol#L312 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/LUSDToken.sol#L321 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/LUSDToken.sol#L329 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/LUSDToken.sol#L337 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/LUSDToken.sol#L348
Not inlining costs 20 to 40 gas because of two extra JUMP instructions and additional stack operations needed for function calls.
https://github.com/code-423n4/2023-02-ethos/blob/d46ede81e35c1ed86242c9ba3c5c57d2ca2b57d8/Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol#L86 function _liquidatePosition(uint256 _amountNeeded) internal override returns (uint256 liquidatedAmount, uint256 loss) {
Saves 5 gas per loop
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/LQTY/LQTYStaking.sol#L206 line 206: for (uint i = 0; i < assets.length; i++) {
line 228: for (uint i = 0; i < collaterals.length; i++) {
line 240: for (uint i = 0; i < numCollaterals; i++) {
https://github.com/code-423n4/2023-02-ethos/blob/d46ede81e35c1ed86242c9ba3c5c57d2ca2b57d8/Ethos-Core/contracts/ActivePool.sol line 108: for(uint256 i = 0; i < numCollaterals; i++) {
https://github.com/code-423n4/2023-02-ethos/blob/d46ede81e35c1ed86242c9ba3c5c57d2ca2b57d8/Ethos-Core/contracts/TroveManager.sol line 608: for (vars.i = 0; vars.i < _n && vars.user != firstUser; vars.i++) {
line 882: for (vars.i = 0; vars.i < _troveArray.length; vars.i++) {
line 808: for (vars.i = 0; vars.i < _troveArray.length; vars.i++) {
In addition to the above unchecked block could also be used to increment i to further save gas e.g.: unchecked { ++i; }
Or the following could also be used, as used in /Ethos-Vault/contracts/ReaperVaultV2.sol#L128: i = i.uncheckedInc() https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L128
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
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/LQTY/LQTYStaking.sol line 206: for (uint i = 0; i < assets.length; i++) { line 228: for (uint i = 0; i < collaterals.length; i++) {
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol line 882: for (vars.i = 0; vars.i < _troveArray.length; vars.i++) { line 808: for (vars.i = 0; vars.i < _troveArray.length; vars.i++) {
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.
/Ethos-Vault/contracts/abstract/ReaperBaseStrategyv4.sol uint256 public constant PERCENT_DIVISOR = 10_000; uint256 public constant UPGRADE_TIMELOCK = 48 hours; // minimum 48 hours for RF uint256 public constant FUTURE_NEXT_PROPOSAL_TIME = 365 days * 100; https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/abstract/ReaperBaseStrategyv4.sol#L23
Use string for arbitrary-length string (UTF-8) data that's longer than 32 bytes, else use bytes. As a rule of thumb, use bytes for arbitrary-length raw byte data and string for arbitrary-length string (UTF-8) data. If you can limit the length to a certain number of bytes, always use one of bytes1 to bytes32 because they are much cheaper.
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/LQTY/LQTYStaking.sol#L23 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/LUSDToken.sol#L32-L34 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/LQTY/CommunityIssuance.sol#L19 https://github.com/code-423n4/2023-02-ethos/blob/d46ede81e35c1ed86242c9ba3c5c57d2ca2b57d8/Ethos-Core/contracts/Proxy/StabilityPoolScript.sol#L10 https://github.com/code-423n4/2023-02-ethos/blob/d46ede81e35c1ed86242c9ba3c5c57d2ca2b57d8/Ethos-Core/contracts/Proxy/TroveManagerScript.sol#L10 https://github.com/code-423n4/2023-02-ethos/blob/d46ede81e35c1ed86242c9ba3c5c57d2ca2b57d8/Ethos-Core/contracts/Proxy/TokenScript.sol#L10 https://github.com/code-423n4/2023-02-ethos/blob/d46ede81e35c1ed86242c9ba3c5c57d2ca2b57d8/Ethos-Core/contracts/Proxy/BorrowerWrappersScript.sol#L25 https://github.com/code-423n4/2023-02-ethos/blob/d46ede81e35c1ed86242c9ba3c5c57d2ca2b57d8/Ethos-Core/contracts/CollSurplusPool.sol#L17 https://github.com/code-423n4/2023-02-ethos/blob/d46ede81e35c1ed86242c9ba3c5c57d2ca2b57d8/Ethos-Core/contracts/DefaultPool.sol#L25 https://github.com/code-423n4/2023-02-ethos/blob/d46ede81e35c1ed86242c9ba3c5c57d2ca2b57d8/Ethos-Core/contracts/PriceFeed.sol#L27 https://github.com/code-423n4/2023-02-ethos/blob/d46ede81e35c1ed86242c9ba3c5c57d2ca2b57d8/Ethos-Core/contracts/HintHelpers.sol#L13 https://github.com/code-423n4/2023-02-ethos/blob/d46ede81e35c1ed86242c9ba3c5c57d2ca2b57d8/Ethos-Core/contracts/ActivePool.sol#L30 https://github.com/code-423n4/2023-02-ethos/blob/d46ede81e35c1ed86242c9ba3c5c57d2ca2b57d8/Ethos-Core/contracts/SortedTroves.sol#L49 https://github.com/code-423n4/2023-02-ethos/blob/d46ede81e35c1ed86242c9ba3c5c57d2ca2b57d8/Ethos-Core/contracts/BorrowerOperations.sol#L21
#0 - c4-judge
2023-03-09T18:29:08Z
trust1995 marked the issue as grade-b