Open code423n4 opened 2 years ago
Duplicated of #62 at Reduce the size of error messages (Long revert Strings)
Duplicated of #76 at public functions not called by the contract should be declared external instead
Duplicated of #2 at For loop optimizaion
Duplicated of #29 at Split up require statements instead of &&
G01 Custom Errors
As your using a solidity version greater 0.8.4 you can replace revert strings with custom errors. This will save in deployment costs and runtime costs. I ran a test in remix comparing a revert string vs custom errors and found that replacing a single revert string with a custom error saved 12,404 gas in deployment cost and 86 gas on each function call.
There are 131 revert strings throughout the in scope files that can be replaced with custom errors:
G02 Long Revert Strings
If you opt not to use custom errors keeping revert strings <= 32 bytes in length will save gas. I ran a test in remix and found the savings for a single short revert string vs long string to be 9,377 gas in deployment cost and 18 gas on function call.
I recommend shortenning the following revert strings to <= 32 bytes in length: TimelockControllerEmergency.sol#L229-L230 TimelockControllerEmergency.sol#L243-L244 TimelockControllerEmergency.sol#L256 TimelockControllerEmergency.sol#L319-L320 TimelockControllerEmergency.sol#L334-L335 TimelockControllerEmergency.sol#L342 TimelockControllerEmergency.sol#L359 TimelockControllerEmergency.sol#L375
G03 Public Functions that can be External
The following functions are currently set to public but are not called anywhere in their contract and can be switched to external.
NestedFactory.sol#L114 OwnableProxyDelegation.sol#L50 OwnableProxyDelegation.sol#L56 OwnerProxy.sol#L16 TimelockControllerEmergency.sol#L199-L206 TimelockControllerEmergency.sol#L221-L228 TimelockControllerEmergency.sol#L255 TimelockControllerEmergency.sol#L274-L280 TimelockControllerEmergency.sol#L295-L299 TimelockControllerEmergency.sol#L312-L318
G04 For Loop Optimisations
When incrementing i in for loops there is no chance of overflow so unchecked can be used to save gas. I ran a simple test in remix and found deployment savings of 31,653 gas and on each function call saved ~141 gas per iteration.
In for loops pre increments can also be used to save a small amount of gas per iteraition. I ran a test in remix using a for loop and found the deployment savings of 497 gas and ~5 gas per iteration.
Instances where unchecked and pre Increments can be implemented in for loops:
NestedFactory.sol#L124 NestedFactory.sol#L136 NestedFactory.sol#L196 NestedFactory.sol#L256 NestedFactory.sol#L315 NestedFactory.sol#L333 NestedFactory.sol#L369 NestedFactory.sol#L412 NestedFactory.sol#L651 OperatorResolver.sol#L40 OperatorResolver.sol#L60 OperatorResolver.sol#L75 MixinOperatorResolver.sol#L37 MixinOperatorResolver.sol#L56 BeefyVaultOperator.sol#L18 BeefyZapBiswapLPVaultOperator.sol#L27 BeefyZapUniswapLPVaultOperator.sol#L27 YearnCurveVaultOperator.sol#L42 CurveHelpers.sol#L22 CurveHelpers.sol#L42 CurveHelpers.sol#L62 CurveHelpers.sol#L86 TimelockControllerEmergency.sol#L84 TimelockControllerEmergency.sol#L89 TimelockControllerEmergency.sol#L234 TimelockControllerEmergency.sol#L324 OperatorScripts.sol#L67 OperatorScripts.sol#L80
G05 && in Require Functions
If optimising for running costs over deployment costs you can seperate && in require functions into 2 parts. I ran a basic test in remix and it cost an extra 234 gas to deploy but will save ~9 gas everytime the require function is called.
BeefyVaultOperator.sol#L54 BeefyZapBiswapLPVaultOperator.sol#L64-L65 BeefyZapUniswapLPVaultOperator.sol#L64-L65 ParaswapOperator.sol#L16