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: 27/67
Findings: 2
Award: $63.84
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 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
_mint()
is discouraged in favor of _safeMint()
which ensures that the recipient is either an EOA or implements IERC721Receiver
. Both open OpenZeppelin and solmate have versions of this function so that NFTs aren’t lost if they’re minted to contracts that cannot transfer them back out.
461: _mint(_reservedTokenBeneficiary, _tokenId); 504: _mint(_beneficiary, _tokenId); 635: _mint(_beneficiary, _tokenId); 677: _mint(_beneficiary, _tokenId);
<address>.code.length
can be used in Solidity >= 0.8.0 to access an account’s code size and check if it is a contract without inline assembly.
let _codeSize := extcodesize(_targetAddress)
216: require(address(this) != codeOrigin); 218: require(address(store) == address(0));
This is applicable accross all the smart contracts.
This is applicable accross all contracts, here are few instances:
44: function _toBase58(bytes memory _source) private pure returns (string memory) { 66: function _truncate(uint8[] memory _array, uint8 _length) private pure returns (uint8[] memory) {
#0 - c4-judge
2022-11-05T09:33:27Z
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
Number of Instances Identified: 5
Removing unused named returns variables can reduce gas usage (MSTOREs/MLOADs) and improve code clarity. To save gas and improve code quality: consider using only one of those.
37: returns (uint256 units) 123: function balanceOf(address _owner) public view override returns (uint256 balance) {
617: ) internal returns (uint256 leftoverAmount) {
119: returns (uint256 configuration) 162: returns (uint256 configuration)
Number of Instances Identified: 7
354: supply += _storedTier.initialQuantity - _storedTier.remainingQuantity; 409: units += _balance * _storedTierOf[_nft][_i].votingUnits; 506: balance += tierBalanceOf[_nft][_owner][_i]; 534: weight += _storedTierOf[_nft][tierIdOfToken(_tokenIds[_i])].contributionFloor; 563: weight +=... 827: numberOfReservesMintedFor[msg.sender][_tierId] += _count;
62: carry += uint256(digits[j]) * 256;
the unchecked
keyword is new in solidity version 0.8.0, so this only applies to that version or higher, which these instances are.
Number of Instances Identified: 5
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++) {
Number of Instances Identified: 6
Pre-increments and pre-decrements are cheaper.
For a uint256 i
variable, the following is true with the Optimizer enabled at 10k:
Increment:
i += 1
is the most expensive formi++
costs 6 gas less than i += 1
++i
costs 5 gas less than i++
(11 gas less than i += 1
)Decrement:
i -= 1
is the most expensive formi--
costs 11 gas less than i -= 1
--i
costs 5 gas less than i--
(16 gas less than i -= 1
)59: digitlength++; 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++) {
1106: numberOfBurnedFor[msg.sender][_tierId]++; 1108: _storedTierOf[msg.sender][_tierId].remainingQuantity++;
Number of Instances Identified: 5
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) {
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++) {
Number of Instances Identified: 4
Not inlining costs 20 to 40 gas because of two extra JUMP
instructions and additional stack operations needed for function calls.
194: function _getTierVotingUnits(address _account, uint256 _tierId) 242: function _transferTierVotingUnits
524: function _processPayment(JBDidPayData calldata _data) internal override { 598: function _didBurn(uint256[] memory _tokenIds) internal override {
#0 - Picodes
2022-11-08T17:46:24Z
Most findings are invalid or out of scope with the automated report
#1 - c4-judge
2022-11-08T17:46:28Z
Picodes marked the issue as grade-b