NextGen - ZanyBonzy's results

Advanced smart contracts for launching generative art projects on Ethereum.

General Information

Platform: Code4rena

Start Date: 30/10/2023

Pot Size: $49,250 USDC

Total HM: 14

Participants: 243

Period: 14 days

Judge: 0xsomeone

Id: 302

League: ETH

NextGen

Findings Distribution

Researcher Performance

Rank: 116/243

Findings: 1

Award: $13.39

QA:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

13.3948 USDC - $13.39

Labels

bug
grade-b
QA (Quality Assurance)
sufficient quality report
Q-08

External Links

AuctionDemo.sol

  1. No need to denote the constructor's visibility. L36

constructor (address _minter, address _gencore, address _adminsContract) public {

  1. Consider removing empty/unused else block. L118, L141

else {}

  1. returnhighestbidder sets the highbid to 0. The available bids are then compared against it, presumably to check if they're higher. However, the highbid is not set to the last checked bid. This means that that bids are compared against 0 and not the actual bids. COnsider fixing this for as good practice.
function returnHighestBidder(uint256 _tokenid) public view returns (address) { uint256 highBid = 0; uint256 index; for (uint256 i=0; i< auctionInfoData[_tokenid].length; i++) { if (auctionInfoData[_tokenid][i].bid > highBid && auctionInfoData[_tokenid][i].status == true) { //@note all bids are compared against 0 index = i; } } ...
  1. returnHighestBidder function can be refactored. To participate in an auction, the amount bid must be greater than the current highest bid, and each newbid is pushed into the auctionInfoData array. This ensures that every newbid (which is greater than the previous) becomes the last element of the auctionInfoData array. Thererfore, the last element of the array belonds to the highest bidder.

The returnHighestBidder can be made to count down from the last element instead of the first, and checks their auction status. If true, then it is selected. It seems faster and less gas intensive as the loop is more likely to run lesser iterations. e.g

function returnHighestBidder(uint256 _tokenid) public view returns (address) { uint256 index; uint256 refactor = auctionInfoData[_tokenid].length; for (uint i = refactor; i > 0;) { if (auctionInfoData[_tokenid][i - 1].status == true) { index = i - 1; break; unchecked{ --i; } else { revert("No Active Bidder"); } } return auctionInfoData[_tokenid][index].bidder; }
  1. Potential race condition The participateToAuction, cancelBid, cancelAllBids functions can be called when block.timestamp <= minter.getAuctionEndTime(_tokenid) i.e when auction ends.

The claimAuction function can be claimed when block.timestamp >= minter.getAuctionEndTime(_tokenid).

This introduces a potenctial race condition in which users and admins can all call the functions at the exact same time for the exact same token, when block.timestamp >= minter.getAuctionEndTime(_tokenid).

Depending on which gets executed first, undersired outcomes may occur. For instance, If the highest bidder decides to cancel his auction, he might find out that the admin already claimed on his behalf, or that another user outbidded him at the last second. Consider changing the condition in claimAuction to block.timestamp > minter.getAuctionEndTime(_tokenid).

NextGenAdmns.sol

  1. registerCollectionAdmin should check for collection existence before registering admin so as to prevent setting admin for non-existent collections;
function registerCollectionAdmin(uint256 _collectionID, address _address, bool _status) public AdminRequired { require(_collectionID > 0, "Collection Id must be larger than 0"); //@note inexistent collection?? collectionAdmin[_address][_collectionID] = _status; }
  1. Admins can be registered, but not deregistered. Cosider introducting functions to deregister admins in case they get compromised or go rouge. function registerAdmin(address _admin, bool _status) public onlyOwner {

function registerFunctionAdmin(address _address, bytes4 _selector, bool _status) public AdminRequired {

function registerBatchFunctionAdmin(address _address, bytes4[] memory _selector, bool _status) public AdminRequired {

function registerCollectionAdmin(uint256 _collectionID, address _address, bool _status) public AdminRequired {

XRandoms.sol

  1. abi.encodePacked should not be used with dynamic types when passing the result to a hash function such as keccak256. Use abi.encode instead, which will pad items to 32 bytes, to prevent any hash collisions.

uint256 randomNum = uint(keccak256(abi.encodePacked(block.prevrandao, blockhash(block.number - 1), block.timestamp))) % 1000; L36

uint256 randomNum = uint(keccak256(abi.encodePacked(block.prevrandao, blockhash(block.number - 1), block.timestamp))) % 100; L41

MinterContract.sol

  1. External call in unbounded loop uint256 mintIndex = gencore.viewTokensIndexMin(_collectionID) + gencore.viewCirSupply(_collectionID);L188

  2. Typo - "greater" not "grater"

    require(collectionTotalAmount[_collectionID] > 0, "Collection Balance must be grater than 0");

  3. Misleading revert string - "at least 1 mint/period" better

    require(tDiff>=1, "1 mint/period");

RandomizerNXT.sol

  1. updateAdminsContract doens't check if admin address is registered
function updateAdminsContract(address _admin) public FunctionAdminRequired(this.updateAdminsContract.selector) { adminsContract = INextGenAdmins(_admin); }

#0 - 141345

2023-11-25T08:07:08Z

1386 ZanyBonzy l r nc 2 2 4

L 1 n L 2 n L 3 d dup of https://github.com/code-423n4/2023-10-nextgen-findings/issues/586 L 4 r L 5 d dup of https://github.com/code-423n4/2023-10-nextgen-findings/issues/962 L 6 l L 7 r L 8 i bot L 9 i bot L 10 n L 11 n L 12 l

#1 - c4-pre-sort

2023-11-25T08:11:20Z

141345 marked the issue as sufficient quality report

#2 - alex-ppg

2023-12-08T15:15:34Z

QA Judgment

The Warden's QA report has been graded B based on a score of 10 combined with a manual review per the relevant QA guideline document located here.

The Warden's submission's score was assessed based on the following accepted findings:

Low-Risk

  • 5: #1323

#3 - c4-judge

2023-12-08T15:15:43Z

alex-ppg marked the issue as grade-b

#4 - alex-ppg

2023-12-09T11:27:21Z

Hey @ZanyBonzy, thanks for following up on this! When evaluating QA reports, I have performed my independent judgment and the QA Judgment response above reflects this as I only considered 5 as a valid submission of a QA (L) issue.

#5 - alex-ppg

2023-12-12T14:40:43Z

Hey @ZanyBonzy, thanks for your feedback. Per the document linked in the initial response to this submission as well as the main PJQA discussion page:

At my discretion, if a Warden has sufficiently argued in the QA report that the submission may be upgrade-able and they have focused adequately on the issue, I may reward them a reduced percentage out of the report's pool.

Your 5 statement makes no mention of the potential impact of #1323 and the impact detailed in your QA report is of a QA (L) grade or lower. To ensure transparency in the grade of your QA report, I will provide rationale for the grade of each of the report's points:

  1. Submitted as part of a public PR in the contest page during its duration and thus was invalidated (#30)
  2. Part of the bot report L-2
  3. The code correctly checks that the bids are non-zero and have a status of true. The bids are in a strictly ascending order (when we factor in their status) meaning that no functionality needs to change. As such, I considered this a gas optimization.
  4. This is a gas optimization
  5. This was graded as QA (L)
  6. This submission pertains to an administrator mistake that is inconsequential and falls under the relevant SC verdict with no points awarded
  7. Administrators can be "de-registered" by setting their status to false, rendering this incorrect
  8. All types in the referenced statement are 32 bytes in length, rendering the output of abi.encode equivalent to abi.encodePacked
  9. Part of the bot report L-14
  10. Typographic mistake of a comment which would be awarded an I point at best
  11. The misleading string is not misleading to an extent that would warrant a change
  12. This recommendation is generic and does not specify where it should be registered.

As a result of the above evaluation, I will maintain my grade B assignment which could have arguably been a grade C. Keep in mind that the A grade was awarded to a report that had at minimum 23 points which is substantially higher than yours. Even considering 3 and 6 as a QA (NC) and all I exhibits, it would bring your total to 10 + 6 + 2 = 18 which is far less than the fifth and final A report with a score of 23 (#1794).

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter