Platform: Code4rena
Start Date: 31/03/2022
Pot Size: $75,000 USDC
Total HM: 7
Participants: 42
Period: 7 days
Judge: Jack the Pug
Total Solo HM: 5
Id: 102
League: ETH
Rank: 11/42
Findings: 2
Award: $357.53
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: rayn
Also found by: 0xDjango, 0xkatana, 0xkowloon, BouSalman, CertoraInc, Dravee, Funen, Hawkeye, IllIllI, Jujic, Kenshin, Kthere, Meta0xNull, Sleepy, TerrierLover, async, aysha, berndartmueller, catchup, cccz, cmichel, csanuragjain, danb, defsec, georgypetrov, hake, hubble, kenta, kyliek, pauliax, rfa, robee, sahar, shenwilly, teryanarmen
130.3737 USDC - $130.37
_setupRole
function usedThe _setupRole function is deprecated according to the Open Zeppelin comment
NOTE: This function is deprecated in favor of {_grantRole}
Use the recommended _grantRole function instead.
The _setupRole function, which is deprecated, is found in one place https://github.com/code-423n4/2022-03-volt/blob/main/contracts/core/Permissions.sol#L212
This Open Zeppelin comment indicates it is deprecated https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/AccessControl.sol#L195
Manual analysis
Replace the _setupRole function with _grantRole from the same Open Zeppelin library
The approve function is called for an ERC20 without checking the return value. Checking the return value would help confirm the approve was successful, but it is better to use safeIncreaseAllowance or safeDecreaseAllowance. This suggestion is mentioned in this Open Zeppelin comment https://github.com/OpenZeppelin/openzeppelin-contracts/blob/742e85be7c08dff21410ba4aa9c60f6a033befb8/contracts/token/ERC20/utils/SafeERC20.sol#L38-L44
The unsafe approve is used in ERC20CompoundPCVDeposit https://github.com/code-423n4/2022-03-volt/blob/main/contracts/pcv/compound/ERC20CompoundPCVDeposit.sol#L31
Manual analysis
Replace the unsafe approve call with safeIncreaseAllowance or safeDecreaseAllowance
The revokeOverride function acts like a backdoor to give the Guardian role the same revoke privileges as a Governor role, with the exception of preventing a guardian revoke. It would be better to create a new modifier for the relevant functions named 'onlyGovernorOrGuardian' to clarify the actual access controls, because the onlyGovernor modifier does not accurately reflect the access control of the revoke functions.
The revokeOverride gives guardian users a backdoor to functions with the onlyGovernor modifier https://github.com/code-423n4/2022-03-volt/blob/main/contracts/core/Permissions.sol#L127
Access controls should not be broken in this manner to give one privilege level access to functions that are limited to another privilege level. With the current code, an address might be granted the Guardian role without the understanding that this allows that address to revoke the roles of other addresses. Instead, the permissions of the onlyGovernor functions that permit the Guardian role should be modified.
Manual analysis
Add a new modifier named 'onlyGovernorOrGuardian' that permits both Governor and Guardian users. Use this modifier on all relevant revoke functions. A similar modifier is already created in CoreRef. https://github.com/code-423n4/2022-03-volt/blob/main/contracts/refs/CoreRef.sol#L69
modifier onlyGovernorOrGuardian() { require( isGovernor(msg.sender) || isGuardian(msg.sender), "Permissions: Caller is not a governor or guardian" ); _; }
🌟 Selected for report: IllIllI
Also found by: 0v3rf10w, 0xNazgul, 0xkatana, 0xkowloon, CertoraInc, Dravee, Funen, Hawkeye, Jujic, Kenshin, Meta0xNull, Sleepy, TerrierLover, catchup, csanuragjain, defsec, georgypetrov, kenta, okkothejawa, rayn, rfa, robee, saian, samruna
227.1568 USDC - $227.16
Use calldata instead of memory for function parameters. Having function arguments use calldata instead of memory can save gas.
At least two cases exist of function arguments using memory instead of calldata https://github.com/code-423n4/2022-03-volt/blob/main/contracts/refs/OracleRef.sol#L84 https://github.com/code-423n4/2022-03-volt/blob/main/contracts/peg/NonCustodialPSM.sol#L456
Manual analysis
Change function arguments from memory to calldata
Marking a function as payable saves gas. Functions that have the onlyOwner modifier cannot be called by normal users and will not mistakenly receive ETH. These functions can be payable to save gas.
One function was found with the onlyOwner modifier that can be payable https://github.com/code-423n4/2022-03-volt/blob/main/contracts/oracle/OraclePassThrough.sol#L53
But all functions in Permissions.sol that have the onlyGovernor modifier or the onlyGuardian modifier can receive the same gas optimization
Manual analysis
Add payable to functions with access control for gas savings
Combining require statement conditions with && logic uses unnecessary gas. It is better to split up each part of the logical statement into a separate require statements
One instance of this issue was found https://github.com/code-423n4/2022-03-volt/blob/main/contracts/volt/Volt.sol#L91
Manual analysis
Use separate require statements instead of concatenating with && to save gas
Strings in solidity are handled in 32 byte chunks. A require string longer than 32 bytes uses more gas. Shortening these strings will save gas.
Several cases of this gas optimization were found. These are a few examples, but more may exist
Manual analysis
Shorten require strings
Solidity errors introduced in version 0.8.4 can save gas on revert conditions https://blog.soliditylang.org/2021/04/21/custom-errors/ https://twitter.com/PatrickAlphaC/status/1505197417884528640
Error messages are not used in the contract, so all require blocks could receive a gas optimization
Manual analysis
Replace require blocks with new solidity errors from solidity 0.8.4 described in https://blog.soliditylang.org/2021/04/21/custom-errors/
#0 - ElliotFriedman
2022-04-07T20:24:37Z