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: 46/105
Findings: 3
Award: $131.51
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: horsefacts
Also found by: 0x1f8b, 0x29A, 0x52, 0xf15ers, AlleyCat, Ch_301, Chom, Franfran, IllIllI, Kaiziron, Limbooo, Meera, Ruhum, Sm4rty, apostle0x01, berndartmueller, cccz, cloudjunky, codexploder, cryptphi, delfin454000, durianSausage, fatherOfBlocks, hake, hansfriese, hyh, jonatascm, m_Rassska, oyc_109, peritoflores, rajatbeladiya, rbserver, svskaushik, zzzitron
3.4075 USDC - $3.41
The transferFrom() method is used instead of safeTransferFrom(), presumably to save gas. I however argue that this isn’t recommended because:
OpenZeppelin’s documentation discourages the use of transferFrom(), use safeTransferFrom() whenever possible.
JBERC20PaymentTerminal.sol, L88, _transferFrom
IERC20(token).transferFrom(_from, _to, _amount);
we should use
IERC20(token).safeTransferFrom(_from, _to, _amount);
#0 - mejango
2022-07-12T18:23:27Z
dup #281
🌟 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
89.271 USDC - $89.27
If we use storage variable without modifying its value, we should use SLOAD once and MLOAD others.
JBController.sol, 983, _configure
if (_metadata.reservedRate > JBConstants.MAX_RESERVED_RATE) revert INVALID_RESERVED_RATE(); // Make sure the provided redemption rate is valid. if (_metadata.redemptionRate > JBConstants.MAX_REDEMPTION_RATE) revert INVALID_REDEMPTION_RATE(); // Make sure the provided ballot redemption rate is valid. if (_metadata.ballotRedemptionRate > JBConstants.MAX_REDEMPTION_RATE) revert INVALID_BALLOT_REDEMPTION_RATE();
we should convert it into
uint256 max_redemption_rate = JBConstants.MAX_RESERVED_RATE; if (_metadata.reservedRate > max_redemption_rate) revert INVALID_RESERVED_RATE(); // Make sure the provided redemption rate is valid. if (_metadata.redemptionRate > max_redemption_rate) revert INVALID_REDEMPTION_RATE(); // Make sure the provided ballot redemption rate is valid. if (_metadata.ballotRedemptionRate > max_redemption_rate) revert INVALID_BALLOT_REDEMPTION_RATE();
JBController.sol, 1069, _reservedTokenAmountFrom
// If all tokens are reserved, return the full unprocessed amount. if (_reservedRate == JBConstants.MAX_RESERVED_RATE) return _unprocessedTokenBalanceOf; return PRBMath.mulDiv( _unprocessedTokenBalanceOf, JBConstants.MAX_RESERVED_RATE, JBConstants.MAX_RESERVED_RATE - _reservedRate ) - _unprocessedTokenBalanceOf;
we should convert it into
uint256 max_reserved_rate = JBConstants.MAX_RESERVED_RATE; // If all tokens are reserved, return the full unprocessed amount. if (_reservedRate == max_reserved_rate) return _unprocessedTokenBalanceOf; return PRBMath.mulDiv( _unprocessedTokenBalanceOf, max_reserved_rate, max_reserved_rate - _reservedRate ) - _unprocessedTokenBalanceOf;
JBFundingCycleStore.sol, 704, _deriveWeightFrom
if (_baseFundingCycle.duration == 0) return PRBMath.mulDiv( _baseFundingCycle.weight, JBConstants.MAX_DISCOUNT_RATE - _baseFundingCycle.discountRate, JBConstants.MAX_DISCOUNT_RATE );
we should convert it into
uint256 max_discount_rate = JBConstants.MAX_DISCOUNT_RATE; if (_baseFundingCycle.duration == 0) return PRBMath.mulDiv( _baseFundingCycle.weight, max_discount_rate - _baseFundingCycle.discountRate, max_discount_rate );
JBFundingCycleStore.sol, 727, _deriveWeightFrom
weight = PRBMath.mulDiv( weight, JBConstants.MAX_DISCOUNT_RATE - _baseFundingCycle.discountRate, JBConstants.MAX_DISCOUNT_RATE );
we should convert it into
weight = PRBMath.mulDiv( weight, max_discount_rate - _baseFundingCycle.discountRate, max_discount_rate );
JBSingleTokenPaymentTerminalStore.sol, 580, recordDistributionFor
distributedAmount = (_currency == _balanceCurrency) ? _amount : PRBMath.mulDiv( _amount, 10**_MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting. prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY) );
we use convert it into
uint256 max_fixed_point_fidelity = _MAX_FIXED_POINT_FIDELITY; distributedAmount = (_currency == _balanceCurrency) ? _amount : PRBMath.mulDiv( _amount, 10**max_fixed_point_fidelity, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting. prices.priceFor(_currency, _balanceCurrency, max_fixed_point_fidelity) );
JBSingleTokenPaymentTerminalStore.sol, 775, _reclaimableOverflowDuring
if (_redemptionRate == JBConstants.MAX_REDEMPTION_RATE) return _base; return PRBMath.mulDiv( _base, _redemptionRate + PRBMath.mulDiv( _tokenCount, JBConstants.MAX_REDEMPTION_RATE - _redemptionRate, _totalSupply ), JBConstants.MAX_REDEMPTION_RATE );
we use convert it into
uint256 max_redemption_rate = JBConstants.MAX_REDEMPTION_RATE; if (_redemptionRate == max_redemption_rate) return _base; return PRBMath.mulDiv( _base, _redemptionRate + PRBMath.mulDiv( _tokenCount, max_redemption_rate - _redemptionRate, _totalSupply ), max_redemption_rate );
JBSingleTokenPaymentTerminalStore.sol, 827, _overflowDuring
_distributionLimitRemaining = PRBMath.mulDiv( _distributionLimitRemaining, 10**_MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting. prices.priceFor(_distributionLimitCurrency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY) );
we use convert it into
uint256 max_fixed_point_dielity = _MAX_FIXED_POINT_FIDELITY; _distributionLimitRemaining = PRBMath.mulDiv( _distributionLimitRemaining, 10**max_fixed_point_dielity, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting. prices.priceFor(_distributionLimitCurrency, _balanceCurrency, max_fixed_point_dielity) );
JBSingleTokenPaymentTerminalStore.sol, 866, _currentTotalOverflowOf
uint256 _totalOverflow18Decimal = _currency == JBCurrencies.ETH ? _ethOverflow : PRBMath.mulDiv(_ethOverflow, 10**18, prices.priceFor(JBCurrencies.ETH, _currency, 18));
we use convert it into
uint256 eth_address = JBCurrencies.ETH; uint256 _totalOverflow18Decimal = _currency == eth_address ? _ethOverflow : PRBMath.mulDiv(_ethOverflow, 10**18, prices.priceFor(eth_address, _currency, 18));
🌟 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
0 is less gas efficient than !0 if you enable the optimizer at 10k AND you’re in a require statement. Detailed explanation with the opcodes https://twitter.com/gzeon/status/1485428085885640706
'JBController.sol', 437, 'JBController.sol', 480, 'JBController.sol', 497, 'JBController.sol', 874, 'JBController.sol', 924, 'JBController.sol', 1031 'JBController.sol', 1039 'JBController.sol', 437 'JBController.sol', 497 'JBETHERC20ProjectPayer.sol', 267, 'JBETHERC20ProjectPayer.sol', 311, 'JBETHERC20SplitsPayer.sol', 252, 'JBETHERC20SplitsPayer.sol', 274, 'JBETHERC20SplitsPayer.sol', 344, 'JBETHERC20SplitsPayer.sol', 366, 'JBETHERC20SplitsPayer.sol', 476, 'JBFundingCycleStore.sol', 148, 'JBFundingCycleStore.sol', 209, 'JBFundingCycleStore.sol', 346, 'JBFundingCycleStore.sol', 347, 'JBFundingCycleStore.sol', 363, 'JBFundingCycleStore.sol', 468, 'JBFundingCycleStore.sol', 559, 'JBFundingCycleStore.sol', 588, 'JBFundingCycleStore.sol', 600, 'JBFundingCycleStore.sol', 588 'JBProjects.sol', 142 'JBProjects.sol', 142 'JBSingleTokenPaymentTerminalStore.sol', 474 'JBSingleTokenPaymentTerminalStore.sol', 517 'JBSplitsStore.sol', 258 'JBSplitsStore.sol', 325 'JBPayoutRedemptionPaymentTerminal.sol', 345 'JBPayoutRedemptionPaymentTerminal.sol', 515 'JBPayoutRedemptionPaymentTerminal.sol', 551 'JBPayoutRedemptionPaymentTerminal.sol', 744 'JBPayoutRedemptionPaymentTerminal.sol', 771 'JBPayoutRedemptionPaymentTerminal.sol', 883 'JBPayoutRedemptionPaymentTerminal.sol', 963 'JBPayoutRedemptionPaymentTerminal.sol', 1021 'JBPayoutRedemptionPaymentTerminal.sol', 1296
The overheads outlined below are PER LOOP, excluding the first loop
storage arrays incur a Gwarmaccess (100 gas) memory arrays use MLOAD (3 gas) calldata arrays use CALLDATALOAD (3 gas) Caching the length changes each of these to a DUP (3 gas), and gets rid of the extra DUP needed to store the stack offset
JBController.sol', 912, JBController.sol', 1013 JBDirectory.sol', 138 JBDirectory.sol', 166 'JBDirectory.sol', 274 'JBDirectory.sol', 275 'JBETHERC20SplitsPayer.sol', 465 'JBOperatorStore.sol', 84 'JBOperatorStore.sol', 134 'JBOperatorStore.sol', 164 'JBSingleTokenPaymentTerminalStore.sol', 861 'JBSplitsStore.sol', 203 'JBSplitsStore.sol', 210 'JBSplitsStore.sol', 228 'JBPayoutRedemptionPaymentTerminal.sol', 1007
prefix increment ++i is more cheaper than postfix i++
JBController.sol', 912, JBController.sol', 1013 JBDirectory.sol', 138, JBDirectory.sol', 166, JBDirectory.sol', 274, JBDirectory.sol', 275, 'JBETHERC20SplitsPayer.sol', 465 'JBFundingCycleStore.sol', 723 JBOperatorStore.sol', 84, JBOperatorStore.sol', 134, JBOperatorStore.sol', 164, JBSingleTokenPaymentTerminalStore.sol', 861 JBSplitsStore.sol', 203 JBSplitsStore.sol', 210 JBSplitsStore.sol', 228 JBSplitsStore.sol', 303
JBPayoutRedemptionPaymentTerminal.sol, 859 JBPayoutRedemptionPaymentTerminal.sol, 1037 JBPayoutRedemptionPaymentTerminal.sol, 1102 JBPayoutRedemptionPaymentTerminal.sol, 1144 JBPayoutRedemptionPaymentTerminal.sol, 1400 JBPayoutRedemptionPaymentTerminal.sol, 1416