Juicebox contest - Saintcode_'s results

The decentralized fundraising and treasury protocol.

General Information

Platform: Code4rena

Start Date: 18/10/2022

Pot Size: $50,000 USDC

Total HM: 13

Participants: 67

Period: 5 days

Judge: Picodes

Total Solo HM: 7

Id: 172

League: ETH

Juicebox

Findings Distribution

Researcher Performance

Rank: 66/67

Findings: 1

Award: $25.96

Gas:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

25.9629 USDC - $25.96

Labels

bug
G (Gas Optimization)
grade-b
G-20

External Links

USE CALLDATA INSTEAD OF MEMORY

When a function with a memory array is called externally, the abi.decode() step has to use a for-loop to copy each index of the calldata to the memory index. Each iteration of this for-loop costs at least 60 gas (i.e. 60 * <mem_array>.length). Using calldata directly, obliviates the need for such a loop in the contract code and runtime execution.

When arguments are read-only on external functions, the data location should be calldata

16 Instances: -JB721GlobalGovernance.sol line 55 -JB721TieredGovernance.sol lines 147, 313 -JBTiered721Delegate.sol lines 205, 206, 208, 210, 211, 213, 264, 290, 386, 480, 598, 652. -JBTiered721DelegateDeployer.sol line 71

<ARRAY>.LENGTH SHOULD NOT BE LOOKED UP IN EVERY LOOP OF A FOR-LOOP

Reading array length at each iteration of the loop consumes more gas than necessary. In the best case scenario (length read on a memory variable), caching the array length in the stack saves around 3 gas per iteration. In the worst case scenario (external calls at each iteration), the amount of gas wasted can be massive.

Consider storing the array’s length in a variable before the for-loop, and use this new variable instead

3 Instances: -JBIpfsDecoder.sol lines 49, 76, 84

<X> += <Y> COSTS MORE GAS THAN <X> = <X> + <Y> FOR STATE VARIABLES

1 Instance: -JBTiered721DelegateStore.sol line 827

++I INSTEAD OF I++ (OR USE ASSEMBLY WHEN APPLICABLE)

Use ++i instead of i++. This is especially useful in for loops but this optimization can be used anywhere in your code.

4 Instances: -JBIpfsDecoder.sol lines 59, 68, 76, 84

IT COSTS MORE GAS TO INITIALIZE VARIABLES WITH THEIR DEFAULT VALUE THAN LETTING THE DEFAULT VALUE BE APPLIED

If a variable is not set/initialized, it is assumed to have the default value (0 for uint, false for bool, address(0) for address…). Explicitly initializing it with its default value is an anti-pattern and wastes gas.

As an example: for (uint256 i = 0; i < numIterations; ++i) { should be replaced with for (uint256 i; i < numIterations; ++i) {

6 Instances: -JBIpfsDecoder.sol lines 47, 49, 51, 68, 76, 84

>= COSTS LESS GAS THAN >

The compiler uses opcodes GT and ISZERO for solidity code that uses >, but only requires LT for >=, which saves 3 gas

5 Instances: -JBTiered721Delegate.sol lines 240, 551 -JBTiered721DelegateStore.sol line 1254 -JB721Delegate.sol line 116 -JBIpfsDecoder.sol line 57

++I/I++ SHOULD BE UNCHECKED{++I}/UNCHECKED{I++} WHEN IT IS NOT POSSIBLE FOR THEM TO OVERFLOW, AS IS THE CASE WHEN USED IN FOR- AND WHILE-LOOPS

The unchecked keyword is new in solidity version 0.8.0, so this only applies to that version or higher, which these instances are. This saves 30-40 gas per loop for (uint256 i = 0; i < orders.length; /** NOTE: Removed i++ **/ ) { // Do the thing // Unchecked pre-increment is cheapest unchecked { ++i; } }

5 Instances: -JBIpfsDecode.sol lines 49, 51, 68, 76, 84

#0 - c4-judge

2022-11-04T21:07:53Z

Picodes marked the issue as grade-b

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