Platform: Code4rena
Start Date: 09/11/2021
Pot Size: $75,000 USDC
Total HM: 57
Participants: 27
Period: 7 days
Judge: alcueca
Total Solo HM: 49
Id: 52
League: ETH
Rank: 17/27
Findings: 2
Award: $454.67
🌟 Selected for report: 6
🚀 Solo Findings: 0
🌟 Selected for report: ye0lde
Also found by: Meta0xNull, defsec, pants, pauliax
21.2455 USDC - $21.25
pants
These files has open TODOs:
Open TODOs can hint at programming or architectural errors that still need to be fixed.
Manual code review.
Resolve these TODOs and bubble up the errors.
#0 - 0xstormtrooper
2021-11-16T05:47:42Z
#1 - alcueca
2021-12-10T14:21:56Z
Duplicate of #102
🌟 Selected for report: Reigada
Also found by: Meta0xNull, pants, pauliax
12.5116 USDC - $12.51
pants
You initialize the index variable of the for loop to 0 although it's already set to 0 when declared. appears at GovernorAlpha.sol line 571 and LinearVesting.sol line 72.
for (uint256 i = 0; i < _targets.length; i++) { ... }
Can be changed to (to save gas):
for (uint256 i; i < _targets.length; i++) { ... }
#0 - SamSteinGG
2021-11-20T06:48:46Z
Duplicate of #82
pants
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. https://github.com/code-423n4/2021-09-sushimiso-findings/issues/134
For example "BasePool::swap: Unfavourable Trade" can be changed to "BasePool swap Unfavourable Trade". (BasePool.sol line 324)
#0 - SamSteinGG
2021-11-20T06:46:29Z
Duplicate of #104
🌟 Selected for report: pants
68.651 USDC - $68.65
pants
You can cache the array length to save length access gas cost at every iteration. The following (bad) form appears at GovernorAlpha.sol line 571 and LinearVesting.sol line 72. GovernorAlpha.sol example:
for (uint256 i = 0; i < _targets.length; i++) { if (_targets[i] == address(this)) { revert( "GovernorAlpha::veto: council cannot veto on proposal having action with address(this) as target" ); } }
Change it to:
uint256 len = _targets.length; for (uint256 i = 0; i < len; i++) { if (_targets[i] == address(this)) { revert( "GovernorAlpha::veto: council cannot veto on proposal having action with address(this) as target" ); } }
🌟 Selected for report: pants
pants
These functions use postfix increaments (i++
) instead of uncheked postfix increaments (unchecked{i++}
):
For example GovernorAlpha.sol line 571 and LinearVesting.sol line 72.
The index is uint256 therefore cannot overflow (gas limit).
#0 - SamSteinGG
2021-11-20T06:52:17Z
Duplicate of #81
#1 - alcueca
2021-12-10T14:49:33Z
Not a duplicate, different solution.
🌟 Selected for report: pants
68.651 USDC - $68.65
pants
These functions use postfix increaments (x++
) instead of prefix increaments (++x
):
For example GovernorAlpha.sol line 571 and LinearVesting.sol line 72.
Prefix increaments are cheaper than postfix increaments.
Manual code review.
Change all postfix increaments to prefix increaments where it doesn't affects the functionality.
🌟 Selected for report: pants
68.651 USDC - $68.65
pants
These public
functions are never called by their contract (a very partial list):
Therefore, their visibility can be reduced to external
.
external
functions are cheaper than public
functions.
https://gus-tavo-guim.medium.com/public-vs-external-functions-in-solidity-b46bcf0ba3ac
Manual code review.
Define these functions as external
.
🌟 Selected for report: pants
68.651 USDC - $68.65
pants
unessesary safe math in UniSwapV2Pair.sol line 120.
if (rootK > rootKLast) { uint256 numerator = totalSupply * (rootK - rootKLast); uint256 denominator = (rootK * 5) + rootKLast; uint256 liquidity = numerator / denominator; if (liquidity > 0) _mint(feeTo, liquidity); }
Here rootK - rootKLast could be calculated with unchecked. As mentioned in the main git page, UniSwapV2Pair.sol is a part of the contest.
if (rootK > rootKLast) { uint256 numerator = totalSupply * (unchecked{rootK - rootKLast}); uint256 denominator = (rootK * 5) + rootKLast; uint256 liquidity = numerator / denominator; if (liquidity > 0) _mint(feeTo, liquidity); }
🌟 Selected for report: pants
68.651 USDC - $68.65
pants
use calldata instead of memory when possible to save GAS
For example in LinearVesting.sol the following function (constructor) could be changed to:
constructor( IERC20 _vader, address[] memory vesters, uint192[] memory amounts ) { require( _vader != IERC20(_ZERO_ADDRESS) && vesters.length == amounts.length, "LinearVesting::constructor: Misconfiguration" ); vader = _vader; uint256 total; for (uint256 i = 0; i < vesters.length; i++) { require( amounts[i] != 0, "LinearVesting::constructor: Incorrect Amount Specified" ); vest[vesters[i]].amount = amounts[i]; total = total + amounts[i]; } require( total == _TEAM_ALLOCATION, "LinearVesting::constructor: Invalid Vest Amounts Specified" ); transferOwnership(address(_vader)); }
could be changed to:
constructor( IERC20 _vader, address[] calldata vesters, uint192[] calldata amounts ) { require( _vader != IERC20(_ZERO_ADDRESS) && vesters.length == amounts.length, "LinearVesting::constructor: Misconfiguration" ); vader = _vader; uint256 total; for (uint256 i = 0; i < vesters.length; i++) { require( amounts[i] != 0, "LinearVesting::constructor: Incorrect Amount Specified" ); vest[vesters[i]].amount = amounts[i]; total = total + amounts[i]; } require( total == _TEAM_ALLOCATION, "LinearVesting::constructor: Invalid Vest Amounts Specified" ); transferOwnership(address(_vader)); }