Platform: Code4rena
Start Date: 16/11/2021
Pot Size: $30,000 USDC
Total HM: 3
Participants: 18
Period: 3 days
Judge: leastwood
Total Solo HM: 2
Id: 56
League: ETH
Rank: 4/18
Findings: 2
Award: $2,367.26
🌟 Selected for report: 5
🚀 Solo Findings: 0
🌟 Selected for report: pauliax
751.5154 USDC - $751.52
pauliax
_setupRole is used in function setSentinel. This is not a recommended approach. See the warning: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.1.0/contracts/access/AccessControl.sol#L183-L189
OZ suggests using _grantRole when you need to assign roles not from the constructor.
#0 - Xuefeng-Zhu
2021-11-23T07:43:56Z
_grantRole
is private
#1 - 0xleastwood
2021-12-21T03:59:04Z
This is a best security practice. Incorrectly using OpenZeppelin's AccessControl library may lead to unintended consequences as the admin
account can call setSentinel
multiple times.
🌟 Selected for report: pauliax
751.5154 USDC - $751.52
pauliax
Please note that function setSentinel does not actually remove an existing sentinel but adds a new address with this role. I am not sure if this is intended behavior and you are aware of this, but the function name is a bit misleading in my opinion, so submitting this FYI. Anyway, roles can be managed directly if necessary (grantRole/revokeRole).
#0 - Xuefeng-Zhu
2021-11-23T07:42:20Z
AccessControl.sol provides function to revoke role
#1 - 0xleastwood
2021-12-21T04:02:16Z
I don't think the sponsor is understanding the issue. There seems to be a mismatch with the naming of setSentinel
and the actual behaviour. Multiple sentinel accounts can be given access to the SENTINEL_ROLE
. I fully understand if the sponsor is aware and has acknowledged the issue, but for judging purposes, I will leave this as is.
#2 - Xuefeng-Zhu
2022-01-31T04:40:11Z
I am going to remove setSentinel function, since it can be managed by AccessControl directly
🌟 Selected for report: pmerkleplant
Also found by: pauliax
pauliax
Either the comment is misleading or the code is incorrect, as it says about the admin role but checks against sentinel:
/// This function reverts if the caller does not have the admin role. function pauseAlchemist(address _toPause, bool _state) external onlySentinel /// This function reverts if the caller does not have the admin role. function setBlacklist(address _toBlacklist) external onlySentinel
Also, it is strange to see that the admin can setWhitelist, but sentinel can setBlacklist.
Make the codebase and comments coherent.
#0 - Xuefeng-Zhu
2021-12-09T06:13:24Z
pauliax
function setBorrowFee emits HarvestFeeUpdated event. This event based on its name is for harvest fee and is also emitted in setHarvestFee. Because it has only one parameter of uint, there is no way for an external agent that fetches these events to know which fee was updated by just looking at the event.
Consider introducing a separate event for the borrow fee.
#0 - Xuefeng-Zhu
2021-12-09T06:10:25Z
🌟 Selected for report: pauliax
47.3259 USDC - $47.33
pauliax
Expressions can be extracted to constants as they do not change and do not need to be recalculated again and again:
10**decimals uint256(-1)
#0 - 0xleastwood
2021-12-21T05:56:37Z
Agree with warden, this is a valid way to save gas.
🌟 Selected for report: pauliax
47.3259 USDC - $47.33
pauliax
Assigned operations to constant variables are re-evalueted every time.
bytes32 public constant ADMIN_ROLE = keccak256('ADMIN'); bytes32 public constant SENTINEL_ROLE = keccak256('SENTINEL');
See https://github.com/ethereum/solidity/issues/9232
Change from 'constant' to 'immutable'.
#0 - Xuefeng-Zhu
2021-11-23T07:46:07Z
change to immutable will result in compile error
#1 - 0xleastwood
2021-12-21T05:58:43Z
Marking this as a valid finding.
#2 - 0xleastwood
2021-12-21T06:00:56Z
Tested this in remix, doesn't seem to cause compiler errors.
338.1819 USDC - $338.18
pauliax
function deposit in vault adapters does not have any auth checks, thus anyone can call it directly on the strategy. This deposits tokens to the vault but will not issue the corresponding shares. Thus, by depositing directly these tokens will basically be sacrificed to the existing owners of shares. It is a very unlikely scenario in practice as it requires 2 steps:
deposit onlyAdmin
21.2967 USDC - $21.30
pauliax
Shortening revert strings to fit in 32 bytes will decrease deployment time gas and will decrease runtime gas when the revert condition has been met. An example of an error message that could be shortened:
'Alchemist: not an emergency, not governance, and user does not have permission to recall funds from active vault'
#0 - Xuefeng-Zhu
2021-12-09T08:43:05Z
pauliax
'immutable' greatly reduces gas costs. There are variables that do not change so they can be marked as immutable to greatly improve the gas costs. Examples of such variables are: vault and admin in YaxisVaultAdapter. vault admin, and decimals in YearnVaultAdapter.
#0 - Xuefeng-Zhu
2021-11-23T07:47:25Z
change to immutable will result in compile error
#1 - Xuefeng-Zhu
2021-12-09T06:45:41Z
pauliax
Consider removing unused code to save some gas. Examples are:
address public _linkGasOracle; function _expectCaller
#0 - Xuefeng-Zhu
2021-12-09T06:53:49Z