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
Rank: 26/105
Findings: 2
Award: $395.03
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: IllIllI
Also found by: 0v3rf10w, 0x1f8b, 0x29A, 0xDjango, 0xNazgul, 0xNineDec, 0xdanial, 0xf15ers, Bnke0x0, Ch_301, Chandr, Chom, Funen, GimelSec, Hawkeye, JC, Kaiziron, Lambda, Meera, MiloTruck, Noah3o6, Picodes, ReyAdmirado, Rohan16, Sm4rty, TerrierLover, TomJ, Waze, _Adam, __141345__, asutorufos, aysha, berndartmueller, brgltd, cccz, codexploder, defsec, delfin454000, djxploit, durianSausage, fatherOfBlocks, hake, horsefacts, hubble, jayfromthe13th, joestakey, jonatascm, m_Rassska, oyc_109, pashov, rajatbeladiya, rbserver, robee, sach1r0, sahar, samruna, simon135, svskaushik, zzzitron
356.1991 USDC - $356.20
If the funding target is not met, the fund is not redeemable. However, after the funding target is hit, new contribution will have an advantage of redeemable, compare to early pay.
Suggestion: Distinguish between redemption before and after funding target.
For any discount rate > 0, and multiple periodic funding cycle, the token received per ETH/USDC contribution would exponentially going to 0, makes the project less and less attractive to users. And eventually not worth contributing anymore. For example, 0.9^20 = 0.12, 0.95^40 = 0.36, for discount rate of 10%, after 20 cycles, the token is only 12%, for discount rate of 5%, only 36% left. Keep in mind they it is exponentially decrease.
If a project is configured by a contract, not being able to change, the later stages of the project could be hard to develop.
Suggestion: Creating alert for long going projects, or contract owned projects.
There is a delay in the reconfiguration, but after submit, it can not be cancelled. Sometimes project operators may make mistakes, or change their mind after community discussion.
Suggestion: Allowing for cancellation for pending reconfiguration.
If the redemption rate is set to 0, it is equivalent to not allow redemption, which can be set elsewhere.
Suggestion: Enforce the redemption rate > 0
🌟 Selected for report: 0xA5DF
Also found by: 0v3rf10w, 0x09GTO, 0x1f8b, 0x29A, 0xDjango, 0xKitsune, 0xNazgul, 0xdanial, 0xf15ers, Aymen0909, Bnke0x0, Ch_301, Cheeezzyyyy, Chom, ElKu, Funen, Hawkeye, IllIllI, JC, JohnSmith, Kaiziron, Lambda, Limbooo, Meera, Metatron, MiloTruck, Noah3o6, Picodes, Randyyy, RedOneN, ReyAdmirado, Rohan16, Saintcode_, Sm4rty, TomJ, Tomio, Tutturu, UnusualTurtle, Waze, _Adam, __141345__, ajtra, apostle0x01, asutorufos, brgltd, c3phas, cRat1st0s, codexploder, defsec, delfin454000, djxploit, durianSausage, exd0tpy, fatherOfBlocks, hake, horsefacts, ignacio, jayfromthe13th, joestakey, jonatascm, kaden, kebabsec, m_Rassska, mektigboy, mrpathfindr, oyc_109, rajatbeladiya, rbserver, rfa, robee, sach1r0, sashik_eth, simon135
38.8282 USDC - $38.83
There are several for loops can be improved to save gas
JBController.sol 913: for (uint256 _i = 0; _i < _splits.length; _i++) { 1014: for (uint256 _i; _i < _fundAccessConstraints.length; _i++) { JBDirectory.sol 139: for (uint256 _i; _i < _terminalsOf[_projectId].length; _i++) { 167: for (uint256 _i; _i < _terminalsOf[_projectId].length; _i++) 275,276: for (uint256 _i; _i < _terminals.length; _i++) for (uint256 _j = _i + 1; _j < _terminals.length; _j++) JBFundingCycleStore.sol 724: for (uint256 i = 0; i < _discountMultiple; i++) { JBOperatorStore.sol 85: for (uint256 _i = 0; _i < _permissionIndexes.length; _i++) { 135: for (uint256 _i = 0; _i < _operatorData.length; _i++) { 165: for (uint256 _i = 0; _i < _indexes.length; _i++) { JBSingleTokenPaymentTerminalStore.sol 862: for (uint256 _i = 0; _i < _terminals.length; _i++) JBSplitsStore.sol 165: for (uint256 _i = 0; _i < _groupedSplitsLength; ) { 204: for (uint256 _i = 0; _i < _currentSplits.length; _i++) { 211: for (uint256 _j = 0; _j < _splits.length; _j++) { 229: for (uint256 _i = 0; _i < _splits.length; _i++) { 304: for (uint256 _i = 0; _i < _splitCount; _i++) { abstract\JBPayoutRedemptionPaymentTerminal.sol 594: for (uint256 _i = 0; _i < _heldFeeLength; ) { 1008: for (uint256 _i = 0; _i < _splits.length; ) { 1396: for (uint256 _i = 0; _i < _heldFeesLength; ) {
suggestion: cache the for loop length to memory before the loop.
suggestion: using ++i instead of i++ to increment the value of an uint variable.
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.
suggestion:
for (uint i = 0; i < lenth; ++i)
can be written as
for (uint i ; i < lenth; ++i)
The for loops can be written as follows, take one example:
uint length = _splits.length; for (uint i; i < length;) { // ... unchecked { ++i; } }
!= 0 is a cheaper operation compared to > 0, when dealing with uint.
There are multiple if > 0 statements.
Here is one example:
contracts/JBController.sol:438: if (_terminals.length > 0) directory.setTerminalsOf(projectId, _terminals);
JBTokenStore.sol:
344-364: if (_claimedBalance == 0) _claimedTokensToBurn = 0; // If prefer converted, redeem tokens before redeeming unclaimed tokens. else if (_preferClaimedTokens) _claimedTokensToBurn = _claimedBalance < _amount ? _claimedBalance : _amount; // Otherwise, redeem unclaimed tokens before claimed tokens. else _claimedTokensToBurn = _unclaimedBalance < _amount ? _amount - _unclaimedBalance : 0; // The amount of unclaimed tokens to redeem. uint256 _unclaimedTokensToBurn = _amount - _claimedTokensToBurn; // Subtract the tokens from the unclaimed balance and total supply. if (_unclaimedTokensToBurn > 0) { // Reduce the holders balance and the total supply. unclaimedBalanceOf[_holder][_projectId] = unclaimedBalanceOf[_holder][_projectId] - _unclaimedTokensToBurn; unclaimedTotalSupplyOf[_projectId] = unclaimedTotalSupplyOf[_projectId] - _unclaimedTokensToBurn; } 406-412: if (_unclaimedBalance < _amount) revert INSUFFICIENT_UNCLAIMED_TOKENS(); // Subtract the claim amount from the holder's unclaimed project token balance. unclaimedBalanceOf[_holder][_projectId] = unclaimedBalanceOf[_holder][_projectId] - _amount; // Subtract the claim amount from the project's unclaimed total supply. unclaimedTotalSupplyOf[_projectId] = unclaimedTotalSupplyOf[_projectId] - _amount; 445-448: if (_amount > _unclaimedBalance) revert INSUFFICIENT_UNCLAIMED_TOKENS(); // Subtract from the holder's unclaimed token balance. unclaimedBalanceOf[_holder][_projectId] = unclaimedBalanceOf[_holder][_projectId] - _amount; JBFundingCycleStore.sol 561: block.timestamp < _fundingCycle.start - _baseFundingCycle.duration 589: _fundingCycle.duration > 0 && block.timestamp >= _fundingCycle.start + _fundingCycle.duration 602: block.timestamp >= _baseFundingCycle.start + _baseFundingCycle.duration 673: uint256 _nextImmediateStart = _baseFundingCycle.start + _baseFundingCycle.duration; 679-686: uint256 _timeFromImmediateStartMultiple = (_mustStartAtOrAfter - _nextImmediateStart) % _baseFundingCycle.duration; // A reference to the first possible start timestamp. start = _mustStartAtOrAfter - _timeFromImmediateStartMultiple; // Add increments of duration as necessary to satisfy the threshold. while (_mustStartAtOrAfter > start) start = start + _baseFundingCycle.duration;
Consider use X = X + Y to save gas
contracts/abstract/JBPayoutRedemptionPaymentTerminal.sol 860: _feeEligibleDistributionAmount += _leftoverDistributionAmount; 1038: feeEligibleDistributionAmount += _payoutAmount; 1103: feeEligibleDistributionAmount += _payoutAmount; 1145: feeEligibleDistributionAmount += _payoutAmount; 1401: refundedFees += _feeAmount( 1417: refundedFees += _feeAmount(leftoverAmount, _heldFees[_i].fee, _heldFees[_i].feeDiscount);
#0 - drgorillamd
2022-08-18T09:08:46Z
X = X + Y IS CHEAPER THAN X += Y
This is not true (anymore?).
pragma solidity 0.8.6; contract TestPE { function test(uint256 a, uint256 b) external returns(uint256) { // 25644 a += b; return a; } } contract TestEP { function test(uint256 a, uint256 b) external returns(uint256) { // 25644 a = a + b; return a; } }