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: 30/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
return
from a function if it already has named declared return variablesline#L631: return leftoverAmount;
line#L2: pragma solidity ^0.8.16;
line#L2: pragma solidity ^0.8.16;
line#L2: pragma solidity ^0.8.16;
line#L2: pragma solidity ^0.8.16;
line#L2: pragma solidity ^0.8.16;
JBTiered721DelegateDeployer.sol:
line#L2: pragma solidity ^0.8.16;
JBTiered721DelegateProjectDeployer.sol:
line#L2: pragma solidity ^0.8.16;
https://docs.soliditylang.org/en/develop/natspec-format.html
JBTiered721FundingCycleMetadataResolver.sol:
line#L1: // SPDX-License-Identifier: MIT
Emmiting events is recommended each time when a state variable's value is being changed or just some critical event for the contract has occurred. It also helps off-chain monitoring of the contract's state.
line#L202: function initialize(
line#L203: function _initialize(
external
visibility modifier for function that are not being invoked by the contractline#L147: function setTierDelegates(JBTiered721SetTierDelegatesData[] memory _setTierDelegatesData) line#L177: function setTierDelegate(address _delegatee, uint256 _tierId) public virtual override {
line#L138: function tokenURI(uint256 _tokenId) public view override returns (string memory) {
line#L499: function balanceOf(address _nft, address _owner) public view override returns (uint256 balance) { line#L523: function redemptionWeightOf(address _nft, uint256[] calldata _tokenIds) line#L585: function tierIdOfToken(uint256 _tokenId) public pure override returns (uint256) { line#L599: function reservedTokenBeneficiaryOf(address _nft, uint256 _tierId)
#0 - c4-judge
2022-11-04T14:47:19Z
Picodes marked the issue as grade-c
#1 - c4-judge
2022-11-04T21:14:03Z
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
If you declare a variables of type uint256
it will automatically get assigned to its default value of 0. It is a gas wastage to assign it yourself.
line#L49: for (uint256 i = 0; i < _source.length; ++i) { line#L51: for (uint256 j = 0; j < digitlength; ++j) { line#L76: for (uint256 i = 0; i < _input.length; i++) { line#L84: for (uint256 i = 0; i < _indices.length; i++) {
constant
and immutable
keywords for storage varibles if they doesn't change through contract's lifecycleThat way the variable will go to the contract's bytecode and will not allocate a storage slot
line#L48: address public override codeOrigin;
++i
costs less gas than i++
(same for --i
/i--
)Prefix increments are cheaper than postfix increments
line#L1108:_storedTierOf[msg.sender][_tierId].remainingQuantity++;
line#L59: digitlength++; line#L68: for (uint256 i = 0; i < _length; i++) { line#L76: for (uint256 i = 0; i < _input.length; i++) { line#L84: for (uint256 i = 0; i < _indices.length; i++) {
payable
to avoid the low-level evm is-a-payment-provided
checkThe EVM checks whether a payment is provided to the function and this check costs additional gas. If the function is marked as payable
there is no such check
line#L370: function setDefaultReservedTokenBeneficiary(address _beneficiary) external override onlyOwner { line#L386: function setBaseUri(string memory _baseUri) external override onlyOwner { line#L402: function setContractUri(string calldata _contractUri) external override onlyOwner { line#L418: function setTokenUriResolver(IJBTokenUriResolver _tokenUriResolver) external override onlyOwner {
If a function is called only once it can be inlined in order to save 20 gas
line#L44: function _toBase58(bytes memory _source) private pure returns (string memory) { line#L66: function _truncate(uint8[] memory _array, uint8 _length) private pure returns (uint8[] memory) { line#L74: function _reverse(uint8[] memory _input) private pure returns (uint8[] memory) { line#L82: function _toAlphabet(uint8[] memory _indices) private pure returns (bytes memory) {
line#L827: numberOfReservesMintedFor[msg.sender][_tierId] += _count;
x < y + 1
is cheaper than x <= y
line#L903: if (_storedTierOf[msg.sender][_tierId].lockedUntil >= block.timestamp) revert TIER_LOCKED();
line#L133: if (_blockNumber >= block.number) revert BLOCK_NOT_YET_MINED();
unchecked
for the counter in for
loopsSince it is compared to a target value (usually the length of an array) there is no way the counter overflows
line#L49: for (uint256 i = 0; i < _source.length; ++i) { line#L51: for (uint256 j = 0; j < digitlength; ++j) { line#L76: for (uint256 i = 0; i < _input.length; i++) { line#L84: for (uint256 i = 0; i < _indices.length; i++) {
line#L341: ++_i; line#L355: ++_i;
calldata
where possible instead of memory
to save gasline#L205: string memory _name, line#L206: string memory _symbol, line#L210: string memory _contractUri, line#L211: JB721PricingParams memory _pricing, line#L264: function mintReservesFor(JBTiered721MintReservesForTiersData[] memory _mintReservesForTiersData) line#L290: function mintFor(JBTiered721MintForTiersData[] memory _mintForTiersData) line#L480: function mintFor(uint16[] memory _tierIds, address _beneficiary) line#L598: function _didBurn(uint256[] memory _tokenIds) internal override { line#L695: function _redemptionWeightOf(uint256[] memory _tokenIds) line#L789: JB721Tier memory _tier
line#L22: function decode(string memory _baseUri, bytes32 _hexString) /// @audit Store `_source` in calldata. line#L44: function _toBase58(bytes memory _source) private pure returns (string memory) { /// @audit Store `_input` in calldata. line#L74: function _reverse(uint8[] memory _input) private pure returns (uint8[] memory) { /// @audit Store `_indices` in calldata. line#L82: function _toAlphabet(uint8[] memory _indices) private pure returns (bytes memory) {
line#L55: JB721Tier memory _tier
line#L628: function recordAddTiers(JB721TierParams[] memory _tiersToAdd) line#L1091:function recordBurn(uint256[] memory _tokenIds) external override { line#L1227:JBStored721Tier memory _storedTier
JBTiered721DelegateProjectDeployer.sol:
line#L72: JBDeployTiered721DelegateData memory _deployTiered721DelegateData, line#L73: JBLaunchProjectData memory _launchProjectData line#L110: JBLaunchFundingCyclesData memory _launchFundingCyclesData line#L152: JBDeployTiered721DelegateData memory _deployTiered721DelegateData, line#L191: function _launchProjectFor(address _owner, JBLaunchProjectData memory _launchProjectData) line#L218: JBLaunchFundingCyclesData memory _launchFundingCyclesData
line#L29: function isTierIdRemoved(JBBitmapWord memory self, uint256 _index) internal pure returns (bool) { line#L59: function refreshBitmapNeeded(JBBitmapWord memory self, uint256 _index)
line#L206: string memory _name, line#L207: string memory _symbol line#L311: function _didBurn(uint256[] memory _tokenIds) internal virtual { line#L323: function _redemptionWeightOf(uint256[] memory _tokenIds) internal view virtual returns (uint256) {
JBTiered721DelegateDeployer.sol:
line#L71: JBDeployTiered721DelegateData memory _deployTiered721DelegateData
line#L147: function setTierDelegates(JBTiered721SetTierDelegatesData[] memory _setTierDelegatesData) line#L313: JB721Tier memory _tier
uint256
instead of the smaller uints where possibleThe word-size in ethereum is 32 bytes which means that every variables which is sized with less bytes will cost more to operate with
line#L48: uint8 digitlength = 1; line#L66: function _truncate(uint8[] memory _array, uint8 _length) private pure returns (uint8[] memory) {
if (x != 0)
instead of if (x > 0)
for uints comparisonSaves 3 gas per if
-check
line#L57: while (carry > 0) {
line#L1254:if (_numerator - JBConstants.MAX_RESERVED_RATE * _numberReservedTokensMintable > 0)
#0 - c4-judge
2022-11-04T14:45:40Z
Picodes marked the issue as grade-c
#1 - c4-judge
2022-11-04T21:14:59Z
Picodes marked the issue as grade-b