Juicebox V2 contest - Ch_301'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: 45/105

Findings: 3

Award: $131.86

🌟 Selected for report: 0

🚀 Solo Findings: 0

Lines of code

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBERC20PaymentTerminal.sol#L87-L88 https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBETHERC20ProjectPayer.sol#L271 https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBETHERC20ProjectPayer.sol#L315 https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBETHERC20SplitsPayer.sol#L256 https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBETHERC20SplitsPayer.sol#L301 https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBETHERC20SplitsPayer.sol#L348 https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBETHERC20SplitsPayer.sol#L384 https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBETHERC20SplitsPayer.sol#L534

Vulnerability details

Details & Impact

The transferFrom() and transfer() method is used instead of safeTransferFrom() and safeTransfer()I however argue that this isn’t recommended because:

SafeERC20 is not an ERC20 extension that you use to make your token safe (OpenZeppelin’s ERC20 is already safe). It’s a helper to make safe the interaction with someone else’s ERC20 token, in your contracts.

You can read the full post here : https://forum.openzeppelin.com/t/safeerc20-tokentimelock-wrappers/396

Call the safeTransferFrom() and safeTransfer() method instead of transferFrom() and transfer() for assets transfers

#0 - mejango

2022-07-12T18:39:09Z

dup #281

Check Isn't Efficace

Description

allows malicious users to keep calling the _getStructFor () function, via calling the function queuedOf () with parameter _projectId = 0.

Findings

File: /jbx-protocol/juice-contracts-v2/blob/main/contracts/JBFundingCycleStore.sol 143: if (latestConfigurationOf[_projectId] == 0) return _getStructFor(0, 0);

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBFundingCycleStore.sol#L143

201: if (latestConfigurationOf[_projectId] == 0) return _getStructFor(0, 0); https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBFundingCycleStore.sol#L201

Recommended

error INVALID_PROJECTID(); if (latestConfigurationOf[_projectId] == 0) revert INVALID_PROJECTID();

Unnecessary Return

Description

The function tokenURI returns an empty URI If there's no resolver

Findings

/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBProjects.sol 71: if (tokenUriResolver == IJBTokenUriResolver(address(0))) return ' ';

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBProjects.sol#L71

Recommended

It is better to use assert() or require() to handle the empty value

assert(tokenUriResolver == IJBTokenUriResolver(address(0)));

Functions With Confused Names

Description

Functions called the same name function from openzeppelin

Findings

File: /jbx-protocol/juice-contracts-v2/blob/main/contracts/JBToken.sol 145: function approve

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBToken.sol#L145-L153

163: function transfer https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBToken.sol#L163-L171

182: function transferFrom https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBToken.sol#L182-L191

Missing Checks For Address(0x0) When Setting The New Controller

File: /jbx-protocol/juice-contracts-v2/blob/main/contracts/JBDirectory.sol 236: controllerOf[_projectId] = _controller;

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBDirectory.sol#L236

File: /jbx-protocol/juice-contracts-v2/blob/main/contracts/JBDirectory.sol 339: isAllowedToSetFirstController[_address] = _flag

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBDirectory.sol#L339

Optimal Comparison Operator

Description

When comparing uints, you can save gas costs by strategically picking the optimal operator. In this case, changing the operator >= to > will save more gas, The time is specified in milliseconds so the probability of parity is very low. which is unlikely

Findings

File: /jbx-protocol/juice-contracts-v2/blob/main/contracts/JBFundingCycleStore.sol 550: block.timestamp >= _fundingCycle.start

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBFundingCycleStore.sol#L550

589: block.timestamp >= _fundingCycle.start https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBFundingCycleStore.sol#L589

593: block.timestamp >= _fundingCycle.start https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBFundingCycleStore.sol#L593

602: if (_baseFundingCycle.duration > 0 && block.timestamp >= _baseFundingCycle.start + _baseFundingCycle.duration) return 0; https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBFundingCycleStore.sol#L602

815: else if (_ballotFundingCycle.ballot.duration() >= block.timestamp - _configuration) return JBBallotState.Active;

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBFundingCycleStore.sol#L815

Calldata Instead Of Memory For Ro Function Parameters

Description

If a reference type function parameter is read-only, it is cheaper in gas to use calldata instead of memory. Calldata is a non-modifiable, non-persistent area where function arguments are stored, and behaves mostly like memory.

It is better to use calldata as a data location because it will avoid copies and also makes sure that the data cannot be modified.

Findings

File: /jbx-protocol/juice-contracts-v2/blob/main/contracts/JBFundingCycleStore.sol #406: JBFundingCycle memory _baseFundingCycle

https://github.com//jbx-protocol/juice-contracts-v2/blob/main/contracts/JBFundingCycleStore.sol#L406

#624: JBFundingCycle memory _baseFundingCycle https://github.com//jbx-protocol/juice-contracts-v2/blob/main/contracts/JBFundingCycleStore.sol#L624

#698: JBFundingCycle memory _baseFundingCycle

https://github.com//jbx-protocol/juice-contracts-v2/blob/main/contracts/JBFundingCycleStore.sol#L698

#770: JBFundingCycle memory _fundingCycle

https://github.com//jbx-protocol/juice-contracts-v2/blob/main/contracts/JBFundingCycleStore.sol#L770

File: /jbx-protocol/juice-contracts-v2/blob/main/contracts/JBController.sol #841: string memory _memo

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBController.sol#L841

Recommended

Replace memory with calldata

Using Prefix Increments Save Gas

Description

Prefix increments are cheaper than postfix increments, eg ++i rather than i++

Findings

File: /jbx-protocol/juice-contracts-v2/blob/main/contracts/JBFundingCycleStore.sol 724: for (uint256 i = 0; i < _discountMultiple; i++) {

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBFundingCycleStore.sol#L724

File: /jbx-protocol/juice-contracts-v2/blob/main/contracts/JBSplitsStore.sol 204: for (uint256 _i = 0; _i < _currentSplits.length; _i++) {

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBSplitsStore.sol#L204

211: for (uint256 _j = 0; _j < _splits.length; _j++) { https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBSplitsStore.sol#L211

229: for (uint256 _i = 0; _i < _splits.length; _i++) { https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBSplitsStore.sol#L229

304: for (uint256 _i = 0; _i < _splitCount; _i++) { https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBSplitsStore.sol#L304

File: /jbx-protocol/juice-contracts-v2/blob/main/contracts/JBOperatorStore.sol 85: for (uint256 _i = 0; _i < _permissionIndexes.length; _i++) {

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBOperatorStore.sol#L85

135: for (uint256 _i = 0; _i < _operatorData.length; _i++) { https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBOperatorStore.sol#L135

165: for (uint256 _i = 0; _i < _indexes.length; _i++) { https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBOperatorStore.sol#L165

File: /jbx-protocol/juice-contracts-v2/blob/main/contracts/JBDirectory.sol 139: for (uint256 _i; _i < _terminalsOf[_projectId].length; _i++) {

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBDirectory.sol#L139

167: for (uint256 _i; _i < _terminalsOf[_projectId].length; _i++) https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBDirectory.sol#L167

275: for (uint256 _i; _i < _terminals.length; _i++) 276: for (uint256 _j = _i + 1; _j < _terminals.length; _j++)

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBDirectory.sol#L275-L276

File: /jbx-protocol/juice-contracts-v2/blob/main/contracts/JBController.sol 913: for (uint256 _i = 0; _i < _splits.length; _i++) {

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBController.sol#L913

1014: for (uint256 _i; _i < _fundAccessConstraints.length; _i++) { https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBController.sol#L1014

File: /jbx-protocol/juice-contracts-v2/blob/main/contracts/JBSingleTokenPaymentTerminalStore.sol 862: for (uint256 _i = 0; _i < _terminals.length; _i++)

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBSingleTokenPaymentTerminalStore.sol#L862

File: /jbx-protocol/juice-contracts-v2/blob/main/contracts/JBETHERC20SplitsPayer.sol 466: for (uint256 i = 0; i < _splits.length; i++) {

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBETHERC20SplitsPayer.sol#L466

<array>.length Should Not Be Looked Up In Every Loop Of A For-loop

description The code can be optimized by minimizing the number of SLOADs. SLOADs are expensive (100 gas) compared to MLOADs/MSTOREs (3 gas).

Findings

File: /jbx-protocol/juice-contracts-v2/blob/main/contracts/JBSplitsStore.sol 204: for (uint256 _i = 0; _i < _currentSplits.length; _i++) {

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBSplitsStore.sol#L204

211: for (uint256 _j = 0; _j < _splits.length; _j++) {

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBSplitsStore.sol#L211

229: for (uint256 _i = 0; _i < _splits.length; _i++) {

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBSplitsStore.sol#L229

File: /jbx-protocol/juice-contracts-v2/blob/main/contracts/JBOperatorStore.sol 85: for (uint256 _i = 0; _i < _permissionIndexes.length; _i++) {

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBOperatorStore.sol#L85

135: for (uint256 _i = 0; _i < _operatorData.length; _i++) { https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBOperatorStore.sol#L135

165: for (uint256 _i = 0; _i < _indexes.length; _i++) { https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBOperatorStore.sol#L165

File: /jbx-protocol/juice-contracts-v2/blob/main/contracts/JBDirectory.sol 139: for (uint256 _i; _i < _terminalsOf[_projectId].length; _i++) {

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBDirectory.sol#L139

167: for (uint256 _i; _i < _terminalsOf[_projectId].length; _i++) https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBDirectory.sol#L167

275: for (uint256 _i; _i < _terminals.length; _i++) 276: for (uint256 _j = _i + 1; _j < _terminals.length; _j++)

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBDirectory.sol#L275-L276

File: /jbx-protocol/juice-contracts-v2/blob/main/contracts/JBController.sol 913: for (uint256 _i = 0; _i < _splits.length; _i++) { ``` https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBController.sol#L913 `1014: for (uint256 _i; _i < _fundAccessConstraints.length; _i++) {` https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBController.sol#L1014 ``` File: /jbx-protocol/juice-contracts-v2/blob/main/contracts/JBSingleTokenPaymentTerminalStore.sol 862: for (uint256 _i = 0; _i < _terminals.length; _i++) ``` https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBSingleTokenPaymentTerminalStore.sol#L862 ``` File: /jbx-protocol/juice-contracts-v2/blob/main/contracts/JBETHERC20SplitsPayer.sol 466: for (uint256 i = 0; i < _splits.length; i++) { ``` https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBETHERC20SplitsPayer.sol#L466 # Using > 0 Costs More Gas Than != 0 ``` File: /jbx-protocol/juice-contracts-v2/blob/main/contracts/JBETHERC20SplitsPayer.sol 477: if (_splitAmount > 0) { ``` https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBETHERC20SplitsPayer.sol#L477 # <X> = <X> - <Y> Costs More Gas Than <X> - = <Y> ``` File: /jbx-protocol/juice-contracts-v2/blob/main/contracts/JBETHERC20SplitsPayer.sol 543: leftoverAmount = leftoverAmount - _splitAmount; ``` https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBETHERC20SplitsPayer.sol#L543 # Declare This Variable “uint256 _splitAmount” Outside The Loop

File: /jbx-protocol/juice-contracts-v2/blob/main/contracts/JBETHERC20SplitsPayer.sol

471: uint256 _splitAmount = PRBMath.mulDiv()

https://github.com/jbx-protocol/juice-contracts-v2/blob/main/contracts/JBETHERC20SplitsPayer.sol#L471-L475
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