Juicebox V2 contest - ElKu's results

The decentralized fundraising and treasury protocol.

General Information

Platform: Code4rena

Start Date: 01/07/2022

Pot Size: $75,000 USDC

Total HM: 17

Participants: 105

Period: 7 days

Judge: Jack the Pug

Total Solo HM: 5

Id: 143

League: ETH

Juicebox

Findings Distribution

Researcher Performance

Rank: 97/105

Findings: 1

Award: $38.23

🌟 Selected for report: 0

🚀 Solo Findings: 0

1) In for loops ++i should be unchecked.

For arithmetic operations which are unlikely to overflow or underflow, you could put them inside an unchecked block. This is usually the case for increment of loop indices in for and while loops.

For example: for (uint256 _i = 0; i < _terminals.length; _i++) could be rewritten as:

// you can remove initializing to _i as well as its redundant. // the length of the array can be cached if the arrays are long, but if its just few elements then you will // end up using more gas than before. So I have left it to the sponsor’s judgement. for (uint256 _i; _i < _terminals.length; ) { //statements… unchecked { _i++; } }

There is a total of 13 instances of this issue found in 4 files.

  1. File : contracts\JBFundingCycleStore.sol:

    1. Lines 724: for (uint256 i = 0; i < _discountMultiple; i++)
  2. File : contracts\JBSplitsStore.sol:

    1. Lines 165: for (uint256 _i = 0; _i < _groupedSplitsLength; )
    2. Lines 204: for (uint256 _i = 0; _i < _currentSplits.length; _i++)
    3. Lines 211: for (uint256 _j = 0; _j < _splits.length; _j++)
    4. Lines 229: for (uint256 _i = 0; _i < _splits.length; _i++)
    5. Lines 304: for (uint256 _i = 0; _i < _splitCount; _i++)

    The above optimizations reduced the deployment cost from 862721 to 847308(15413 saved = 1.79% gas saving). The max execution cost of set function was reduced from 57527 to 57453(74 saved = 0.13%). The max execution cost of splitsOf function was reduced from 8679 to 8606(73 saved = 0.84%).

  3. File : contracts\JBOperatorStore.sol:

    1. Lines 85: for (uint256 _i = 0; _i < _permissionIndexes.length; _i++)
    2. Lines 135: for (uint256 _i = 0; _i < _operatorData.length; _i++)
    3. Lines 165: for (uint256 _i = 0; _i < _indexes.length; _i++)
  4. File : contracts\JBDirectory.sol:

    1. Lines 139: for (uint256 _i; _i < _terminalsOf[_projectId].length; _i++)
    2. Lines 167: for (uint256 _i; _i < _terminalsOf[_projectId].length; _i++)
    3. Lines 275: for (uint256 _i; _i < _terminals.length; _i++)
    4. Lines 276: for (uint256 _j = _i + 1; _j < _terminals.length; _j++)

    The above optimizations reduced the deployment cost from 1250080 to 1244680(5400 saved = 0.43% gas saving). The max execution cost of primaryTerminalOf function was reduced from 6046 to 5972(74 saved = 1.22%). The max execution cost of setTerminalsOf function was reduced from 78546 to 78254(292 saved = 0.37%).

2) Cache storage variables which are read more than once.

Storage read costs 100 gas while memory read costs only 3 gas. Instances where we can profit from this are:

  1. File : contracts\JBTokenStore.sol:
    1. unclaimedBalanceOf[_holder][_projectId] is already cached at line 330. So use that, instead of accessing the storage again. The above optimization reduced the max execution cost of burnFrom function from 6267 to 6002(265 saved = 4.23%).
    2. unclaimedBalanceOf[_holder][_projectId] is already cached at line 403. So use that, instead of accessing the storage again. The above optimization reduced the max execution cost of claimFor function from 51755 to 51490(265 saved = 0.51%).
    3. unclaimedBalanceOf[_holder][_projectId] at line 448 and line 452 is already cached at line 442. So use that, instead of accessing the storage again.
AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter