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: 124/154
Findings: 1
Award: $61.26
π Selected for report: 0
π Solo Findings: 0
π Selected for report: GalloDaSballo
Also found by: 0x3b, 0xAgro, 0xSmartContract, 0xTheC0der, 0xackermann, 0xnev, 0xsomeone, ABA, BRONZEDISC, Bjorn_bug, Bnke0x0, Breeje, Co0nan, CodeFoxInc, CodingNameKiki, DadeKuma, DeFiHackLabs, IceBear, Josiah, Kaysoft, Lavishq, MohammedRizwan, PaludoX0, PawelK, Phantasmagoria, Raiders, RaymondFam, Rickard, Rolezn, Sathish9098, SleepingBugs, SuperRayss, UdarTeam, Udsen, Viktor_Cortess, arialblack14, ast3ros, bin2chen, brgltd, btk, catellatech, ch0bu, chaduke, chrisdior4, codeislight, cryptonue, delfin454000, descharre, dontonka, emmac002, fs0c, hacker-dom, hansfriese, imare, lukris02, luxartvinsec, martin, matrix_0wl, peanuts, rbserver, shark, tnevler, trustindistrust, tsvetanovv, vagrant, yongskiws, zzzitron
61.2601 USDC - $61.26
Contracts should be deployed with the same compiler version and flags that they have been tested with thoroughly. Locking the pragma helps to ensure that contracts do not accidentally get deployed using, for example, an outdated compiler version that might introduce bugs that affect the contract system negatively.
pragma solidity ^0.8.0;
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L3 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol#L3 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultERC4626.sol#L3 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/abstract/ReaperBaseStrategyv4.sol#L3
Can import the required specific contracts, functions or variables by using the named imports explicitly. Plain imports will import the entire context of the imported contract which could lead into variable name conflicts etc ...
Currently the ReaperAccessControl
is imported as follows:
import "./mixins/ReaperAccessControl.sol";
But it can be imported explicitly by the name as follows:
import {ReaperAccessControl} from "./mixins/ReaperAccessControl.sol";
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L5-L14 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol#L5-L14 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultERC4626.sol#L5-L6 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/abstract/ReaperBaseStrategyv4.sol#L5-L12 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/CollateralConfig.sol#L5-L8
There are 15 more instances of this issue:
10**
TO DEPICT NUMBERS FOR BETTER READABILITY OF THE CODE.uint256 public constant PERCENT_DIVISOR = 10000;
Above line of code can be rewritten as follows for better code readability.
uint256 public constant PERCENT_DIVISOR = 10**4;
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L41
address(0)
CHECKSZero-address check should be used in the constructors, to avoid the risk of setting protocol critical parameters as address(0) at contract deployment time.
token = IERC20Metadata(_token);
above line of code should be preceded by the address(0)
check as follows:
require(_token != address(0), "_token can not be zero address"); token = IERC20Metadata(_token);
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L120 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L124
For the use of off-chain tools it is recommended to emit both old and new values when critical parameters are updated in the protocol.
function updateStrategyFeeBPS(address _strategy, uint256 _feeBPS) external { _atLeastRole(ADMIN); require(strategies[_strategy].activation != 0, "Invalid strategy address"); require(_feeBPS <= PERCENT_DIVISOR / 5, "Fee cannot be higher than 20 BPS"); strategies[_strategy].feeBPS = _feeBPS; emit StrategyFeeBPSUpdated(_strategy, _feeBPS); }
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L178-L184 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L198 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L216 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L270 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L570 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L581 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L621
address(0)
CHECKS FOR THE PROTOCOL CRITICAL ADDRESSES_mint(_receiver, shares);
In the above example _mint()
is used to mint shares to the _reciever
address. Hence _reciever
address should be checked for address(0) as follows (before the _mint
function is called):
require(_reciever != address(0), "Receiver can not be zero address");
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L336 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol#L70
events
FOR PROTOCOL CRITICAL PARAMETER CHANGESEvents should be emitted appropriately for protocol critical parameter changes to be used by off-chain tools.
function updateTreasury(address newTreasury) external { _atLeastRole(DEFAULT_ADMIN_ROLE); require(newTreasury != address(0), "Invalid address"); treasury = newTreasury; }
If the underlying token of the vault is a proxied token with multiple addresses, then the Admin
can drain the vault assets by bypassing the following require
statement and transfering the entire contract balance to admin himself.
require(_token != address(token), "!token"); uint256 amount = IERC20Metadata(_token).balanceOf(address(this)); IERC20Metadata(_token).safeTransfer(msg.sender, amount); emit InCaseTokensGetStuckCalled(_token, amount);
initialize()
FUNCTIONS SHOULD BE USING ACCESS CONTROLInitialize()
function should be secured by access control to prevent front running the initialize()
function by an attacker.
In the worst case if the initialize()
function is not secured by access control, it could prompt redeployment of the contract as well.
function initialize( address _vault, address[] memory _strategists, address[] memory _multisigRoles, IAToken _gWant ) public initializer { gWant = _gWant; want = _gWant.UNDERLYING_ASSET_ADDRESS(); __ReaperBaseStrategy_init(_vault, want, _strategists, _multisigRoles); rewardClaimingTokens = [address(_gWant)]; }
Only let permissioned users to initialize the ReaperStrategyGranarySupplyOnly
contract by calling the initialize()
function.
Old version of solidity is used (^0.8.0 and 0.6.11), but newer version 0.8.17 can be used.
For security, it is recommended to use the latest solidity version. security fix list for different solidity versions can be found in the following link.
https://github.com/ethereum/solidity/blob/develop/Changelog.md
Above issue is found in all contracts.
According to the package.json file, the project is using 4.7.0, to be exact ^4.7.3 which is not the latest updated version.
"dependencies": { "@openzeppelin/contracts": "^4.7.3",
It is recommended to use the latest non vulnerable version 4.8.0
NatSpec is missing for the following contracts, functions, constructor and modifier
ReaperBaseStrategyv4.sol
, ReaperVaultERC4626.sol
and ReaperStrategyGranarySupplyOnly.sol
are main contracts of the project. But NatSpec is missing in the code.
It is recommended to use the NatSpec for commenting for better readability and understanding of the code base.
want
IS AN ADDRESS AND NO NEED TO RECAST IT BACK INTO AN ADDRESSILendingPool(ADDRESSES_PROVIDER.getLendingPool()).withdraw(address(want), _withdrawAmount, address(this));
Above line of code can be rewritten as follows (by removing the address recast of want):
ILendingPool(ADDRESSES_PROVIDER.getLendingPool()).withdraw(want, _withdrawAmount, address(this));
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol#L200 https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol#L232
#0 - c4-judge
2023-03-08T13:15:56Z
trust1995 marked the issue as grade-b
#1 - c4-sponsor
2023-03-17T02:29:09Z
0xBebis marked the issue as sponsor confirmed