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
Rank: 9/67
Findings: 4
Award: $1,298.66
π Selected for report: 0
π Solo Findings: 0
617.4135 USDC - $617.41
Solidity won't perform automatic checks when downcasting and it's possible for some fields to overflow while adding tiers.
JBTiered721DelegateStore.recordAddTiers()
, one item for _tiersToAdd
contains votingUnits
bigger than the size of uint16, e.g. 65536._storedTierOf
will overflow, e.g. if the input is 65536 the value will be 0.Similar behavior can occur for other fields for a tier.
Slient overflows will affect tier accouting and can cause unexpected behavior in the protocol.
Make use of a safe-cast library. E.g. OpenZeppelin's SafeCast.
#0 - drgorillamd
2022-10-24T08:34:12Z
Nice finding, disagree with severity (another tier can be added to fix it/no function/availability of the protocol impacted)
#1 - c4-judge
2022-11-08T16:22:15Z
Picodes marked the issue as duplicate
#2 - c4-judge
2022-12-03T19:19:40Z
Picodes marked the issue as satisfactory
617.4135 USDC - $617.41
https://github.com/jbx-protocol/juice-nft-rewards/blob/f9893b1497098241dd3a664956d8016ff0d0efd0/contracts/JBTiered721DelegateStore.sol#L349 https://github.com/jbx-protocol/juice-nft-rewards/blob/f9893b1497098241dd3a664956d8016ff0d0efd0/contracts/JBTiered721DelegateStore.sol#L403 https://github.com/jbx-protocol/juice-nft-rewards/blob/f9893b1497098241dd3a664956d8016ff0d0efd0/contracts/JBTiered721DelegateStore.sol#L504 https://github.com/jbx-protocol/juice-nft-rewards/blob/f9893b1497098241dd3a664956d8016ff0d0efd0/contracts/JBTiered721DelegateStore.sol#L558
Multiple loops in JBTiered721DelegateStore
are iterating over maxTierIdOf
for a nft address. This value is incremented when calling recordAddTiers()
. The contract doesn't seem to have a functionality for decreasing this value.
maxTierIdOf
for a nft address gets large due to several incrementstotalSupply()
, votingUnitsOf()
, balanceOf()
, totalRedemptionWeight()
may run out of gas.Add a limit value when increment maxTierIfOf
inside recordAddTiers()
. E.g. require(maxTierIdOf[msg.sender] <= CONSTANT_MAX_VALUE
).
Additionally consider adding a pagination functionality when retrieving data for totalSupply()
, votingUnitsOf()
, balanceOf()
and totalRedemptionWeight()
#0 - drgorillamd
2022-10-24T08:26:18Z
Disagree with:
Over time maxTierIdOf for a nft address gets large due to several increments
There is no several increments outside of adding new tiers by the project owner (this is similar to adding new token in an erc1155 - there is no such check in, for instance, OZ https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC1155/ERC1155.sol), this is a project owner choice, not a faulty logic
#1 - trust1995
2022-11-08T15:28:02Z
Agree that this is a design choice and that no danger to any user funds or usability makes it a QA recommendation issue.
#2 - Picodes
2022-11-08T16:02:56Z
I don't think https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC1155/ERC1155.sol uses unbounded for loop ?
#3 - Picodes
2022-11-08T16:19:11Z
User funds could be at stake as redeemParams
would revert because of the for loop in totalRedemptionWeight
. A limit value would be indeed a good safeguard.
#4 - c4-judge
2022-11-08T16:19:17Z
Picodes marked the issue as satisfactory
#5 - c4-judge
2022-12-03T19:11:01Z
Picodes marked the issue as primary issue
#6 - c4-judge
2022-12-07T07:31:05Z
Simon-Busch marked the issue as duplicate of #64
π Selected for report: berndartmueller
Also found by: 0x1f8b, 0x4non, 0xNazgul, 0xSmartContract, Aymen0909, BClabs, Diana, Jeiwan, Lambda, LeoS, RaoulSchaffranek, RaymondFam, RedOneN, ReyAdmirado, Rolezn, SaharAP, Trust, V_B, __141345__, a12jmx, bharg4v, brgltd, carlitox477, ch0bu, chaduke, cloudjunky, cryptostellar5, cryptphi, csanuragjain, d3e4, delfin454000, erictee, fatherOfBlocks, hansfriese, ignacio, joestakey, karanctf, ladboy233, lukris02, mcwildy, minhtrng, peanuts, ret2basic, seyni, slowmoses, svskaushik, tnevler, yixxas
37.8829 USDC - $37.88
If a variable gets configured with address zero, failure to immediately reset the value can result in unexpected behavior for the project.
Lack of two-step procedure for critical operations leaves them error-prone. Consider adding two step procedure on the critical functions.
Assume the following scenario:
JBTiered721Delegate.setBaseUri()
with the existing current baseUri
, potentially by accidentConsider checking if the new parameter is different from the existing parameter for the following functions:
Consider adding NATSPEC on all functions to improve documentation.
Some functions return named variables, others return explicit values.
Following function return explicit value
Following function return return a named variable
Consider adopting a consistent approach to return values throughout the codebase by removing all named return variables, explicitly declaring them as local variables, and adding the necessary return statements where appropriate. This would improve both the explicitness and readability of the code, and it may also help reduce regressions during future code refactors.
#0 - c4-judge
2022-11-08T18:18:45Z
Picodes marked the issue as grade-b
π Selected for report: Jeiwan
Also found by: 0x1f8b, 0x4non, 0x5rings, 0xSmartContract, Awesome, Aymen0909, Bnke0x0, CodingNameKiki, Diana, DimSon, JC, JrNet, LeoS, RaymondFam, ReyAdmirado, Saintcode_, Shinchan, __141345__, berndartmueller, bharg4v, brgltd, carlitox477, ch0bu, chaduke, cryptostellar5, emrekocak, gogo, lukris02, martin, mcwildy, sakman, trustindistrust, zishansami
25.9629 USDC - $25.96
It can save 30-40 gas per loop
There are 5 instances of this issue.
File: contracts/libraries/JBIpfsDecoder.sol 49: for (uint256 i = 0; i < _source.length; ++i) { 51: for (uint256 j = 0; j < digitlength; ++j) { 68: for (uint256 i = 0; i < _length; i++) { 76: for (uint256 i = 0; i < _input.length; i++) { 84: for (uint256 i = 0; i < _indices.length; i++) {
Using the addition operator instead of plus-equals saves 113 gas.
There's 1 instance with this issue.
File: contracts/JBTiered721DelegateStore.sol 827: numberOfReservesMintedFor[msg.sender][_tierId] += _count;
Caching of a state variable replace each Gwarmaccess (100 gas) with a cheaper stack read.
For example, on the following instance, projectId
should be cached.
#0 - c4-judge
2022-11-04T10:15:57Z
Picodes marked the issue as grade-b
#1 - Picodes
2022-11-04T10:17:22Z
1 - out of scope 2 - invalid for arrays per this 3 - valid