Juicebox V2 contest - Tutturu'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: 90/105

Findings: 1

Award: $38.24

🌟 Selected for report: 0

🚀 Solo Findings: 0

1. Restructure the if/if else/else flow into if() {if else} to avoid an unnecessary assignment to zero

The current flow assigns _claimedTokensToBurn to 0 when _claimedBalance == 0, since _claimedTokensToBurn is already 0 by default this can be avoided, saving about 10 gas on average.

There is 1 instance of this issue

Current implementation:

if (_claimedBalance == 0) _claimedTokensToBurn = 0; else if (_preferClaimedTokens) _claimedTokensToBurn = _claimedBalance < _amount ? _claimedBalance : _amount; else _claimedTokensToBurn = _unclaimedBalance < _amount ? _amount - _unclaimedBalance : 0;

Proposed change:

if (_claimedBalance != 0) { if (_preferClaimedTokens) _claimedTokensToBurn = _claimedBalance < _amount ? _claimedBalance : _amount; else _claimedTokensToBurn = _unclaimedBalance < _amount ? _amount - _unclaimedBalance : 0; }

Both implementations should be functionally identical but the proposed change is very slightly cheaper and improves readability.

JBTokenStore.sol#L344-350

2. Use variables cached in memory instead of reading from storage multiple times

This saves about 100 gas per warm storage read.

There are 3 instances of this issue in JBTokenStore.sol:

  1. Value stored in memory at line 330 can replace storage read at line 359
  2. Value stored in memory at line 403 can replace storage read at line 409
  3. Value stored in memory at line 442 can replace storage read at line 448

There is 1 instances of this issue in JBSingleTokenPaymentTerminalStore.sol:

  1. Value balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] can be stored in memory to avoid 1 storage read. Affected lines: L589 and L599

3. Caching array length in memory

Caching the length in memory instead of reading from storage on each iteration of the loop saves about 100 gas per iteration due to avoiding a warm storage read.

There is 1 instance of this issue in JBDirectory.sol on line 139

Current implementation:

for (uint256 _i; _i < _terminalsLength; _i++) {

Proposed implementation:

uint256 _terminalsLength = _terminalsOf[_projectId].length; for (uint256 _i; _i < _terminalsLength; _i++) {

4. Replace i++ with unchecked ++i to reduce gas cost

Using unchecked when incrementing a value that can't realistically underflow or overflow reduces gas cost. Since _discountMultiple cannot realistically overflow, this should be safe to do.

There is 1 instance of this issue in JBFundingCycleStore.sol on line 724-734

Current implementation:

for (uint256 i = 0; i < _discountMultiple; i++) { weight = PRBMath.mulDiv( weight, JBConstants.MAX_DISCOUNT_RATE - _baseFundingCycle.discountRate, JBConstants.MAX_DISCOUNT_RATE ); if (weight == 0) break; }

Proposed implementation:

for (uint256 i = 0; i < _discountMultiple;) { weight = PRBMath.mulDiv( weight, JBConstants.MAX_DISCOUNT_RATE - _baseFundingCycle.discountRate, JBConstants.MAX_DISCOUNT_RATE ); if (weight == 0) break; unchecked { ++i; } }
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