Platform: Code4rena
Start Date: 20/01/2022
Pot Size: $80,000 USDC
Total HM: 5
Participants: 37
Period: 7 days
Judge: Jack the Pug
Total Solo HM: 1
Id: 76
League: ETH
Rank: 23/37
Findings: 2
Award: $106.37
🌟 Selected for report: 1
🚀 Solo Findings: 0
11.8662 USDC - $11.87
bobi
unchecked
: Using the unchecked
keyword to avoid redundant arithmetic underflow/overflow checks to save gas when an underflow/overflow cannot happen.
As an example, on can add unchecked
on a for
loop's iterator( from contracts/managers/Manager.sol:46
) as so:
for (uint256 i; i < _extraTokens.length; i++) { ... }
Into a more efficient:
for (uint256 i = 0; i < _extraTokens.length; unchecked{++i}) { ... }
Since the uint256's max cannot be reached, it is safe to use.
#0 - jack-the-pug
2022-03-15T01:06:26Z
Dup #253
bobi
.length
is called on each for
indexing, causing extra gas to be used
storage > memory >= calldata reads > local variable reads.
For example, in the SherBuy.sol
you have:
for (uint256 i; i < _tokens.length; i++) { IERC20 token = _tokens[I]; ...
On each iteration, the .length
will be called; to fix this, you could cache it in a local variable as so: (this applies wherever in the codebase possible)
uint256 _length = _tokens.length; for (uint256 i; i < _length; i++) { IERC20 token = _tokens[I]; ...
Manual analysis.
Cache the .length
of the arrays.
#0 - jack-the-pug
2022-03-26T07:07:54Z
Dup #231
bobi
There are some function calls that can be done after subsequent checks in order to avoid unnecessary calls, save gas, and keep a consistent coding style.
For example, this part of AaveV2Strategy.sol
:
function withdrawAll() external override onlySherlockCore returns (uint256) { ILendingPool lp = getLp(); if (balanceOf() == 0) { return 0; } ...
The internal call of getLp()
can be called after the if()
check. This pattern appears on:
https://github.com/code-423n4/2022-01-sherlock/blob/main/contracts/Sherlock.sol#L657-L668
https://github.com/code-423n4/2022-01-sherlock/blob/main/contracts/Sherlock.sol#L408-L417
Use a similar pattern(check - first, call - after) to the one at: https://github.com/code-423n4/2022-01-sherlock/blob/main/contracts/managers/AaveV2Strategy.sol#L92-L96
function withdraw(uint256 _amount) external override onlySherlockCore { // Why do we only check if _amount is equal to the max value? if (_amount == type(uint256).max) revert InvalidArgument(); ILendingPool lp = getLp();