This is the top-ranked automated findings report, from Hound bot. All findings in this report will be considered known issues for the purposes of your C4 audit.
# # # # # # # # # # # # # # # # # # # # # #
# #
# |\_/| #
# | O O #
# | <> _ #
# | _/\------____ ((| |)) #
# | `--' | #
# ____|_ ___| |___.' #
# /_/_____/____/_______| #
# _ _ _ #
# | | | | | | #
# | |_| | ___ _ _ _ __ __| | #
# | _ | / _ \ | | | || '_ \ / _` | #
# | | | || (_) || |_| || | | || (_| | #
# \_| |_/ \___/ \__,_||_| |_| \__,_| #
# #
# # # # # # # # # # # # # # # # # # # # # #
Id | Title | Instances |
---|---|---|
[H-01] | Permanent DoS due to non-shrinking array usage in an unbounded loop | 4 |
Total: 4 instances over 1 issues.
Id | Title | Instances |
---|---|---|
[M-01] | Unchecked return value of low-level call()/delegatecall() |
11 |
[M-02] | User funds sent in excess are not refunded | 3 |
[M-03] | Centralization issue caused by admin privileges | 1 |
Total: 15 instances over 3 issues.
Id | Title | Instances |
---|---|---|
[L-01] | Execution at deadlines should be allowed | 3 |
[L-02] | Missing checks in constructor/initialize | 3 |
[L-03] | Missing checks for state variable assignments | 31 |
[L-04] | payable function does not transfer ETH |
1 |
[L-05] | Functions calling contracts with transfer hooks are missing reentrancy guards | 1 |
[L-06] | NFT ownership doesn't support hard forks | 1 |
[L-07] | Missing disallowlist for ERC721 |
1 |
[L-08] | Array lengths not checked | 2 |
[L-09] | Avoid shadowing state variables | 1 |
[L-10] | Subtraction may underflow if multiplication is too large | 2 |
[L-11] | Code does not follow the best practice of check-effects-interaction | 22 |
[L-12] | Missing limits when setting min/max amounts | 12 |
[L-13] | Owner can renounce ownership | 6 |
[L-14] | External calls in an unbounded loop can result in a DoS | 3 |
[L-15] | Use of ownership with a single step rather than double | 7 |
[L-16] | Use of abi.encodePacked with dynamic types inside keccak256 |
1 |
[L-17] | Loss of precision on division | 8 |
[L-18] | Gas griefing/theft is possible on an unsafe external call | 8 |
[L-19] | Arrays can grow in size without a way to shrink them | 1 |
[L-20] | onlyOwner functions not accessible if owner renounces ownership |
1 |
[L-21] | No access control on receive/payable fallback |
1 |
[L-22] | Unused/empty receive /fallback |
1 |
[L-23] | Missing checks for address(0) in constructor/initializers |
16 |
[L-24] | Missing checks for address(0) when updating state variables |
17 |
[L-25] | Consider using ERC721A instead of ERC721 |
1 |
Total: 151 instances over 25 issues.
Id | Title | Instances |
---|---|---|
[N-01] | Custom error should be used rather than require /assert |
84 |
[N-02] | High cyclomatic complexity | 1 |
[N-03] | Missing events in sensitive functions | 23 |
[N-04] | Missing events in initializers | 2 |
[N-05] | Setters should prevent re-setting the same value | 19 |
[N-06] | Usage of int/uint is discouraged |
25 |
[N-07] | Named imports of parent contracts are missing | 6 |
[N-08] | Unused arguments should be removed or implemented | 3 |
[N-09] | Ownable is not used anywhere |
6 |
[N-10] | Contracts with only utility functions should be libraries | 1 |
[N-11] | Hardcoded address should be avoided |
5 |
[N-12] | Enum values should be used in place of constant array indexes | 11 |
[N-13] | Variable initialization with zero value | 11 |
[N-14] | Consider adding emergency-stop functionality | 6 |
[N-15] | Duplicated require/if statements should be refactored |
11 |
[N-16] | Some functions contain the same exact logic | 14 |
[N-17] | Unbounded loop may run out of gas | 6 |
[N-18] | Public functions not called internally | 75 |
[N-19] | Large multiples of ten should use scientific notation | 4 |
[N-20] | Missing/malformed underscores for large numeric literals | 5 |
[N-21] | Mixed usage of int /uint with int256 /uint256 |
25 |
[N-22] | Missing timelock in critical functions | 34 |
[N-23] | Use transfer libraries instead of low level calls | 11 |
[N-24] | Use of non-named numeric constants | 30 |
[N-25] | Complex math should be split into multiple steps | 5 |
[N-26] | Control structures do not comply with best practices | 3 |
[N-27] | Use of floating pragma | 8 |
[N-28] | No checks for empty bytes | 3 |
[N-29] | Use of abi.encodePacked instead of bytes.concat /string.concat |
4 |
[N-30] | Contract functions should use an interface |
102 |
[N-31] | require /revert without any message |
10 |
[N-32] | else block is not required |
6 |
[N-33] | Multiple address /ID mappings can be combined into a single mapping of an address /ID to a struct , for readability |
12 |
[N-34] | Lack of specific import identifier |
32 |
[N-35] | Imports should be organized more systematically | 4 |
[N-36] | Event is missing msg.sender parameter |
7 |
[N-37] | Top-level declarations should be separated by at least two lines | 10 |
[N-38] | Use a struct to encapsulate multiple function parameters | 18 |
[N-39] | Returning a struct instead of returning many variables is better | 6 |
[N-40] | Events may be emitted out of order due to reentrancy | 3 |
[N-41] | Use a modifier instead of require to check for msg.sender |
13 |
[N-42] | Don't use uppercase for non constant /immutable variables |
1 |
[N-43] | Constants in comparisons should appear on the left side | 19 |
[N-44] | Consider using delete instead of assigning zero/false to clear values |
6 |
[N-45] | Use a ternary statement instead of if /else when appropriate |
1 |
[N-46] | Consider using named mappings | 48 |
[N-47] | Layout order does not comply with best practices | 7 |
[N-48] | mapping definitions do not comply with best practices |
40 |
[N-49] | Function visibility order does not comply with best practices | 56 |
[N-50] | Long functions should be refactored into multiple functions | 1 |
[N-51] | Strings should use double quotes rather than single quotes | 4 |
[N-52] | Lines are too long | 117 |
[N-53] | Some variables have a implicit default visibility | 6 |
[N-54] | Consider adding a block/deny-list | 6 |
[N-55] | Use of override is unnecessary |
3 |
[N-56] | Typos in comments | 3 |
[N-57] | Contracts should have full test coverage | - |
[N-58] | Large or complicated code bases should implement invariant tests | - |
[N-59] | Codebase should implement formal verification testing | - |
[N-60] | Inconsistent spacing in comments | 2 |
[N-61] | State variables should include comments | 30 |
[N-62] | Use @inheritdoc for overridden functions |
4 |
[N-63] | Some contract names don't follow the Solidity naming conventions | 2 |
[N-64] | Struct names don't follow the Solidity naming convention | 8 |
[N-65] | Modifier names don't follow the Solidity naming convention | 10 |
[N-66] | Variable names don't follow the Solidity naming convention | 15 |
[N-67] | Enum names don't follow the Solidity naming convention | 8 |
[N-68] | Missing underscore prefix for non-external functions | 4 |
[N-69] | Missing underscore prefix for non-external variables | 28 |
[N-70] | Missing NatSpec from contract declarations | 8 |
[N-71] | Missing NatSpec @author from contract declaration |
8 |
[N-72] | Missing NatSpec @dev from contract declaration |
8 |
[N-73] | Missing NatSpec @notice from contract declaration |
8 |
[N-74] | Missing NatSpec @title from contract declaration |
8 |
[N-75] | Missing NatSpec from event declaration | 8 |
[N-76] | Missing NatSpec @dev from event declaration |
8 |
[N-77] | Missing NatSpec @notice from event declaration |
8 |
[N-78] | Missing NatSpec @param from event declaration |
8 |
[N-79] | Missing NatSpec from modifiers definitions | 10 |
[N-80] | Missing NatSpec @dev from modifier declaration |
10 |
[N-81] | Missing NatSpec @notice from modifier declaration |
10 |
[N-82] | Missing NatSpec @param from modifier declaration |
9 |
[N-83] | Missing NatSpec from function definitions | 110 |
[N-84] | Missing NatSpec @dev from function declaration |
110 |
[N-85] | Missing NatSpec @notice from function declaration |
110 |
[N-86] | Missing NatSpec @param from function declaration |
110 |
[N-87] | Incomplete NatSpec @return from function declaration |
46 |
Total: 1690 instances over 87 issues.
Id | Title | Instances | Gas Saved |
---|---|---|---|
[G-01] | State variables can be packed into fewer storage slots | 1 | 20,000 |
[G-02] | Structs can be packed into fewer storage slots | 3 | 60,000 |
[G-03] | Structs can be modified to fit in fewer storage slots | 1 | 20,000 |
[G-04] | Multiple mapping s that share an ID can be combined into a single mapping of ID / struct |
12 | 391,340 |
[G-05] | State variables access within a loop | 9 | 2,385 |
[G-06] | State variables only set in the constructor should be declared immutable |
5 | 100,000 |
[G-07] | Cache state variables with stack variables | 9 | 6,100 |
[G-08] | Low level call can be optimized with assembly |
11 | 2,728 |
[G-09] | Use of memory instead of calldata for immutable arguments |
13 | 8,384 |
[G-10] | Avoid updating storage when the value hasn't changed | 19 | 13,300 |
[G-11] | Use of emit inside a loop |
3 | 3,078 |
[G-12] | Shortcircuit rules can be be used to optimize some gas usage | 2 | 4,200 |
[G-13] | Cache multiple accesses of a mapping/array | 46 | 8,400 |
[G-14] | Redundant state variable getters | 2 | - |
[G-15] | Using bool for storage incurs overhead |
13 | 222,300 |
[G-16] | Custom error s cost less than require /assert |
84 | 2,436 |
[G-17] | Consider activating via-ir for deploying |
- | - |
[G-18] | Function calls should be cached instead of re-calling the function | 11 | - |
[G-19] | Functions that revert when called by normal users can be payable |
43 | 903 |
[G-20] | Array length is not cached |
8 | 24 |
[G-21] | Caching global variables is more expensive than using the actual variable | 1 | 12 |
[G-22] | Add unchecked blocks for subtractions where the operands cannot underflow |
1 | 85 |
[G-23] | Add unchecked blocks for divisions where the operands cannot overflow |
13 | 2,067 |
[G-24] | Empty blocks should be removed or emit something | 1 | 4,006 |
[G-25] | Usage of uints /ints smaller than 32 bytes (256 bits) incurs overhead |
13 | 78 |
[G-26] | Stack variable cost less while used in emiting event | 6 | 54 |
[G-27] | Using pre instead of post increments/decrements | 10 | 10 |
[G-28] | Avoid using _msgSender if not supporting EIP-2771 |
2 | 32 |
[G-29] | >= /<= costs less gas than > /< |
24 | 72 |
[G-30] | internal/private functions only called once can be inlined to save gas |
1 | 20 |
[G-31] | Boolean comparison with boolean literals is unnecessary | 69 | 621 |
[G-32] | Function names can be optimized | 8 | 176 |
[G-33] | Using delete instead of setting mapping/struct to 0 saves gas |
2 | 10 |
[G-34] | Use of += is cheaper for mappings |
8 | 320 |
[G-35] | Constructors can be marked payable |
7 | 147 |
[G-36] | Long revert strings | 7 | 126 |
[G-37] | Splitting require statements that use && saves gas |
12 | 36 |
[G-38] | Nesting if statements that use && saves gas |
11 | 330 |
[G-39] | Lack of unchecked in loops |
10 | 600 |
[G-40] | uint comparison with zero can be cheaper |
6 | 24 |
[G-41] | Use assembly to write hashes | 8 | 960 |
[G-42] | Use assembly to validate msg.sender |
25 | 300 |
[G-43] | Use assembly to write address storage values |
32 | 2,368 |
[G-44] | Use assembly to emit an event |
12 | 456 |
Total: 584 instances over 44 issues with an estimate of 878,488 gas saved.
Id | Title | Instances |
---|---|---|
[D-01] | It's possible to mint to address(0) |
1 |
[D-02] | Use an already existing Ownable implementation |
7 |
[D-03] | Using this.<fn>() wastes gas |
39 |
[D-04] | Some functions do not work correctly with fee-on-transfer tokens | 2 |
[D-05] | block.number has a different behaviour on different chains |
3 |
[D-06] | Wrong address when deploying on multiple chains |
6 |
[D-07] | Hardcoded address should be avoided |
9 |
[D-08] | Enum values should be used in place of constant array indexes | 427 |
[D-09] | Time related variables should use time units instead of numbers | 4 |
[D-10] | Upgradeable contract is missing a constructor that disables initialization | 8 |
[D-11] | Upgradeable contract is missing a gap storage variable | 8 |
[D-12] | selfbalance() is cheaper than address(this).balance |
2 |
[D-13] | Initializers could be front-run | 2 |
[D-14] | Modifier order does not comply with best practices | - |
Total: 518 instances over 14 issues.
There are some arrays that can grow indefinitely in size, as they never shrink. When these arrays are used in unbounded loops, they may lead to a permanent denial-of-service (DoS) of these functions.
POC:
- Attacker calls
participateToAuction
N times with dust amounts untilreturnHighestBid
reverts (out of gas) - When
claimAuction
is called byWinnerOrAdminRequired
, the transaction will fail, as it callsreturnHighestBid
. As a result,claimAuction
will be permanently DoS.
There are 4 instances of this issue.
File: smart-contracts/AuctionDemo.sol
// @audit function returnHighestBid is vulnerable as length grows in size but never shrinks
69: for (uint256 i=0; i< auctionInfoData[_tokenid].length; i++) {
60: auctionInfoData[_tokenid].push(newBid);
// @audit function returnHighestBidder is vulnerable as length grows in size but never shrinks
90: for (uint256 i=0; i< auctionInfoData[_tokenid].length; i++) {
60: auctionInfoData[_tokenid].push(newBid);
// @audit function claimAuction is vulnerable as length grows in size but never shrinks
110: for (uint256 i=0; i< auctionInfoData[_tokenid].length; i ++) {
60: auctionInfoData[_tokenid].push(newBid);
// @audit function cancelAllBids is vulnerable as length grows in size but never shrinks
136: for (uint256 i=0; i<auctionInfoData[_tokenid].length; i++) {
60: auctionInfoData[_tokenid].push(newBid);
The call/delegatecall
function returns a boolean value indicating whether the call was successful. However, it is important to note that this return value is not being checked in the current implementation.
As a result, there is a possibility that the call wasn't successful, while the transaction continues without reverting.
There are 11 instances of this issue.
File: smart-contracts/AuctionDemo.sol
113: (bool success, ) = payable(owner()).call{value: highestBid}("");
116: (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}("");
128: (bool success, ) = payable(auctionInfoData[_tokenid][index].bidder).call{value: auctionInfoData[_tokenid][index].bid}("");
139: (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}("");
File: smart-contracts/MinterContract.sol
434: (bool success1, ) = payable(collectionArtistPrimaryAddresses[colId].primaryAdd1).call{value: artistRoyalties1}("");
435: (bool success2, ) = payable(collectionArtistPrimaryAddresses[colId].primaryAdd2).call{value: artistRoyalties2}("");
436: (bool success3, ) = payable(collectionArtistPrimaryAddresses[colId].primaryAdd3).call{value: artistRoyalties3}("");
437: (bool success4, ) = payable(tm1).call{value: teamRoyalties1}("");
438: (bool success5, ) = payable(tm2).call{value: teamRoyalties2}("");
464: (bool success, ) = payable(admin).call{value: balance}("");
[434, 435, 436, 437, 438, 464]
File: smart-contracts/RandomizerRNG.sol
82: (bool success, ) = payable(admin).call{value: balance}("");
[82]
These functions lack a refund mechanism for excess Ether sent by the caller, resulting in locked funds within the contract. To rectify this, the function should be modified to implement a refund for any surplus amount.
There are 3 instances of this issue.
File: smart-contracts/MinterContract.sol
233: require(msg.value >= (getPrice(col) * _numberOfTokens), "Wrong ETH");
234: for(uint256 i = 0; i < _numberOfTokens; i++) {
235: uint256 mintIndex = gencore.viewTokensIndexMin(col) + gencore.viewCirSupply(col);
236: gencore.mint(mintIndex, mintingAddress, _mintTo, tokData, _saltfun_o, col, phase);
237: }
238: collectionTotalAmount[col] = collectionTotalAmount[col] + msg.value;
266: require(msg.value >= getPrice(_mintCollectionID), "Wrong ETH");
267: uint256 mintIndex = gencore.viewTokensIndexMin(_mintCollectionID) + gencore.viewCirSupply(_mintCollectionID);
268: // burn and mint token
269: address burner = msg.sender;
270: gencore.burnToMint(mintIndex, _burnCollectionID, _tokenId, _mintCollectionID, _saltfun_o, burner);
271: collectionTotalAmount[_mintCollectionID] = collectionTotalAmount[_mintCollectionID] + msg.value;
361: require(msg.value >= (getPrice(col) * 1), "Wrong ETH");
362: uint256 mintIndex = gencore.viewTokensIndexMin(col) + gencore.viewCirSupply(col);
363: gencore.mint(mintIndex, mintingAddress, ownerOfToken, tokData, _saltfun_o, col, phase);
364: collectionTotalAmount[col] = collectionTotalAmount[col] + msg.value;
There are priviliged roles that are a single point of failure, who can use critical functions, posing a centralization issue.
There is 1 instance of this issue.
File: smart-contracts/NextGenAdmins.sol
38: function registerAdmin(address _admin, bool _status) public onlyOwner {
[38]
The condition may be wrong in these cases, as when block.timestamp
is equal to the compared >
or <
variable these blocks will not be executed.
There are 3 instances of this issue.
File: smart-contracts/MinterContract.sol
540: } else if (collectionPhases[_collectionId].salesOption == 2 && block.timestamp > collectionPhases[_collectionId].allowlistStartTime && block.timestamp < collectionPhases[_collectionId].publicEndTime){
540: } else if (collectionPhases[_collectionId].salesOption == 2 && block.timestamp > collectionPhases[_collectionId].allowlistStartTime && block.timestamp < collectionPhases[_collectionId].publicEndTime){
File: smart-contracts/NextGenCore.sol
308: require (block.timestamp > IMinterContract(minterContract).getEndTime(_collectionID) + collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint, "Time has not passed");
[308]
There are some missing checks in these functions, and this could lead to unexpected scenarios. Consider always adding a sanity check for state variables.
There are 3 instances of this issue.
File: smart-contracts/MinterContract.sol
// @audit _burnCollectionID, _mintCollectionID
308: function initializeBurn(uint256 _burnCollectionID, uint256 _mintCollectionID, bool _status) public FunctionAdminRequired(this.initializeBurn.selector) {
// @audit _burnCollectionID, _mintCollectionID, _tokmin, _tokmax
315: function initializeExternalBurnOrSwap(address _erc721Collection, uint256 _burnCollectionID, uint256 _mintCollectionID, uint256 _tokmin, uint256 _tokmax, address _burnOrSwapAddress, bool _status) public FunctionAdminRequired(this.initializeExternalBurnOrSwap.selector) {
File: smart-contracts/RandomizerVRF.sol
// @audit subscriptionId
39: constructor(uint64 subscriptionId, address vrfCoordinator, address _gencore, address _adminsContract) VRFConsumerBaseV2(vrfCoordinator) {
[39]
There are some missing checks in these functions, and this could lead to unexpected scenarios. Consider always adding a sanity check for state variables.
There are 31 instances of this issue.
Expand findings
File: smart-contracts/MinterContract.sol
165: setMintingCosts[_collectionID] = true;
238: collectionTotalAmount[col] = collectionTotalAmount[col] + msg.value;
271: collectionTotalAmount[_mintCollectionID] = collectionTotalAmount[_mintCollectionID] + msg.value;
296: mintToAuctionData[mintIndex] = _auctionEndTime;
297: mintToAuctionStatus[mintIndex] = true;
364: collectionTotalAmount[col] = collectionTotalAmount[col] + msg.value;
[165, 238, 271, 296, 297, 364]
File: smart-contracts/NextGenAdmins.sol
60: collectionAdmin[_address][_collectionID] = _status;
[60]
File: smart-contracts/NextGenCore.sol
157: wereDataAdded[_collectionID] = true;
183: tokensAirdropPerAddress[_collectionID][_recipient] = tokensAirdropPerAddress[_collectionID][_recipient] + 1;
195: tokensMintedAllowlistAddress[_collectionID][_mintingAddress] = tokensMintedAllowlistAddress[_collectionID][_mintingAddress] + 1;
197: tokensMintedPerAddress[_collectionID][_mintingAddress] = tokensMintedPerAddress[_collectionID][_mintingAddress] + 1;
208: burnAmount[_collectionID] = burnAmount[_collectionID] + 1;
221: burnAmount[_burnCollectionID] = burnAmount[_burnCollectionID] + 1;
228: tokenData[_mintIndex] = _tokenData;
230: tokenIdsToCollectionIds[_mintIndex] = _collectionID;
260: artistsSignatures[_collectionID] = _signature;
268: onchainMetadata[_collectionID] = _status;
276: tokenData[_tokenId] = newData;
294: collectionFreeze[_collectionID] = true;
[157, 183, 195, 197, 208, 221, 228, 230, 260, 268, 276, 294]
File: smart-contracts/RandomizerRNG.sol
43: tokenToRequest[tokenid] = requestId;
44: requestToToken[requestId] = tokenid;
55: tokenIdToCollection[_mintIndex] = _collectionID;
74: ethRequired = _ethRequired;
File: smart-contracts/RandomizerVRF.sol
61: tokenToRequest[tokenid] = requestId;
62: requestToToken[requestId] = tokenid;
73: tokenIdToCollection[_mintIndex] = _collectionID;
80: callbackGasLimit = _callbackGasLimit;
81: keyHash = _keyHash;
87: s_subscriptionId = _s_subscriptionId;
88: numWords = _numWords;
89: requestConfirmations = _requestConfirmations;
The following functions can be called by any user, who may also send some funds by mistake. In that case, those funds will be lost.
There is 1 instance of this issue.
File: smart-contracts/RandomizerRNG.sol
86: receive() external payable {}
[86]
Even if the function follows the best practice of check-effects-interaction, not using a reentrancy guard when there may be transfer hooks will open the users of this protocol up to read-only reentrancies with no way to protect against it, except by block-listing the whole protocol.
There is 1 instance of this issue.
File: smart-contracts/MinterContract.sol
340: IERC721(_erc721Collection).safeTransferFrom(ownerOfToken, burnOrSwapAddress[externalCol], _tokenId);
[340]
To ensure clarity regarding the ownership of the NFT on a specific chain, it is recommended to add require(block.chainid == 1, "Invalid Chain")
or the desired chain ID in the functions below.
Alternatively, consider including the chain ID in the URI itself. By doing so, any confusion regarding the chain responsible for owning the NFT will be eliminated.
There is 1 instance of this issue.
File: smart-contracts/NextGenCore.sol
343: function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
344: _requireMinted(tokenId);
345: if (onchainMetadata[tokenIdsToCollectionIds[tokenId]] == false && tokenToHash[tokenId] != 0x0000000000000000000000000000000000000000000000000000000000000000) {
346: string memory baseURI = collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionBaseURI;
347: return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
348: } else if (onchainMetadata[tokenIdsToCollectionIds[tokenId]] == false && tokenToHash[tokenId] == 0x0000000000000000000000000000000000000000000000000000000000000000) {
349: string memory baseURI = collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionBaseURI;
350: return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, "pending")) : "";
351: }
352: else {
353: string memory b64 = Base64.encode(abi.encodePacked("<html><head></head><body><script src=\"",collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionLibrary,"\"></script><script>",retrieveGenerativeScript(tokenId),"</script></body></html>"));
354: string memory _uri = string(abi.encodePacked("data:application/json;utf8,{\"name\":\"",getTokenName(tokenId),"\",\"description\":\"",collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionDescription,"\",\"image\":\"",tokenImageAndAttributes[tokenId][0],"\",\"attributes\":[",tokenImageAndAttributes[tokenId][1],"],\"animation_url\":\"data:text/html;base64,",b64,"\"}"));
355: return _uri;
356: }
357: }
[343-357]
Lately, there has been a rise in cases where NFTs are being stolen. These stolen NFTs are then added to platforms, allowing them to be easily converted into liquidity.
Some popular marketplaces, such as Opensea, have already taken steps to combat this issue by introducing a disallowlist feature. This means that if an NFT is reported as stolen, it won't be listed or sold on their platform.
This may increase the project centralization, but it can help solve this problem, if this issue is a concern.
There is 1 instance of this issue.
File: smart-contracts/NextGenCore.sol
22: contract NextGenCore is ERC721Enumerable, Ownable, ERC2981 {
[22]
If the length of the arrays are not required to be of the same length, user operations may not be fully executed.
There are 2 instances of this issue.
File: smart-contracts/MinterContract.sol
// @audit _numberOfTokens, _recipients, _tokenData, _saltfun_o
181: function airDropTokens(address[] memory _recipients, string[] memory _tokenData, uint256[] memory _saltfun_o, uint256 _collectionID, uint256[] memory _numberOfTokens) public FunctionAdminRequired(this.airDropTokens.selector) {
[181]
File: smart-contracts/NextGenCore.sol
// @audit _tokenId, _images, _attributes
281: function updateImagesAndAttributes(uint256[] memory _tokenId, string[] memory _images, string[] memory _attributes) public FunctionAdminRequired(this.updateImagesAndAttributes.selector) {
[281]
Some state variables are shadowed by local variables/function parameters, this might result in the use of the wrong variable, in some scenarios. Consider renaming these variables with a different name.
There is 1 instance of this issue.
File: smart-contracts/RandomizerVRF.sol
// @audit vrfCoordinator inherited from VRFConsumerBaseV2
39: constructor(uint64 subscriptionId, address vrfCoordinator, address _gencore, address _adminsContract) VRFConsumerBaseV2(vrfCoordinator) {
[39]
The following expressions may underflow, as the subtrahend could be greater than the minuend in case the former is multiplied by a large number.
There are 2 instances of this issue.
File: smart-contracts/MinterContract.sol
551: decreaserate = ((price - (collectionPhases[_collectionId].collectionMintCost / (tDiff + 2))) / collectionPhases[_collectionId].timePeriod) * ((block.timestamp - (tDiff * collectionPhases[_collectionId].timePeriod) - collectionPhases[_collectionId].allowlistStartTime));
554: price = collectionPhases[_collectionId].collectionMintCost - (tDiff * collectionPhases[_collectionId].rate);
Code should follow the best-practice of CEI, where state variables are updated before any external calls are made. Doing so prevents a large class of reentrancy bugs.
There are 22 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
// @audit minter.getAuctionEndTime(_tokenid) called on line 105
106: auctionClaim[_tokenid] = true;
[106]
File: smart-contracts/MinterContract.sol
// @audit gencore.retrievewereDataAdded(_collectionID) called on line 158
165: setMintingCosts[_collectionID] = true;
// @audit dmc.retrieveGlobalStatusOfDelegation(_delegator, 0x8888888888888888888888888888888888888888, msg.sender, 1) called on line 207
238: collectionTotalAmount[col] = collectionTotalAmount[col] + msg.value;
// @audit dmc.retrieveGlobalStatusOfDelegation(_delegator, 0x8888888888888888888888888888888888888888, msg.sender, 1) called on line 207
252: lastMintDate[col] = collectionPhases[col].allowlistStartTime + (collectionPhases[col].timePeriod * (gencore.viewCirSupply(col) - 1));
// @audit gencore.viewTokensIndexMin(_burnCollectionID) called on line 261
271: collectionTotalAmount[_mintCollectionID] = collectionTotalAmount[_mintCollectionID] + msg.value;
// @audit gencore.retrievewereDataAdded(_collectionID) called on line 277
295: lastMintDate[_collectionID] = collectionPhases[_collectionID].allowlistStartTime + (collectionPhases[_collectionID].timePeriod * (gencore.viewCirSupply(_collectionID) - 1));
// @audit gencore.retrievewereDataAdded(_collectionID) called on line 277
296: mintToAuctionData[mintIndex] = _auctionEndTime;
// @audit gencore.retrievewereDataAdded(_collectionID) called on line 277
297: mintToAuctionStatus[mintIndex] = true;
// @audit gencore.retrievewereDataAdded(_burnCollectionID) called on line 309
310: burnToMintCollections[_burnCollectionID][_mintCollectionID] = _status;
// @audit gencore.retrievewereDataAdded(_mintCollectionID) called on line 317
318: burnExternalToMintCollections[externalCol][_mintCollectionID] = _status;
// @audit gencore.retrievewereDataAdded(_mintCollectionID) called on line 317
319: burnOrSwapAddress[externalCol] = _burnOrSwapAddress;
// @audit gencore.retrievewereDataAdded(_mintCollectionID) called on line 317
320: burnOrSwapIds[externalCol][0] = _tokmin;
// @audit gencore.retrievewereDataAdded(_mintCollectionID) called on line 317
321: burnOrSwapIds[externalCol][1] = _tokmax;
// @audit IERC721(_erc721Collection).ownerOf(_tokenId) called on line 330
364: collectionTotalAmount[col] = collectionTotalAmount[col] + msg.value;
// @audit INextGenAdmins(_newadminsContract).isAdminContract() called on line 455
456: adminsContract = INextGenAdmins(_newadminsContract);
[165, 238, 252, 271, 295, 296, 297, 310, 318, 319, 320, 321, 364, 456]
File: smart-contracts/NextGenCore.sol
// @audit collectionAdditionalData[_collectionID].randomizer.calculateTokenHash(_collectionID, _mintIndex, _saltfun_o) called on line 229
230: tokenIdsToCollectionIds[_mintIndex] = _collectionID;
// @audit IMinterContract(_minterContract).isMinterContract() called on line 316
317: minterContract = _minterContract;
// @audit INextGenAdmins(_newadminsContract).isAdminContract() called on line 323
324: adminsContract = INextGenAdmins(_newadminsContract);
File: smart-contracts/RandomizerRNG.sol
// @audit INextGenAdmins(_newadminsContract).isAdminContract() called on line 62
63: adminsContract = INextGenAdmins(_newadminsContract);
[63]
File: smart-contracts/RandomizerVRF.sol
// @audit COORDINATOR.requestRandomWords(
keyHash,
s_subscriptionId,
requestConfirmations,
callbackGasLimit,
numWords
) called on line 54
61: tokenToRequest[tokenid] = requestId;
// @audit COORDINATOR.requestRandomWords(
keyHash,
s_subscriptionId,
requestConfirmations,
callbackGasLimit,
numWords
) called on line 54
62: requestToToken[requestId] = tokenid;
// @audit INextGenAdmins(_newadminsContract).isAdminContract() called on line 95
96: adminsContract = INextGenAdmins(_newadminsContract);
There are some missing limits in these functions, and this could lead to unexpected scenarios. Consider adding a min/max limit for the following values, when appropriate.
There are 12 instances of this issue.
Expand findings
File: smart-contracts/MinterContract.sol
// @audit missing both checks -> _collectionID, _collectionMintCost, _collectionEndMintCost, _rate, _timePeriod, _salesOption
157: function setCollectionCosts(uint256 _collectionID, uint256 _collectionMintCost, uint256 _collectionEndMintCost, uint256 _rate, uint256 _timePeriod, uint8 _salesOption, address _delAddress) public CollectionAdminRequired(_collectionID, this.setCollectionCosts.selector) {
// @audit missing both checks -> _collectionID, _allowlistStartTime, _allowlistEndTime, _publicStartTime, _publicEndTime
170: function setCollectionPhases(uint256 _collectionID, uint _allowlistStartTime, uint _allowlistEndTime, uint _publicStartTime, uint _publicEndTime, bytes32 _merkleRoot) public CollectionAdminRequired(_collectionID, this.setCollectionPhases.selector) {
// @audit missing both checks -> _collectionID
302: function updateDelegationCollection(uint256 _collectionID, address _collectionAddress) public FunctionAdminRequired(this.updateDelegationCollection.selector) {
// @audit missing both checks -> _collectionID, _artistPrSplit, _teamPrSplit, _artistSecSplit, _teamSecSplit
369: function setPrimaryAndSecondarySplits(uint256 _collectionID, uint256 _artistPrSplit, uint256 _teamPrSplit, uint256 _artistSecSplit, uint256 _teamSecSplit) public FunctionAdminRequired(this.setPrimaryAndSecondarySplits.selector) {
File: smart-contracts/NextGenCore.sol
// @audit missing both checks -> _collectionID, _maxCollectionPurchases, _collectionTotalSupply, _setFinalSupplyTimeAfterMint
147: function setCollectionData(uint256 _collectionID, address _collectionArtistAddress, uint256 _maxCollectionPurchases, uint256 _collectionTotalSupply, uint _setFinalSupplyTimeAfterMint) public CollectionAdminRequired(_collectionID, this.setCollectionData.selector) {
// @audit missing both checks -> _collectionID, _index
238: function updateCollectionInfo(uint256 _collectionID, string memory _newCollectionName, string memory _newCollectionArtist, string memory _newCollectionDescription, string memory _newCollectionWebsite, string memory _newCollectionLicense, string memory _newCollectionBaseURI, string memory _newCollectionLibrary, uint256 _index, string[] memory _newCollectionScript) public CollectionAdminRequired(_collectionID, this.updateCollectionInfo.selector) {
// @audit missing both checks -> _collectionID, _mintIndex
299: function setTokenHash(uint256 _collectionID, uint256 _mintIndex, bytes32 _hash) external {
// @audit missing both checks -> _collectionID
307: function setFinalSupply(uint256 _collectionID) public FunctionAdminRequired(this.setFinalSupply.selector) {
// @audit missing both checks -> _bps
329: function setDefaultRoyalties(address _royaltyAddress, uint96 _bps) public FunctionAdminRequired(this.setDefaultRoyalties.selector) {
File: smart-contracts/RandomizerRNG.sol
// @audit missing both checks -> _ethRequired
73: function updateRNGCost(uint256 _ethRequired) public FunctionAdminRequired(this.updateRNGCost.selector) {
[73]
File: smart-contracts/RandomizerVRF.sol
// @audit missing both checks -> _callbackGasLimit
79: function updatecallbackGasLimitAndkeyHash(uint32 _callbackGasLimit, bytes32 _keyHash) public FunctionAdminRequired(this.updatecallbackGasLimitAndkeyHash.selector){
// @audit missing both checks -> _s_subscriptionId, _numWords, _requestConfirmations
86: function updateAdditionalData(uint64 _s_subscriptionId, uint32 _numWords, uint16 _requestConfirmations) public FunctionAdminRequired(this.updateAdditionalData.selector){
Each of the following contracts implements or inherits the renounceOwnership
function. This can represent a certain risk if the ownership is renounced for any other reason than by design. Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.
There are 6 instances of this issue.
File: smart-contracts/AuctionDemo.sol
18: contract auctionDemo is Ownable {
[18]
File: smart-contracts/MinterContract.sol
20: contract NextGenMinterContract is Ownable {
[20]
File: smart-contracts/NextGenAdmins.sol
15: contract NextGenAdmins is Ownable{
[15]
File: smart-contracts/NextGenCore.sol
22: contract NextGenCore is ERC721Enumerable, Ownable, ERC2981 {
[22]
File: smart-contracts/RandomizerRNG.sol
18: contract NextGenRandomizerRNG is ArrngConsumer, Ownable {
[18]
File: smart-contracts/RandomizerVRF.sol
19: contract NextGenRandomizerVRF is VRFConsumerBaseV2, Ownable {
[19]
Consider limiting the number of iterations in loops that make external calls, as just a single one of them failing will result in a revert.
There are 3 instances of this issue.
File: smart-contracts/AuctionDemo.sol
// @audit safeTransferFrom (112)
110: for (uint256 i=0; i< auctionInfoData[_tokenid].length; i ++) {
[110]
File: smart-contracts/MinterContract.sol
// @audit viewTokensIndexMin (185), viewCirSupply (185), viewTokensIndexMax (186), viewTokensIndexMin (188), viewCirSupply (188), airDropTokens (189)
184: for (uint256 y=0; y< _recipients.length; y++) {
// @audit viewTokensIndexMin (235), viewCirSupply (235), mint (236)
234: for(uint256 i = 0; i < _numberOfTokens; i++) {
A single step ownership change is risky due to the fact that the new owner address could be wrong.
Instead, consider using a contract like Ownable2Step, which provides a two-step ownership.
There are 7 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
15: import "./Ownable.sol";
[15]
File: smart-contracts/MinterContract.sol
14: import "./Ownable.sol";
[14]
File: smart-contracts/NextGenAdmins.sol
13: import "./Ownable.sol";
[13]
File: smart-contracts/NextGenCore.sol
14: import "./Ownable.sol";
[14]
File: smart-contracts/RandomizerNXT.sol
15: import "./Ownable.sol";
[15]
File: smart-contracts/RandomizerRNG.sol
14: import "./Ownable.sol";
[14]
File: smart-contracts/RandomizerVRF.sol
15: import "./Ownable.sol";
[15]
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.
There is 1 instance of this issue.
File: smart-contracts/RandomizerNXT.sol
57: bytes32 hash = keccak256(abi.encodePacked(_mintIndex, blockhash(block.number - 1), randoms.randomNumber(), randoms.randomWord()));
[57]
Solidity doesn't support fractions, so divisions by large numbers could result in the quotient being zero.
To avoid this, it's recommended to require a minimum numerator amount to ensure that it is always greater than the denominator.
There are 8 instances of this issue.
File: smart-contracts/MinterContract.sol
249: uint tDiff = (block.timestamp - timeOfLastMint) / collectionPhases[col].timePeriod;
292: uint tDiff = (block.timestamp - timeOfLastMint) / collectionPhases[_collectionID].timePeriod;
536: return collectionPhases[_collectionId].collectionMintCost + ((collectionPhases[_collectionId].collectionMintCost / collectionPhases[_collectionId].rate) * gencore.viewCirSupply(_collectionId));
546: tDiff = (block.timestamp - collectionPhases[_collectionId].allowlistStartTime) / collectionPhases[_collectionId].timePeriod;
550: price = collectionPhases[_collectionId].collectionMintCost / (tDiff + 1);
551: decreaserate = ((price - (collectionPhases[_collectionId].collectionMintCost / (tDiff + 2))) / collectionPhases[_collectionId].timePeriod) * ((block.timestamp - (tDiff * collectionPhases[_collectionId].timePeriod) - collectionPhases[_collectionId].allowlistStartTime));
551: decreaserate = ((price - (collectionPhases[_collectionId].collectionMintCost / (tDiff + 2))) / collectionPhases[_collectionId].timePeriod) * ((block.timestamp - (tDiff * collectionPhases[_collectionId].timePeriod) - collectionPhases[_collectionId].allowlistStartTime));
553: if (((collectionPhases[_collectionId].collectionMintCost - collectionPhases[_collectionId].collectionEndMintCost) / (collectionPhases[_collectionId].rate)) > tDiff) {
[249, 292, 536, 546, 550, 551, 551, 553]
A low-level call will copy any amount of bytes to local memory. When bytes are copied from returndata to memory, the memory expansion cost is paid.
This means that when using a standard solidity call, the callee can 'returnbomb' the caller, imposing an arbitrary gas cost.
Because this gas is paid by the caller and in the caller's context, it can cause the caller to run out of gas and halt execution.
Consider replacing all unsafe call
with excessivelySafeCall
from this repository.
There are 8 instances of this issue.
File: smart-contracts/AuctionDemo.sol
116: (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}("");
128: (bool success, ) = payable(auctionInfoData[_tokenid][index].bidder).call{value: auctionInfoData[_tokenid][index].bid}("");
139: (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}("");
File: smart-contracts/MinterContract.sol
434: (bool success1, ) = payable(collectionArtistPrimaryAddresses[colId].primaryAdd1).call{value: artistRoyalties1}("");
435: (bool success2, ) = payable(collectionArtistPrimaryAddresses[colId].primaryAdd2).call{value: artistRoyalties2}("");
436: (bool success3, ) = payable(collectionArtistPrimaryAddresses[colId].primaryAdd3).call{value: artistRoyalties3}("");
437: (bool success4, ) = payable(tm1).call{value: teamRoyalties1}("");
438: (bool success5, ) = payable(tm2).call{value: teamRoyalties2}("");
As these arrays cannot shrink, if the array has a maximum size, it won't be possible to change its elements once it reaches that size. Otherwise, it can grow indefinitely in size, which can increase the likelihood of out-of-gas errors.
There is 1 instance of this issue.
File: smart-contracts/AuctionDemo.sol
60: auctionInfoData[_tokenid].push(newBid);
[60]
The owner
is able to perform certain privileged activities, but it's possible to set the owner to address(0)
. This can represent a certain risk if the ownership is renounced for any other reason than by design.
Renouncing ownership will leave the contract without an owner
, therefore limiting any functionality that needs authority.
There is 1 instance of this issue.
File: smart-contracts/NextGenAdmins.sol
38: function registerAdmin(address _admin, bool _status) public onlyOwner {
[38]
Users may send ETH by mistake to these contracts. As there is no access control on these functions, the funds will be permanently lost.
There is 1 instance of this issue.
File: smart-contracts/RandomizerRNG.sol
86: receive() external payable {}
[86]
If the intention is for the ETH to be used, the function should call another function, otherwise it should revert (e.g. require(msg.sender == address(weth))
)
There is 1 instance of this issue.
File: smart-contracts/RandomizerRNG.sol
86: receive() external payable {}
[86]
Check for zero-address to avoid the risk of setting address(0)
for state variables when deploying.
There are 16 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
// @audit _minter
37: minter = IMinterContract(_minter);
// @audit _gencore
38: gencore = _gencore;
// @audit _adminsContract
39: adminsContract = INextGenAdmins(_adminsContract);
File: smart-contracts/MinterContract.sol
// @audit _gencore
130: gencore = INextGenCore(_gencore);
// @audit _del
131: dmc = IDelegationManagementContract(_del);
// @audit _adminsContract
132: adminsContract = INextGenAdmins(_adminsContract);
// @audit _burnOrSwapAddress
319: burnOrSwapAddress[externalCol] = _burnOrSwapAddress;
File: smart-contracts/NextGenCore.sol
// @audit _adminsContract
109: adminsContract = INextGenAdmins(_adminsContract);
[109]
File: smart-contracts/RandomizerNXT.sol
// @audit _randoms
26: randoms = IXRandoms(_randoms);
// @audit _admin
27: adminsContract = INextGenAdmins(_admin);
// @audit _gencore
28: gencore = _gencore;
File: smart-contracts/RandomizerRNG.sol
// @audit _gencore
30: gencore = _gencore;
// @audit _adminsContract
32: adminsContract = INextGenAdmins(_adminsContract);
File: smart-contracts/RandomizerVRF.sol
// @audit vrfCoordinator
40: COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator);
// @audit _gencore
42: gencore = _gencore;
// @audit _adminsContract
44: adminsContract = INextGenAdmins(_adminsContract);
Check for zero-address to avoid the risk of setting address(0)
for state variables after an update.
There are 17 instances of this issue.
Expand findings
File: smart-contracts/MinterContract.sol
// @audit _gencore
449: gencore = INextGenCore(_gencore);
// @audit _newadminsContract
456: adminsContract = INextGenAdmins(_newadminsContract);
File: smart-contracts/NextGenAdmins.sol
// @audit _admin
39: adminPermissions[_admin] = _status;
// @audit _address
45: functionAdmin[_address][_selector] = _status;
// @audit _address
52: functionAdmin[_address][_selector[i]] = _status;
// @audit _address
60: collectionAdmin[_address][_collectionID] = _status;
File: smart-contracts/NextGenCore.sol
// @audit _recipient
183: tokensAirdropPerAddress[_collectionID][_recipient] = tokensAirdropPerAddress[_collectionID][_recipient] + 1;
// @audit _mintingAddress
195: tokensMintedAllowlistAddress[_collectionID][_mintingAddress] = tokensMintedAllowlistAddress[_collectionID][_mintingAddress] + 1;
// @audit _minterContract
317: minterContract = _minterContract;
// @audit _newadminsContract
324: adminsContract = INextGenAdmins(_newadminsContract);
File: smart-contracts/RandomizerNXT.sol
// @audit _randoms
42: randoms = IXRandoms(_randoms);
// @audit _admin
46: adminsContract = INextGenAdmins(_admin);
// @audit _gencore
50: gencore = _gencore;
File: smart-contracts/RandomizerRNG.sol
// @audit _newadminsContract
63: adminsContract = INextGenAdmins(_newadminsContract);
// @audit _gencore
67: gencore = _gencore;
File: smart-contracts/RandomizerVRF.sol
// @audit _newadminsContract
96: adminsContract = INextGenAdmins(_newadminsContract);
// @audit _gencore
100: gencore = _gencore;
ERC721A is an implementation of IERC721 with significant gas savings for minting multiple NFTs in a single transaction.
There is 1 instance of this issue.
File: smart-contracts/NextGenCore.sol
22: contract NextGenCore is ERC721Enumerable, Ownable, ERC2981 {
[22]
Custom errors are available from solidity version 0.8.4. Custom errors are more easily processed in try-catch blocks, and are easier to re-use and maintain.
There are 84 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
32: require(msg.sender == returnHighestBidder(_tokenId) || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
58: require(msg.value > returnHighestBid(_tokenid) && block.timestamp <= minter.getAuctionEndTime(_tokenid) && minter.getAuctionStatus(_tokenid) == true);
105: require(block.timestamp >= minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true);
125: require(block.timestamp <= minter.getAuctionEndTime(_tokenid), "Auction ended");
126: require(auctionInfoData[_tokenid][index].bidder == msg.sender && auctionInfoData[_tokenid][index].status == true);
135: require(block.timestamp <= minter.getAuctionEndTime(_tokenid), "Auction ended");
File: smart-contracts/MinterContract.sol
137: require(msg.sender == gencore.retrieveArtistAddress(_collectionID) || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
144: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
151: require(adminsContract.retrieveCollectionAdmin(msg.sender,_collectionID) == true || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
158: require(gencore.retrievewereDataAdded(_collectionID) == true, "Add data");
171: require(setMintingCosts[_collectionID] == true, "Set Minting Costs");
182: require(gencore.retrievewereDataAdded(_collectionID) == true, "Add data");
186: require(collectionTokenMintIndex <= gencore.viewTokensIndexMax(_collectionID), "No supply");
197: require(setMintingCosts[_collectionID] == true, "Set Minting Costs");
211: require(isAllowedToMint == true, "No delegation");
213: require(_maxAllowance >= gencore.retrieveTokensMintedALPerAddress(col, _delegator) + _numberOfTokens, "AL limit");
217: require(_maxAllowance >= gencore.retrieveTokensMintedALPerAddress(col, msg.sender) + _numberOfTokens, "AL limit");
220: require(MerkleProof.verifyCalldata(merkleProof, collectionPhases[col].merkleRoot, node), 'invalid proof');
223: require(_numberOfTokens <= gencore.viewMaxAllowance(col), "Change no of tokens");
224: require(gencore.retrieveTokensMintedPublicPerAddress(col, msg.sender) + _numberOfTokens <= gencore.viewMaxAllowance(col), "Max");
232: require(collectionTokenMintIndex <= gencore.viewTokensIndexMax(col), "No supply");
233: require(msg.value >= (getPrice(col) * _numberOfTokens), "Wrong ETH");
251: require(tDiff>=1 && _numberOfTokens == 1, "1 mint/period");
259: require(burnToMintCollections[_burnCollectionID][_mintCollectionID] == true, "Initialize burn");
260: require(block.timestamp >= collectionPhases[_mintCollectionID].publicStartTime && block.timestamp<=collectionPhases[_mintCollectionID].publicEndTime,"No minting");
261: require ((_tokenId >= gencore.viewTokensIndexMin(_burnCollectionID)) && (_tokenId <= gencore.viewTokensIndexMax(_burnCollectionID)), "col/token id error");
265: require(collectionTokenMintIndex <= gencore.viewTokensIndexMax(_mintCollectionID), "No supply");
266: require(msg.value >= getPrice(_mintCollectionID), "Wrong ETH");
277: require(gencore.retrievewereDataAdded(_collectionID) == true, "Add data");
280: require(collectionTokenMintIndex <= gencore.viewTokensIndexMax(_collectionID), "No supply");
294: require(tDiff>=1, "1 mint/period");
309: require((gencore.retrievewereDataAdded(_burnCollectionID) == true) && (gencore.retrievewereDataAdded(_mintCollectionID) == true), "No data");
317: require((gencore.retrievewereDataAdded(_mintCollectionID) == true), "No data");
328: require(burnExternalToMintCollections[externalCol][_mintCollectionID] == true, "Initialize external burn");
329: require(setMintingCosts[_mintCollectionID] == true, "Set Minting Costs");
337: require(isAllowedToMint == true, "No delegation");
339: require(_tokenId >= burnOrSwapIds[externalCol][0] && _tokenId <= burnOrSwapIds[externalCol][1], "Token id does not match");
350: require(MerkleProof.verifyCalldata(merkleProof, collectionPhases[col].merkleRoot, node), 'invalid proof');
360: require(collectionTokenMintIndex <= gencore.viewTokensIndexMax(col), "No supply");
361: require(msg.value >= (getPrice(col) * 1), "Wrong ETH");
370: require(_artistPrSplit + _teamPrSplit == 100, "splits need to be 100%");
371: require(_artistSecSplit + _teamSecSplit == 100, "splits need to be 100%");
381: require (collectionArtistPrimaryAddresses[_collectionID].status == false, "Already approved");
382: require (_add1Percentage + _add2Percentage + _add3Percentage == collectionRoyaltiesPrimarySplits[_collectionID].artistPercentage, "Check %");
395: require (collectionArtistSecondaryAddresses[_collectionID].status == false, "Already approved");
396: require (_add1Percentage + _add2Percentage + _add3Percentage == collectionRoyaltiesSecondarySplits[_collectionID].artistPercentage, "Check %");
416: require(collectionArtistPrimaryAddresses[_collectionID].status == true, "Accept Royalties");
417: require(collectionTotalAmount[_collectionID] > 0, "Collection Balance must be grater than 0");
418: require(collectionRoyaltiesPrimarySplits[_collectionID].artistPercentage + _teamperc1 + _teamperc2 == 100, "Change percentages");
455: require(INextGenAdmins(_newadminsContract).isAdminContract() == true, "Contract is not Admin");
[137, 144, 151, 158, 171, 182, 186, 197, 211, 213, 217, 220, 223, 224, 232, 233, 251, 259, 260, 261, 265, 266, 277, 280, 294, 309, 317, 328, 329, 337, 339, 350, 360, 361, 370, 371, 381, 382, 395, 396, 416, 417, 418, 455]
File: smart-contracts/NextGenAdmins.sol
32: require((adminPermissions[msg.sender] == true) || (_msgSender()== owner()), "Not allowed");
59: require(_collectionID > 0, "Collection Id must be larger than 0");
File: smart-contracts/NextGenCore.sol
117: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
124: require(adminsContract.retrieveCollectionAdmin(msg.sender,_collectionID) == true || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
148: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false) && (_collectionTotalSupply <= 10000000000), "err/freezed");
171: require(IRandomizer(_randomizerContract).isRandomizerContract() == true, "Contract is not Randomizer");
179: require(msg.sender == minterContract, "Caller is not the Minter Contract");
190: require(msg.sender == minterContract, "Caller is not the Minter Contract");
205: require(_isApprovedOrOwner(_msgSender(), _tokenId), "ERC721: caller is not token owner or approved");
206: require ((_tokenId >= collectionAdditionalData[_collectionID].reservedMinTokensIndex) && (_tokenId <= collectionAdditionalData[_collectionID].reservedMaxTokensIndex), "id err");
214: require(msg.sender == minterContract, "Caller is not the Minter Contract");
215: require(_isApprovedOrOwner(burner, _tokenId), "ERC721: caller is not token owner or approved");
239: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false), "Not allowed");
258: require(msg.sender == collectionAdditionalData[_collectionID].collectionArtistAddress, "Only artist");
259: require(artistSigned[_collectionID] == false, "Already Signed");
267: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false), "Not allowed");
274: require(collectionFreeze[tokenIdsToCollectionIds[_tokenId]] == false, "Data frozen");
283: require(collectionFreeze[tokenIdsToCollectionIds[_tokenId[x]]] == false, "Data frozen");
293: require(isCollectionCreated[_collectionID] == true, "No Col");
300: require(msg.sender == collectionAdditionalData[_collectionID].randomizerContract);
301: require(tokenToHash[_mintIndex] == 0x0000000000000000000000000000000000000000000000000000000000000000);
308: require (block.timestamp > IMinterContract(minterContract).getEndTime(_collectionID) + collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint, "Time has not passed");
316: require(IMinterContract(_minterContract).isMinterContract() == true, "Contract is not Minter");
323: require(INextGenAdmins(_newadminsContract).isAdminContract() == true, "Contract is not Admin");
[117, 124, 148, 171, 179, 190, 205, 206, 214, 215, 239, 258, 259, 267, 274, 283, 293, 300, 301, 308, 316, 323]
File: smart-contracts/RandomizerNXT.sol
35: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
56: require(msg.sender == gencore);
File: smart-contracts/RandomizerRNG.sol
36: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
41: require(msg.sender == gencore);
54: require(msg.sender == gencore);
62: require(INextGenAdmins(_newadminsContract).isAdminContract() == true, "Contract is not Admin");
File: smart-contracts/RandomizerVRF.sol
48: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
53: require(msg.sender == gencore);
72: require(msg.sender == gencore);
95: require(INextGenAdmins(_newadminsContract).isAdminContract() == true, "Contract is not Admin");
Consider breaking down these blocks into more manageable units, by splitting things into utility functions, by reducing nesting, and by using early returns.
There is 1 instance of this issue.
File: smart-contracts/MinterContract.sol
196: function mint(uint256 _collectionID, uint256 _numberOfTokens, uint256 _maxAllowance, string memory _tokenData, address _mintTo, bytes32[] calldata merkleProof, address _delegator, uint256 _saltfun_o) public payable {
[196]
Events should be emitted when sensitive changes are made to the contracts, but some functions lack them.
There are 23 instances of this issue.
Expand findings
File: smart-contracts/MinterContract.sol
157: function setCollectionCosts(uint256 _collectionID, uint256 _collectionMintCost, uint256 _collectionEndMintCost, uint256 _rate, uint256 _timePeriod, uint8 _salesOption, address _delAddress) public CollectionAdminRequired(_collectionID, this.setCollectionCosts.selector) {
158: require(gencore.retrievewereDataAdded(_collectionID) == true, "Add data");
159: collectionPhases[_collectionID].collectionMintCost = _collectionMintCost;
160: collectionPhases[_collectionID].collectionEndMintCost = _collectionEndMintCost;
161: collectionPhases[_collectionID].rate = _rate;
162: collectionPhases[_collectionID].timePeriod = _timePeriod;
163: collectionPhases[_collectionID].salesOption = _salesOption;
164: collectionPhases[_collectionID].delAddress = _delAddress;
165: setMintingCosts[_collectionID] = true;
166: }
170: function setCollectionPhases(uint256 _collectionID, uint _allowlistStartTime, uint _allowlistEndTime, uint _publicStartTime, uint _publicEndTime, bytes32 _merkleRoot) public CollectionAdminRequired(_collectionID, this.setCollectionPhases.selector) {
171: require(setMintingCosts[_collectionID] == true, "Set Minting Costs");
172: collectionPhases[_collectionID].allowlistStartTime = _allowlistStartTime;
173: collectionPhases[_collectionID].allowlistEndTime = _allowlistEndTime;
174: collectionPhases[_collectionID].merkleRoot = _merkleRoot;
175: collectionPhases[_collectionID].publicStartTime = _publicStartTime;
176: collectionPhases[_collectionID].publicEndTime = _publicEndTime;
177: }
302: function updateDelegationCollection(uint256 _collectionID, address _collectionAddress) public FunctionAdminRequired(this.updateDelegationCollection.selector) {
303: collectionPhases[_collectionID].delAddress = _collectionAddress;
304: }
369: function setPrimaryAndSecondarySplits(uint256 _collectionID, uint256 _artistPrSplit, uint256 _teamPrSplit, uint256 _artistSecSplit, uint256 _teamSecSplit) public FunctionAdminRequired(this.setPrimaryAndSecondarySplits.selector) {
370: require(_artistPrSplit + _teamPrSplit == 100, "splits need to be 100%");
371: require(_artistSecSplit + _teamSecSplit == 100, "splits need to be 100%");
372: collectionRoyaltiesPrimarySplits[_collectionID].artistPercentage = _artistPrSplit;
373: collectionRoyaltiesPrimarySplits[_collectionID].teamPercentage = _teamPrSplit;
374: collectionRoyaltiesSecondarySplits[_collectionID].artistPercentage = _artistSecSplit;
375: collectionRoyaltiesSecondarySplits[_collectionID].teamPercentage = _teamSecSplit;
376: }
448: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
449: gencore = INextGenCore(_gencore);
450: }
454: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
455: require(INextGenAdmins(_newadminsContract).isAdminContract() == true, "Contract is not Admin");
456: adminsContract = INextGenAdmins(_newadminsContract);
457: }
[157-166, 170-177, 302-304, 369-376, 448-450, 454-457]
File: smart-contracts/NextGenCore.sol
147: function setCollectionData(uint256 _collectionID, address _collectionArtistAddress, uint256 _maxCollectionPurchases, uint256 _collectionTotalSupply, uint _setFinalSupplyTimeAfterMint) public CollectionAdminRequired(_collectionID, this.setCollectionData.selector) {
148: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false) && (_collectionTotalSupply <= 10000000000), "err/freezed");
149: if (collectionAdditionalData[_collectionID].collectionTotalSupply == 0) {
150: collectionAdditionalData[_collectionID].collectionArtistAddress = _collectionArtistAddress;
151: collectionAdditionalData[_collectionID].maxCollectionPurchases = _maxCollectionPurchases;
152: collectionAdditionalData[_collectionID].collectionCirculationSupply = 0;
153: collectionAdditionalData[_collectionID].collectionTotalSupply = _collectionTotalSupply;
154: collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint = _setFinalSupplyTimeAfterMint;
155: collectionAdditionalData[_collectionID].reservedMinTokensIndex = (_collectionID * 10000000000);
156: collectionAdditionalData[_collectionID].reservedMaxTokensIndex = (_collectionID * 10000000000) + _collectionTotalSupply - 1;
157: wereDataAdded[_collectionID] = true;
158: } else if (artistSigned[_collectionID] == false) {
159: collectionAdditionalData[_collectionID].collectionArtistAddress = _collectionArtistAddress;
160: collectionAdditionalData[_collectionID].maxCollectionPurchases = _maxCollectionPurchases;
161: collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint = _setFinalSupplyTimeAfterMint;
162: } else {
163: collectionAdditionalData[_collectionID].maxCollectionPurchases = _maxCollectionPurchases;
164: collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint = _setFinalSupplyTimeAfterMint;
165: }
166: }
238: function updateCollectionInfo(uint256 _collectionID, string memory _newCollectionName, string memory _newCollectionArtist, string memory _newCollectionDescription, string memory _newCollectionWebsite, string memory _newCollectionLicense, string memory _newCollectionBaseURI, string memory _newCollectionLibrary, uint256 _index, string[] memory _newCollectionScript) public CollectionAdminRequired(_collectionID, this.updateCollectionInfo.selector) {
239: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false), "Not allowed");
240: if (_index == 1000) {
241: collectionInfo[_collectionID].collectionName = _newCollectionName;
242: collectionInfo[_collectionID].collectionArtist = _newCollectionArtist;
243: collectionInfo[_collectionID].collectionDescription = _newCollectionDescription;
244: collectionInfo[_collectionID].collectionWebsite = _newCollectionWebsite;
245: collectionInfo[_collectionID].collectionLicense = _newCollectionLicense;
246: collectionInfo[_collectionID].collectionLibrary = _newCollectionLibrary;
247: collectionInfo[_collectionID].collectionScript = _newCollectionScript;
248: } else if (_index == 999) {
249: collectionInfo[_collectionID].collectionBaseURI = _newCollectionBaseURI;
250: } else {
251: collectionInfo[_collectionID].collectionScript[_index] = _newCollectionScript[0];
252: }
253: }
281: function updateImagesAndAttributes(uint256[] memory _tokenId, string[] memory _images, string[] memory _attributes) public FunctionAdminRequired(this.updateImagesAndAttributes.selector) {
282: for (uint256 x; x < _tokenId.length; x++) {
283: require(collectionFreeze[tokenIdsToCollectionIds[_tokenId[x]]] == false, "Data frozen");
284: _requireMinted(_tokenId[x]);
285: tokenImageAndAttributes[_tokenId[x]][0] = _images[x];
286: tokenImageAndAttributes[_tokenId[x]][1] = _attributes[x];
287: }
288: }
299: function setTokenHash(uint256 _collectionID, uint256 _mintIndex, bytes32 _hash) external {
300: require(msg.sender == collectionAdditionalData[_collectionID].randomizerContract);
301: require(tokenToHash[_mintIndex] == 0x0000000000000000000000000000000000000000000000000000000000000000);
302: tokenToHash[_mintIndex] = _hash;
303: }
307: function setFinalSupply(uint256 _collectionID) public FunctionAdminRequired(this.setFinalSupply.selector) {
308: require (block.timestamp > IMinterContract(minterContract).getEndTime(_collectionID) + collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint, "Time has not passed");
309: collectionAdditionalData[_collectionID].collectionTotalSupply = collectionAdditionalData[_collectionID].collectionCirculationSupply;
310: collectionAdditionalData[_collectionID].reservedMaxTokensIndex = (_collectionID * 10000000000) + collectionAdditionalData[_collectionID].collectionTotalSupply - 1;
311: }
322: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
323: require(INextGenAdmins(_newadminsContract).isAdminContract() == true, "Contract is not Admin");
324: adminsContract = INextGenAdmins(_newadminsContract);
325: }
329: function setDefaultRoyalties(address _royaltyAddress, uint96 _bps) public FunctionAdminRequired(this.setDefaultRoyalties.selector) {
330: _setDefaultRoyalty(_royaltyAddress, _bps);
331: }
[147-166, 238-253, 281-288, 299-303, 307-311, 322-325, 329-331]
File: smart-contracts/RandomizerNXT.sol
41: function updateRandomsContract(address _randoms) public FunctionAdminRequired(this.updateRandomsContract.selector) {
42: randoms = IXRandoms(_randoms);
43: }
45: function updateAdminsContract(address _admin) public FunctionAdminRequired(this.updateAdminsContract.selector) {
46: adminsContract = INextGenAdmins(_admin);
47: }
49: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
50: gencore = _gencore;
51: gencoreContract = INextGenCore(_gencore);
52: }
File: smart-contracts/RandomizerRNG.sol
61: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
62: require(INextGenAdmins(_newadminsContract).isAdminContract() == true, "Contract is not Admin");
63: adminsContract = INextGenAdmins(_newadminsContract);
64: }
66: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
67: gencore = _gencore;
68: gencoreContract = INextGenCore(_gencore);
69: }
73: function updateRNGCost(uint256 _ethRequired) public FunctionAdminRequired(this.updateRNGCost.selector) {
74: ethRequired = _ethRequired;
75: }
File: smart-contracts/RandomizerVRF.sol
79: function updatecallbackGasLimitAndkeyHash(uint32 _callbackGasLimit, bytes32 _keyHash) public FunctionAdminRequired(this.updatecallbackGasLimitAndkeyHash.selector){
80: callbackGasLimit = _callbackGasLimit;
81: keyHash = _keyHash;
82: }
86: function updateAdditionalData(uint64 _s_subscriptionId, uint32 _numWords, uint16 _requestConfirmations) public FunctionAdminRequired(this.updateAdditionalData.selector){
87: s_subscriptionId = _s_subscriptionId;
88: numWords = _numWords;
89: requestConfirmations = _requestConfirmations;
90: }
94: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
95: require(INextGenAdmins(_newadminsContract).isAdminContract() == true, "Contract is not Admin");
96: adminsContract = INextGenAdmins(_newadminsContract);
97: }
99: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
100: gencore = _gencore;
101: gencoreContract = INextGenCore(_gencore);
102: }
As a best practice, consider emitting an event when the contract is initialized. In this way, it's easy for the user to track the exact point in time when the contract was initialized, by filtering the emitted events.
There are 2 instances of this issue.
File: smart-contracts/MinterContract.sol
308: function initializeBurn(uint256 _burnCollectionID, uint256 _mintCollectionID, bool _status) public FunctionAdminRequired(this.initializeBurn.selector) {
315: function initializeExternalBurnOrSwap(address _erc721Collection, uint256 _burnCollectionID, uint256 _mintCollectionID, uint256 _tokmin, uint256 _tokmax, address _burnOrSwapAddress, bool _status) public FunctionAdminRequired(this.initializeExternalBurnOrSwap.selector) {
Not only is wasteful in terms of gas, but this is especially problematic when an event is emitted and the old and new values set are the same, as listeners might not expect this kind of scenario.
There are 19 instances of this issue.
Expand findings
File: smart-contracts/MinterContract.sol
// @audit setMintingCosts
157: function setCollectionCosts(uint256 _collectionID, uint256 _collectionMintCost, uint256 _collectionEndMintCost, uint256 _rate, uint256 _timePeriod, uint8 _salesOption, address _delAddress) public CollectionAdminRequired(_collectionID, this.setCollectionCosts.selector) {
// @audit gencore
448: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
// @audit adminsContract
454: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
File: smart-contracts/NextGenCore.sol
// @audit wereDataAdded
147: function setCollectionData(uint256 _collectionID, address _collectionArtistAddress, uint256 _maxCollectionPurchases, uint256 _collectionTotalSupply, uint _setFinalSupplyTimeAfterMint) public CollectionAdminRequired(_collectionID, this.setCollectionData.selector) {
// @audit onchainMetadata
266: function changeMetadataView(uint256 _collectionID, bool _status) public CollectionAdminRequired(_collectionID, this.changeMetadataView.selector) {
// @audit tokenData
273: function changeTokenData(uint256 _tokenId, string memory newData) public FunctionAdminRequired(this.changeTokenData.selector) {
// @audit tokenImageAndAttributes, tokenImageAndAttributes
281: function updateImagesAndAttributes(uint256[] memory _tokenId, string[] memory _images, string[] memory _attributes) public FunctionAdminRequired(this.updateImagesAndAttributes.selector) {
// @audit tokenToHash
299: function setTokenHash(uint256 _collectionID, uint256 _mintIndex, bytes32 _hash) external {
// @audit adminsContract
322: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
[147, 266, 273, 281, 299, 322]
File: smart-contracts/RandomizerNXT.sol
// @audit randoms
41: function updateRandomsContract(address _randoms) public FunctionAdminRequired(this.updateRandomsContract.selector) {
// @audit adminsContract
45: function updateAdminsContract(address _admin) public FunctionAdminRequired(this.updateAdminsContract.selector) {
// @audit gencore, gencoreContract
49: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
File: smart-contracts/RandomizerRNG.sol
// @audit adminsContract
61: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
// @audit gencore, gencoreContract
66: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
// @audit ethRequired
73: function updateRNGCost(uint256 _ethRequired) public FunctionAdminRequired(this.updateRNGCost.selector) {
File: smart-contracts/RandomizerVRF.sol
// @audit callbackGasLimit, keyHash
79: function updatecallbackGasLimitAndkeyHash(uint32 _callbackGasLimit, bytes32 _keyHash) public FunctionAdminRequired(this.updatecallbackGasLimitAndkeyHash.selector){
// @audit s_subscriptionId, numWords, requestConfirmations
86: function updateAdditionalData(uint64 _s_subscriptionId, uint32 _numWords, uint16 _requestConfirmations) public FunctionAdminRequired(this.updateAdditionalData.selector){
// @audit adminsContract
94: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
// @audit gencore, gencoreContract
99: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
It is recommended to always use uint256/int256
instead of uint/int
in function parameters, since they are used for function signatures.
There are 25 instances of this issue.
Expand findings
File: smart-contracts/MinterContract.sol
45: uint allowlistStartTime;
46: uint allowlistEndTime;
47: uint publicStartTime;
48: uint publicEndTime;
170: function setCollectionPhases(uint256 _collectionID, uint _allowlistStartTime, uint _allowlistEndTime, uint _publicStartTime, uint _publicEndTime, bytes32 _merkleRoot) public CollectionAdminRequired(_collectionID, this.setCollectionPhases.selector) {
170: function setCollectionPhases(uint256 _collectionID, uint _allowlistStartTime, uint _allowlistEndTime, uint _publicStartTime, uint _publicEndTime, bytes32 _merkleRoot) public CollectionAdminRequired(_collectionID, this.setCollectionPhases.selector) {
170: function setCollectionPhases(uint256 _collectionID, uint _allowlistStartTime, uint _allowlistEndTime, uint _publicStartTime, uint _publicEndTime, bytes32 _merkleRoot) public CollectionAdminRequired(_collectionID, this.setCollectionPhases.selector) {
170: function setCollectionPhases(uint256 _collectionID, uint _allowlistStartTime, uint _allowlistEndTime, uint _publicStartTime, uint _publicEndTime, bytes32 _merkleRoot) public CollectionAdminRequired(_collectionID, this.setCollectionPhases.selector) {
241: uint timeOfLastMint;
249: uint tDiff = (block.timestamp - timeOfLastMint) / collectionPhases[col].timePeriod;
276: function mintAndAuction(address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint _auctionEndTime) public FunctionAdminRequired(this.mintAndAuction.selector) {
283: uint timeOfLastMint;
292: uint tDiff = (block.timestamp - timeOfLastMint) / collectionPhases[_collectionID].timePeriod;
462: uint balance = address(this).balance;
494: function retrieveCollectionPhases(uint256 _collectionID) public view returns(uint, uint, bytes32, uint, uint){
494: function retrieveCollectionPhases(uint256 _collectionID) public view returns(uint, uint, bytes32, uint, uint){
494: function retrieveCollectionPhases(uint256 _collectionID) public view returns(uint, uint, bytes32, uint, uint){
494: function retrieveCollectionPhases(uint256 _collectionID) public view returns(uint, uint, bytes32, uint, uint){
512: function getEndTime(uint256 _collectionID) external view returns (uint) {
518: function getAuctionEndTime(uint256 _tokenId) external view returns (uint) {
531: uint tDiff;
[45, 46, 47, 48, 170, 170, 170, 170, 241, 249, 276, 283, 292, 462, 494, 494, 494, 494, 512, 518, 531]
File: smart-contracts/NextGenCore.sol
51: uint setFinalSupplyTimeAfterMint;
147: function setCollectionData(uint256 _collectionID, address _collectionArtistAddress, uint256 _maxCollectionPurchases, uint256 _collectionTotalSupply, uint _setFinalSupplyTimeAfterMint) public CollectionAdminRequired(_collectionID, this.setCollectionData.selector) {
438: function retrieveCollectionAdditionalData(uint256 _collectionID) public view returns(address, uint256, uint256, uint256, uint, address){
File: smart-contracts/RandomizerRNG.sol
80: uint balance = address(this).balance;
[80]
Parent contracts should use named imports to improve the code readability.
There are 6 instances of this issue.
File: smart-contracts/AuctionDemo.sol
// @audit Ownable
18: contract auctionDemo is Ownable {
[18]
File: smart-contracts/MinterContract.sol
// @audit Ownable
20: contract NextGenMinterContract is Ownable {
[20]
File: smart-contracts/NextGenAdmins.sol
// @audit Ownable
15: contract NextGenAdmins is Ownable{
[15]
File: smart-contracts/NextGenCore.sol
// @audit ERC721Enumerable, Ownable, ERC2981
22: contract NextGenCore is ERC721Enumerable, Ownable, ERC2981 {
[22]
File: smart-contracts/RandomizerRNG.sol
// @audit ArrngConsumer, Ownable
18: contract NextGenRandomizerRNG is ArrngConsumer, Ownable {
[18]
File: smart-contracts/RandomizerVRF.sol
// @audit VRFConsumerBaseV2, Ownable
19: contract NextGenRandomizerVRF is VRFConsumerBaseV2, Ownable {
[19]
Some arguments are never used: if this is intentional, consider removing these arguments from the function. Otherwise, implement the missing logic accordingly.
There are 3 instances of this issue.
File: smart-contracts/RandomizerNXT.sol
// @audit _saltfun_o
55: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
[55]
File: smart-contracts/RandomizerRNG.sol
// @audit _saltfun_o
53: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
[53]
File: smart-contracts/RandomizerVRF.sol
// @audit _saltfun_o
71: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
[71]
These contracts import an ownable library, but there aren't any functions reserved to onlyOwner
. If this is an error, fix the access control for the appropriate functions; otherwise, remove this import.
There are 6 instances of this issue.
File: smart-contracts/AuctionDemo.sol
15: import "./Ownable.sol";
[15]
File: smart-contracts/MinterContract.sol
14: import "./Ownable.sol";
[14]
File: smart-contracts/NextGenCore.sol
14: import "./Ownable.sol";
[14]
File: smart-contracts/RandomizerNXT.sol
15: import "./Ownable.sol";
[15]
File: smart-contracts/RandomizerRNG.sol
14: import "./Ownable.sol";
[14]
File: smart-contracts/RandomizerVRF.sol
15: import "./Ownable.sol";
[15]
Consider using a library
instead of a contract
to provide utility functions.
There is 1 instance of this issue.
File: smart-contracts/XRandoms.sol
13: contract randomPool {
[13]
It's better to declare the hardcoded addresses as immutable
state variables, as this will facilitate deployment on other chains.
There are 5 instances of this issue.
File: smart-contracts/MinterContract.sol
// @audit 0x8888888888888888888888888888888888888888
207: isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(_delegator, 0x8888888888888888888888888888888888888888, msg.sender, 1) || dmc.retrieveGlobalStatusOfDelegation(_delegator, 0x8888888888888888888888888888888888888888, msg.sender, 2);
// @audit 0x8888888888888888888888888888888888888888
207: isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(_delegator, 0x8888888888888888888888888888888888888888, msg.sender, 1) || dmc.retrieveGlobalStatusOfDelegation(_delegator, 0x8888888888888888888888888888888888888888, msg.sender, 2);
// @audit 0x8888888888888888888888888888888888888888
333: isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(ownerOfToken, 0x8888888888888888888888888888888888888888, msg.sender, 1) || dmc.retrieveGlobalStatusOfDelegation(ownerOfToken, 0x8888888888888888888888888888888888888888, msg.sender, 2);
// @audit 0x8888888888888888888888888888888888888888
333: isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(ownerOfToken, 0x8888888888888888888888888888888888888888, msg.sender, 1) || dmc.retrieveGlobalStatusOfDelegation(ownerOfToken, 0x8888888888888888888888888888888888888888, msg.sender, 2);
File: smart-contracts/NextGenCore.sol
// @audit 0x1B1289E34Fe05019511d7b436a5138F361904df0
111: _setDefaultRoyalty(0x1B1289E34Fe05019511d7b436a5138F361904df0, 690);
[111]
Consider using an enum instead of hardcoding an index access to make the code easier to understand.
There are 11 instances of this issue.
File: smart-contracts/MinterContract.sol
320: burnOrSwapIds[externalCol][0] = _tokmin;
321: burnOrSwapIds[externalCol][1] = _tokmax;
339: require(_tokenId >= burnOrSwapIds[externalCol][0] && _tokenId <= burnOrSwapIds[externalCol][1], "Token id does not match");
339: require(_tokenId >= burnOrSwapIds[externalCol][0] && _tokenId <= burnOrSwapIds[externalCol][1], "Token id does not match");
File: smart-contracts/NextGenCore.sol
251: collectionInfo[_collectionID].collectionScript[_index] = _newCollectionScript[0];
285: tokenImageAndAttributes[_tokenId[x]][0] = _images[x];
286: tokenImageAndAttributes[_tokenId[x]][1] = _attributes[x];
354: string memory _uri = string(abi.encodePacked("data:application/json;utf8,{\"name\":\"",getTokenName(tokenId),"\",\"description\":\"",collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionDescription,"\",\"image\":\"",tokenImageAndAttributes[tokenId][0],"\",\"attributes\":[",tokenImageAndAttributes[tokenId][1],"],\"animation_url\":\"data:text/html;base64,",b64,"\"}"));
354: string memory _uri = string(abi.encodePacked("data:application/json;utf8,{\"name\":\"",getTokenName(tokenId),"\",\"description\":\"",collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionDescription,"\",\"image\":\"",tokenImageAndAttributes[tokenId][0],"\",\"attributes\":[",tokenImageAndAttributes[tokenId][1],"],\"animation_url\":\"data:text/html;base64,",b64,"\"}"));
468: return (tokenImageAndAttributes[_tokenId][0],tokenImageAndAttributes[_tokenId][1]);
468: return (tokenImageAndAttributes[_tokenId][0],tokenImageAndAttributes[_tokenId][1]);
[251, 285, 286, 354, 354, 468, 468]
It's not necessary to initialize a variable with a zero value, as it's the default behaviour, and it's actually worse in gas terms as it adds an overhead.
There are 11 instances of this issue.
File: smart-contracts/AuctionDemo.sol
68: uint256 highBid = 0;
69: for (uint256 i=0; i< auctionInfoData[_tokenid].length; i++) {
88: uint256 highBid = 0;
90: for (uint256 i=0; i< auctionInfoData[_tokenid].length; i++) {
110: for (uint256 i=0; i< auctionInfoData[_tokenid].length; i ++) {
136: for (uint256 i=0; i<auctionInfoData[_tokenid].length; i++) {
File: smart-contracts/MinterContract.sol
184: for (uint256 y=0; y< _recipients.length; y++) {
187: for(uint256 i = 0; i < _numberOfTokens[y]; i++) {
234: for(uint256 i = 0; i < _numberOfTokens; i++) {
File: smart-contracts/NextGenAdmins.sol
51: for (uint256 i=0; i<_selector.length; i++) {
[51]
File: smart-contracts/NextGenCore.sol
453: for (uint256 i=0; i < collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionScript.length; i++) {
[453]
Consider adding pausable
to the following contracts so it's possible to stop them in case of an emergency.
There are 6 instances of this issue.
File: smart-contracts/AuctionDemo.sol
18: contract auctionDemo is Ownable {
[18]
File: smart-contracts/MinterContract.sol
20: contract NextGenMinterContract is Ownable {
[20]
File: smart-contracts/NextGenAdmins.sol
15: contract NextGenAdmins is Ownable{
[15]
File: smart-contracts/NextGenCore.sol
22: contract NextGenCore is ERC721Enumerable, Ownable, ERC2981 {
[22]
File: smart-contracts/RandomizerRNG.sol
18: contract NextGenRandomizerRNG is ArrngConsumer, Ownable {
[18]
File: smart-contracts/RandomizerVRF.sol
19: contract NextGenRandomizerVRF is VRFConsumerBaseV2, Ownable {
[19]
These statements should be refactored to a separate function, as there are multiple parts of the codebase that use the same logic, to improve the code readability and reduce code duplication.
There are 11 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
// @audit this require is duplicated on line 135
125: require(block.timestamp <= minter.getAuctionEndTime(_tokenid), "Auction ended");
[125]
File: smart-contracts/MinterContract.sol
// @audit this require is duplicated on line 182, 277
158: require(gencore.retrievewereDataAdded(_collectionID) == true, "Add data");
// @audit this require is duplicated on line 197
171: require(setMintingCosts[_collectionID] == true, "Set Minting Costs");
// @audit this require is duplicated on line 280
186: require(collectionTokenMintIndex <= gencore.viewTokensIndexMax(_collectionID), "No supply");
// @audit this require is duplicated on line 337
211: require(isAllowedToMint == true, "No delegation");
// @audit this require is duplicated on line 350
220: require(MerkleProof.verifyCalldata(merkleProof, collectionPhases[col].merkleRoot, node), 'invalid proof');
// @audit this require is duplicated on line 360
232: require(collectionTokenMintIndex <= gencore.viewTokensIndexMax(col), "No supply");
[158, 171, 186, 211, 220, 232]
File: smart-contracts/NextGenCore.sol
// @audit this require is duplicated on line 190, 214
179: require(msg.sender == minterContract, "Caller is not the Minter Contract");
// @audit this require is duplicated on line 267
239: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false), "Not allowed");
File: smart-contracts/RandomizerRNG.sol
// @audit this require is duplicated on line 54
41: require(msg.sender == gencore);
[41]
File: smart-contracts/RandomizerVRF.sol
// @audit this require is duplicated on line 72
53: require(msg.sender == gencore);
[53]
These functions might be a problem if the logic changes before the contract is deployed, as the developer must remember to syncronize the logic between all the function instances.
Consider using a single function instead of duplicating the code, for example by using a library
, or through inheritance.
There are 14 instances of this issue.
Expand findings
File: smart-contracts/MinterContract.sol
// @audit duplicated logic in smart-contracts/MinterContract.sol -> updateAdminContract, smart-contracts/NextGenCore.sol -> updateAdminContract, smart-contracts/RandomizerRNG.sol -> updateAdminContract, smart-contracts/RandomizerVRF.sol -> updateAdminContract
454: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
// @audit duplicated logic in smart-contracts/MinterContract.sol -> emergencyWithdraw, smart-contracts/RandomizerRNG.sol -> emergencyWithdraw
461: function emergencyWithdraw() public FunctionAdminRequired(this.emergencyWithdraw.selector) {
// @audit duplicated logic in smart-contracts/MinterContract.sol -> isMinterContract, smart-contracts/NextGenAdmins.sol -> isAdminContract, smart-contracts/RandomizerNXT.sol -> isRandomizerContract, smart-contracts/RandomizerRNG.sol -> isRandomizerContract, smart-contracts/RandomizerVRF.sol -> isRandomizerContract
506: function isMinterContract() external view returns (bool) {
File: smart-contracts/NextGenAdmins.sol
// @audit duplicated logic in smart-contracts/MinterContract.sol -> isMinterContract, smart-contracts/NextGenAdmins.sol -> isAdminContract, smart-contracts/RandomizerNXT.sol -> isRandomizerContract, smart-contracts/RandomizerRNG.sol -> isRandomizerContract, smart-contracts/RandomizerVRF.sol -> isRandomizerContract
83: function isAdminContract() external view returns (bool) {
[83]
File: smart-contracts/NextGenCore.sol
// @audit duplicated logic in smart-contracts/MinterContract.sol -> updateAdminContract, smart-contracts/NextGenCore.sol -> updateAdminContract, smart-contracts/RandomizerRNG.sol -> updateAdminContract, smart-contracts/RandomizerVRF.sol -> updateAdminContract
322: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
[322]
File: smart-contracts/RandomizerNXT.sol
// @audit duplicated logic in smart-contracts/MinterContract.sol -> isMinterContract, smart-contracts/NextGenAdmins.sol -> isAdminContract, smart-contracts/RandomizerNXT.sol -> isRandomizerContract, smart-contracts/RandomizerRNG.sol -> isRandomizerContract, smart-contracts/RandomizerVRF.sol -> isRandomizerContract
62: function isRandomizerContract() external view returns (bool) {
// @audit duplicated logic in smart-contracts/RandomizerNXT.sol -> updateCoreContract, smart-contracts/RandomizerRNG.sol -> updateCoreContract, smart-contracts/RandomizerVRF.sol -> updateCoreContract
49: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
File: smart-contracts/RandomizerRNG.sol
// @audit duplicated logic in smart-contracts/MinterContract.sol -> updateAdminContract, smart-contracts/NextGenCore.sol -> updateAdminContract, smart-contracts/RandomizerRNG.sol -> updateAdminContract, smart-contracts/RandomizerVRF.sol -> updateAdminContract
61: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
// @audit duplicated logic in smart-contracts/MinterContract.sol -> emergencyWithdraw, smart-contracts/RandomizerRNG.sol -> emergencyWithdraw
79: function emergencyWithdraw() public FunctionAdminRequired(this.emergencyWithdraw.selector) {
// @audit duplicated logic in smart-contracts/MinterContract.sol -> isMinterContract, smart-contracts/NextGenAdmins.sol -> isAdminContract, smart-contracts/RandomizerNXT.sol -> isRandomizerContract, smart-contracts/RandomizerRNG.sol -> isRandomizerContract, smart-contracts/RandomizerVRF.sol -> isRandomizerContract
89: function isRandomizerContract() external view returns (bool) {
// @audit duplicated logic in smart-contracts/RandomizerNXT.sol -> updateCoreContract, smart-contracts/RandomizerRNG.sol -> updateCoreContract, smart-contracts/RandomizerVRF.sol -> updateCoreContract
66: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
File: smart-contracts/RandomizerVRF.sol
// @audit duplicated logic in smart-contracts/MinterContract.sol -> updateAdminContract, smart-contracts/NextGenCore.sol -> updateAdminContract, smart-contracts/RandomizerRNG.sol -> updateAdminContract, smart-contracts/RandomizerVRF.sol -> updateAdminContract
94: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
// @audit duplicated logic in smart-contracts/MinterContract.sol -> isMinterContract, smart-contracts/NextGenAdmins.sol -> isAdminContract, smart-contracts/RandomizerNXT.sol -> isRandomizerContract, smart-contracts/RandomizerRNG.sol -> isRandomizerContract, smart-contracts/RandomizerVRF.sol -> isRandomizerContract
105: function isRandomizerContract() external view returns (bool) {
// @audit duplicated logic in smart-contracts/RandomizerNXT.sol -> updateCoreContract, smart-contracts/RandomizerRNG.sol -> updateCoreContract, smart-contracts/RandomizerVRF.sol -> updateCoreContract
99: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
Consider limiting the number of iterations in loops with an explicit revert reason to avoid iterating an array that is too large.
The function would eventually revert if out of gas anyway, but by limiting it the user avoids wasting too much gas, as the loop doesn't execute if an excessive value is provided.
There are 6 instances of this issue.
File: smart-contracts/MinterContract.sol
184: for (uint256 y=0; y< _recipients.length; y++) {
185: collectionTokenMintIndex = gencore.viewTokensIndexMin(_collectionID) + gencore.viewCirSupply(_collectionID) + _numberOfTokens[y] - 1;
186: require(collectionTokenMintIndex <= gencore.viewTokensIndexMax(_collectionID), "No supply");
187: for(uint256 i = 0; i < _numberOfTokens[y]; i++) {
188: uint256 mintIndex = gencore.viewTokensIndexMin(_collectionID) + gencore.viewCirSupply(_collectionID);
189: gencore.airDropTokens(mintIndex, _recipients[y], _tokenData[y], _saltfun_o[y], _collectionID);
190: }
191: }
187: for(uint256 i = 0; i < _numberOfTokens[y]; i++) {
188: uint256 mintIndex = gencore.viewTokensIndexMin(_collectionID) + gencore.viewCirSupply(_collectionID);
189: gencore.airDropTokens(mintIndex, _recipients[y], _tokenData[y], _saltfun_o[y], _collectionID);
190: }
234: for(uint256 i = 0; i < _numberOfTokens; i++) {
235: uint256 mintIndex = gencore.viewTokensIndexMin(col) + gencore.viewCirSupply(col);
236: gencore.mint(mintIndex, mintingAddress, _mintTo, tokData, _saltfun_o, col, phase);
237: }
File: smart-contracts/NextGenAdmins.sol
51: for (uint256 i=0; i<_selector.length; i++) {
52: functionAdmin[_address][_selector[i]] = _status;
53: }
[51-53]
File: smart-contracts/NextGenCore.sol
282: for (uint256 x; x < _tokenId.length; x++) {
283: require(collectionFreeze[tokenIdsToCollectionIds[_tokenId[x]]] == false, "Data frozen");
284: _requireMinted(_tokenId[x]);
285: tokenImageAndAttributes[_tokenId[x]][0] = _images[x];
286: tokenImageAndAttributes[_tokenId[x]][1] = _attributes[x];
287: }
453: for (uint256 i=0; i < collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionScript.length; i++) {
454: scripttext = string(abi.encodePacked(scripttext, collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionScript[i]));
455: }
Those functions should be declared as external
instead of public
, as they are never called internally by the contract.
Contracts are allowed to override their parents' functions and change the visibility from external to public.
There are 75 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
57: function participateToAuction(uint256 _tokenid) public payable {
104: function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){
124: function cancelBid(uint256 _tokenid, uint256 index) public {
134: function cancelAllBids(uint256 _tokenid) public {
147: function returnBids(uint256 _tokenid) public view returns(auctionInfoStru[] memory) {
File: smart-contracts/MinterContract.sol
157: function setCollectionCosts(uint256 _collectionID, uint256 _collectionMintCost, uint256 _collectionEndMintCost, uint256 _rate, uint256 _timePeriod, uint8 _salesOption, address _delAddress) public CollectionAdminRequired(_collectionID, this.setCollectionCosts.selector) {
170: function setCollectionPhases(uint256 _collectionID, uint _allowlistStartTime, uint _allowlistEndTime, uint _publicStartTime, uint _publicEndTime, bytes32 _merkleRoot) public CollectionAdminRequired(_collectionID, this.setCollectionPhases.selector) {
181: function airDropTokens(address[] memory _recipients, string[] memory _tokenData, uint256[] memory _saltfun_o, uint256 _collectionID, uint256[] memory _numberOfTokens) public FunctionAdminRequired(this.airDropTokens.selector) {
196: function mint(uint256 _collectionID, uint256 _numberOfTokens, uint256 _maxAllowance, string memory _tokenData, address _mintTo, bytes32[] calldata merkleProof, address _delegator, uint256 _saltfun_o) public payable {
258: function burnToMint(uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, uint256 _saltfun_o) public payable {
276: function mintAndAuction(address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint _auctionEndTime) public FunctionAdminRequired(this.mintAndAuction.selector) {
302: function updateDelegationCollection(uint256 _collectionID, address _collectionAddress) public FunctionAdminRequired(this.updateDelegationCollection.selector) {
308: function initializeBurn(uint256 _burnCollectionID, uint256 _mintCollectionID, bool _status) public FunctionAdminRequired(this.initializeBurn.selector) {
315: function initializeExternalBurnOrSwap(address _erc721Collection, uint256 _burnCollectionID, uint256 _mintCollectionID, uint256 _tokmin, uint256 _tokmax, address _burnOrSwapAddress, bool _status) public FunctionAdminRequired(this.initializeExternalBurnOrSwap.selector) {
326: function burnOrSwapExternalToMint(address _erc721Collection, uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, string memory _tokenData, bytes32[] calldata merkleProof, uint256 _saltfun_o) public payable {
369: function setPrimaryAndSecondarySplits(uint256 _collectionID, uint256 _artistPrSplit, uint256 _teamPrSplit, uint256 _artistSecSplit, uint256 _teamSecSplit) public FunctionAdminRequired(this.setPrimaryAndSecondarySplits.selector) {
380: function proposePrimaryAddressesAndPercentages(uint256 _collectionID, address _primaryAdd1, address _primaryAdd2, address _primaryAdd3, uint256 _add1Percentage, uint256 _add2Percentage, uint256 _add3Percentage) public ArtistOrAdminRequired(_collectionID, this.proposePrimaryAddressesAndPercentages.selector) {
394: function proposeSecondaryAddressesAndPercentages(uint256 _collectionID, address _secondaryAdd1, address _secondaryAdd2, address _secondaryAdd3, uint256 _add1Percentage, uint256 _add2Percentage, uint256 _add3Percentage) public ArtistOrAdminRequired(_collectionID, this.proposeSecondaryAddressesAndPercentages.selector) {
408: function acceptAddressesAndPercentages(uint256 _collectionID, bool _statusPrimary, bool _statusSecondary) public FunctionAdminRequired(this.acceptAddressesAndPercentages.selector) {
415: function payArtist(uint256 _collectionID, address _team1, address _team2, uint256 _teamperc1, uint256 _teamperc2) public FunctionAdminRequired(this.payArtist.selector) {
448: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
454: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
461: function emergencyWithdraw() public FunctionAdminRequired(this.emergencyWithdraw.selector) {
470: function retrievePrimarySplits(uint256 _collectionID) public view returns(uint256, uint256){
476: function retrievePrimaryAddressesAndPercentages(uint256 _collectionID) public view returns(address, address, address, uint256, uint256, uint256, bool){
482: function retrieveSecondarySplits(uint256 _collectionID) public view returns(uint256, uint256){
488: function retrieveSecondaryAddressesAndPercentages(uint256 _collectionID) public view returns(address, address, address, uint256, uint256, uint256, bool){
494: function retrieveCollectionPhases(uint256 _collectionID) public view returns(uint, uint, bytes32, uint, uint){
500: function retrieveCollectionMintingDetails(uint256 _collectionID) public view returns(uint256, uint256, uint256, uint256, uint8, address){
[157, 170, 181, 196, 258, 276, 302, 308, 315, 326, 369, 380, 394, 408, 415, 448, 454, 461, 470, 476, 482, 488, 494, 500]
File: smart-contracts/NextGenAdmins.sol
38: function registerAdmin(address _admin, bool _status) public onlyOwner {
44: function registerFunctionAdmin(address _address, bytes4 _selector, bool _status) public AdminRequired {
50: function registerBatchFunctionAdmin(address _address, bytes4[] memory _selector, bool _status) public AdminRequired {
58: function registerCollectionAdmin(uint256 _collectionID, address _address, bool _status) public AdminRequired {
65: function retrieveGlobalAdmin(address _address) public view returns(bool) {
71: function retrieveFunctionAdmin(address _address, bytes4 _selector) public view returns(bool) {
77: function retrieveCollectionAdmin(address _address, uint256 _collectionID) public view returns(bool) {
File: smart-contracts/NextGenCore.sol
130: function createCollection(string memory _collectionName, string memory _collectionArtist, string memory _collectionDescription, string memory _collectionWebsite, string memory _collectionLicense, string memory _collectionBaseURI, string memory _collectionLibrary, string[] memory _collectionScript) public FunctionAdminRequired(this.createCollection.selector) {
147: function setCollectionData(uint256 _collectionID, address _collectionArtistAddress, uint256 _maxCollectionPurchases, uint256 _collectionTotalSupply, uint _setFinalSupplyTimeAfterMint) public CollectionAdminRequired(_collectionID, this.setCollectionData.selector) {
170: function addRandomizer(uint256 _collectionID, address _randomizerContract) public FunctionAdminRequired(this.addRandomizer.selector) {
204: function burn(uint256 _collectionID, uint256 _tokenId) public {
238: function updateCollectionInfo(uint256 _collectionID, string memory _newCollectionName, string memory _newCollectionArtist, string memory _newCollectionDescription, string memory _newCollectionWebsite, string memory _newCollectionLicense, string memory _newCollectionBaseURI, string memory _newCollectionLibrary, uint256 _index, string[] memory _newCollectionScript) public CollectionAdminRequired(_collectionID, this.updateCollectionInfo.selector) {
257: function artistSignature(uint256 _collectionID, string memory _signature) public {
266: function changeMetadataView(uint256 _collectionID, bool _status) public CollectionAdminRequired(_collectionID, this.changeMetadataView.selector) {
273: function changeTokenData(uint256 _tokenId, string memory newData) public FunctionAdminRequired(this.changeTokenData.selector) {
281: function updateImagesAndAttributes(uint256[] memory _tokenId, string[] memory _images, string[] memory _attributes) public FunctionAdminRequired(this.updateImagesAndAttributes.selector) {
292: function freezeCollection(uint256 _collectionID) public FunctionAdminRequired(this.freezeCollection.selector) {
307: function setFinalSupply(uint256 _collectionID) public FunctionAdminRequired(this.setFinalSupply.selector) {
315: function addMinterContract(address _minterContract) public FunctionAdminRequired(this.addMinterContract.selector) {
322: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
329: function setDefaultRoyalties(address _royaltyAddress, uint96 _bps) public FunctionAdminRequired(this.setDefaultRoyalties.selector) {
367: function collectionFreezeStatus(uint256 _collectionID) public view returns(bool){
415: function retrieveTokensAirdroppedPerAddress(uint256 _collectionID, address _address) public view returns(uint256) {
426: function retrieveCollectionInfo(uint256 _collectionID) public view returns(string memory, string memory, string memory, string memory, string memory, string memory){
432: function retrieveCollectionLibraryAndScript(uint256 _collectionID) public view returns(string memory, string[] memory){
438: function retrieveCollectionAdditionalData(uint256 _collectionID) public view returns(address, uint256, uint256, uint256, uint, address){
444: function retrieveTokenHash(uint256 _tokenid) public view returns(bytes32){
461: function totalSupplyOfCollection(uint256 _collectionID) public view returns (uint256) {
467: function retrievetokenImageAndAttributes(uint256 _tokenId) public view returns(string memory, string memory) {
[130, 147, 170, 204, 238, 257, 266, 273, 281, 292, 307, 315, 322, 329, 367, 415, 426, 432, 438, 444, 461, 467]
File: smart-contracts/RandomizerNXT.sol
41: function updateRandomsContract(address _randoms) public FunctionAdminRequired(this.updateRandomsContract.selector) {
45: function updateAdminsContract(address _admin) public FunctionAdminRequired(this.updateAdminsContract.selector) {
49: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
55: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
File: smart-contracts/RandomizerRNG.sol
53: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
61: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
66: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
73: function updateRNGCost(uint256 _ethRequired) public FunctionAdminRequired(this.updateRNGCost.selector) {
79: function emergencyWithdraw() public FunctionAdminRequired(this.emergencyWithdraw.selector) {
File: smart-contracts/RandomizerVRF.sol
71: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
79: function updatecallbackGasLimitAndkeyHash(uint32 _callbackGasLimit, bytes32 _keyHash) public FunctionAdminRequired(this.updatecallbackGasLimitAndkeyHash.selector){
86: function updateAdditionalData(uint64 _s_subscriptionId, uint32 _numWords, uint16 _requestConfirmations) public FunctionAdminRequired(this.updateAdditionalData.selector){
94: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
99: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
File: smart-contracts/XRandoms.sol
35: function randomNumber() public view returns (uint256){
40: function randomWord() public view returns (string memory) {
45: function returnIndex(uint256 id) public view returns (string memory) {
Use a scientific notation rather than decimal literals (e.g. 1e6
instead of 1000000
), for better code readability.
There are 4 instances of this issue.
File: smart-contracts/NextGenCore.sol
// @audit 10000000000 -> 1e10
148: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false) && (_collectionTotalSupply <= 10000000000), "err/freezed");
// @audit 10000000000 -> 1e10
155: collectionAdditionalData[_collectionID].reservedMinTokensIndex = (_collectionID * 10000000000);
// @audit 10000000000 -> 1e10
156: collectionAdditionalData[_collectionID].reservedMaxTokensIndex = (_collectionID * 10000000000) + _collectionTotalSupply - 1;
// @audit 10000000000 -> 1e10
310: collectionAdditionalData[_collectionID].reservedMaxTokensIndex = (_collectionID * 10000000000) + collectionAdditionalData[_collectionID].collectionTotalSupply - 1;
Large hardcoded numbers in code can be difficult to read. Consider using underscores for number literals to improve readability (e.g 1234567
-> 1_234_567
). Consider using an underscore for every third digit from the right.
There are 5 instances of this issue.
File: smart-contracts/NextGenCore.sol
148: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false) && (_collectionTotalSupply <= 10000000000), "err/freezed");
155: collectionAdditionalData[_collectionID].reservedMinTokensIndex = (_collectionID * 10000000000);
156: collectionAdditionalData[_collectionID].reservedMaxTokensIndex = (_collectionID * 10000000000) + _collectionTotalSupply - 1;
310: collectionAdditionalData[_collectionID].reservedMaxTokensIndex = (_collectionID * 10000000000) + collectionAdditionalData[_collectionID].collectionTotalSupply - 1;
File: smart-contracts/RandomizerVRF.sol
27: uint32 public callbackGasLimit = 40000;
[27]
The codebase uses both int
/uint
and int256
/uint256
at the same time. To improve the consistency, even if they are aliases, it is recommended to use only a variant, preferably int256
/uint256
as they are the preferred type names.
There are 25 instances of this issue.
Expand findings
File: smart-contracts/MinterContract.sol
// @audit allowlistStartTime
45: uint allowlistStartTime;
// @audit allowlistEndTime
46: uint allowlistEndTime;
// @audit publicStartTime
47: uint publicStartTime;
// @audit publicEndTime
48: uint publicEndTime;
// @audit _allowlistStartTime
170: function setCollectionPhases(uint256 _collectionID, uint _allowlistStartTime, uint _allowlistEndTime, uint _publicStartTime, uint _publicEndTime, bytes32 _merkleRoot) public CollectionAdminRequired(_collectionID, this.setCollectionPhases.selector) {
// @audit _allowlistEndTime
170: function setCollectionPhases(uint256 _collectionID, uint _allowlistStartTime, uint _allowlistEndTime, uint _publicStartTime, uint _publicEndTime, bytes32 _merkleRoot) public CollectionAdminRequired(_collectionID, this.setCollectionPhases.selector) {
// @audit _publicStartTime
170: function setCollectionPhases(uint256 _collectionID, uint _allowlistStartTime, uint _allowlistEndTime, uint _publicStartTime, uint _publicEndTime, bytes32 _merkleRoot) public CollectionAdminRequired(_collectionID, this.setCollectionPhases.selector) {
// @audit _publicEndTime
170: function setCollectionPhases(uint256 _collectionID, uint _allowlistStartTime, uint _allowlistEndTime, uint _publicStartTime, uint _publicEndTime, bytes32 _merkleRoot) public CollectionAdminRequired(_collectionID, this.setCollectionPhases.selector) {
// @audit timeOfLastMint
241: uint timeOfLastMint;
// @audit tDiff
249: uint tDiff = (block.timestamp - timeOfLastMint) / collectionPhases[col].timePeriod;
// @audit _auctionEndTime
276: function mintAndAuction(address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint _auctionEndTime) public FunctionAdminRequired(this.mintAndAuction.selector) {
// @audit timeOfLastMint
283: uint timeOfLastMint;
// @audit tDiff
292: uint tDiff = (block.timestamp - timeOfLastMint) / collectionPhases[_collectionID].timePeriod;
// @audit balance
462: uint balance = address(this).balance;
494: function retrieveCollectionPhases(uint256 _collectionID) public view returns(uint, uint, bytes32, uint, uint){
494: function retrieveCollectionPhases(uint256 _collectionID) public view returns(uint, uint, bytes32, uint, uint){
494: function retrieveCollectionPhases(uint256 _collectionID) public view returns(uint, uint, bytes32, uint, uint){
494: function retrieveCollectionPhases(uint256 _collectionID) public view returns(uint, uint, bytes32, uint, uint){
512: function getEndTime(uint256 _collectionID) external view returns (uint) {
518: function getAuctionEndTime(uint256 _tokenId) external view returns (uint) {
// @audit tDiff
531: uint tDiff;
[45, 46, 47, 48, 170, 170, 170, 170, 241, 249, 276, 283, 292, 462, 494, 494, 494, 494, 512, 518, 531]
File: smart-contracts/NextGenCore.sol
// @audit setFinalSupplyTimeAfterMint
51: uint setFinalSupplyTimeAfterMint;
// @audit _setFinalSupplyTimeAfterMint
147: function setCollectionData(uint256 _collectionID, address _collectionArtistAddress, uint256 _maxCollectionPurchases, uint256 _collectionTotalSupply, uint _setFinalSupplyTimeAfterMint) public CollectionAdminRequired(_collectionID, this.setCollectionData.selector) {
438: function retrieveCollectionAdditionalData(uint256 _collectionID) public view returns(address, uint256, uint256, uint256, uint, address){
File: smart-contracts/RandomizerRNG.sol
// @audit balance
80: uint balance = address(this).balance;
[80]
It is a good practice to give time for users to react and adjust to critical changes. A timelock provides more guarantees and reduces the level of trust required, thus decreasing risk for users. It also indicates that the project is legitimate (less risk of a malicious owner making a sandwich attack on a user). Consider adding a timelock to the following functions:
There are 34 instances of this issue.
Expand findings
File: smart-contracts/MinterContract.sol
157: function setCollectionCosts(uint256 _collectionID, uint256 _collectionMintCost, uint256 _collectionEndMintCost, uint256 _rate, uint256 _timePeriod, uint8 _salesOption, address _delAddress) public CollectionAdminRequired(_collectionID, this.setCollectionCosts.selector) {
170: function setCollectionPhases(uint256 _collectionID, uint _allowlistStartTime, uint _allowlistEndTime, uint _publicStartTime, uint _publicEndTime, bytes32 _merkleRoot) public CollectionAdminRequired(_collectionID, this.setCollectionPhases.selector) {
181: function airDropTokens(address[] memory _recipients, string[] memory _tokenData, uint256[] memory _saltfun_o, uint256 _collectionID, uint256[] memory _numberOfTokens) public FunctionAdminRequired(this.airDropTokens.selector) {
196: function mint(uint256 _collectionID, uint256 _numberOfTokens, uint256 _maxAllowance, string memory _tokenData, address _mintTo, bytes32[] calldata merkleProof, address _delegator, uint256 _saltfun_o) public payable {
258: function burnToMint(uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, uint256 _saltfun_o) public payable {
276: function mintAndAuction(address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint _auctionEndTime) public FunctionAdminRequired(this.mintAndAuction.selector) {
326: function burnOrSwapExternalToMint(address _erc721Collection, uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, string memory _tokenData, bytes32[] calldata merkleProof, uint256 _saltfun_o) public payable {
369: function setPrimaryAndSecondarySplits(uint256 _collectionID, uint256 _artistPrSplit, uint256 _teamPrSplit, uint256 _artistSecSplit, uint256 _teamSecSplit) public FunctionAdminRequired(this.setPrimaryAndSecondarySplits.selector) {
380: function proposePrimaryAddressesAndPercentages(uint256 _collectionID, address _primaryAdd1, address _primaryAdd2, address _primaryAdd3, uint256 _add1Percentage, uint256 _add2Percentage, uint256 _add3Percentage) public ArtistOrAdminRequired(_collectionID, this.proposePrimaryAddressesAndPercentages.selector) {
394: function proposeSecondaryAddressesAndPercentages(uint256 _collectionID, address _secondaryAdd1, address _secondaryAdd2, address _secondaryAdd3, uint256 _add1Percentage, uint256 _add2Percentage, uint256 _add3Percentage) public ArtistOrAdminRequired(_collectionID, this.proposeSecondaryAddressesAndPercentages.selector) {
415: function payArtist(uint256 _collectionID, address _team1, address _team2, uint256 _teamperc1, uint256 _teamperc2) public FunctionAdminRequired(this.payArtist.selector) {
454: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
[157, 170, 181, 196, 258, 276, 326, 369, 380, 394, 415, 454]
File: smart-contracts/NextGenAdmins.sol
58: function registerCollectionAdmin(uint256 _collectionID, address _address, bool _status) public AdminRequired {
[58]
File: smart-contracts/NextGenCore.sol
147: function setCollectionData(uint256 _collectionID, address _collectionArtistAddress, uint256 _maxCollectionPurchases, uint256 _collectionTotalSupply, uint _setFinalSupplyTimeAfterMint) public CollectionAdminRequired(_collectionID, this.setCollectionData.selector) {
170: function addRandomizer(uint256 _collectionID, address _randomizerContract) public FunctionAdminRequired(this.addRandomizer.selector) {
178: function airDropTokens(uint256 mintIndex, address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID) external {
189: function mint(uint256 mintIndex, address _mintingAddress , address _mintTo, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint256 phase) external {
204: function burn(uint256 _collectionID, uint256 _tokenId) public {
213: function burnToMint(uint256 mintIndex, uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, uint256 _saltfun_o, address burner) external {
238: function updateCollectionInfo(uint256 _collectionID, string memory _newCollectionName, string memory _newCollectionArtist, string memory _newCollectionDescription, string memory _newCollectionWebsite, string memory _newCollectionLicense, string memory _newCollectionBaseURI, string memory _newCollectionLibrary, uint256 _index, string[] memory _newCollectionScript) public CollectionAdminRequired(_collectionID, this.updateCollectionInfo.selector) {
257: function artistSignature(uint256 _collectionID, string memory _signature) public {
266: function changeMetadataView(uint256 _collectionID, bool _status) public CollectionAdminRequired(_collectionID, this.changeMetadataView.selector) {
273: function changeTokenData(uint256 _tokenId, string memory newData) public FunctionAdminRequired(this.changeTokenData.selector) {
281: function updateImagesAndAttributes(uint256[] memory _tokenId, string[] memory _images, string[] memory _attributes) public FunctionAdminRequired(this.updateImagesAndAttributes.selector) {
292: function freezeCollection(uint256 _collectionID) public FunctionAdminRequired(this.freezeCollection.selector) {
299: function setTokenHash(uint256 _collectionID, uint256 _mintIndex, bytes32 _hash) external {
307: function setFinalSupply(uint256 _collectionID) public FunctionAdminRequired(this.setFinalSupply.selector) {
315: function addMinterContract(address _minterContract) public FunctionAdminRequired(this.addMinterContract.selector) {
322: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
[147, 170, 178, 189, 204, 213, 238, 257, 266, 273, 281, 292, 299, 307, 315, 322]
File: smart-contracts/RandomizerNXT.sol
55: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
[55]
File: smart-contracts/RandomizerRNG.sol
53: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
61: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
File: smart-contracts/RandomizerVRF.sol
71: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
94: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
Consider using SafeTransferLib.safeTransferETH
or Address.sendValue
for clearer semantic meaning instead of using a low level call
.
There are 11 instances of this issue.
File: smart-contracts/AuctionDemo.sol
113: (bool success, ) = payable(owner()).call{value: highestBid}("");
116: (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}("");
128: (bool success, ) = payable(auctionInfoData[_tokenid][index].bidder).call{value: auctionInfoData[_tokenid][index].bid}("");
139: (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}("");
File: smart-contracts/MinterContract.sol
434: (bool success1, ) = payable(collectionArtistPrimaryAddresses[colId].primaryAdd1).call{value: artistRoyalties1}("");
435: (bool success2, ) = payable(collectionArtistPrimaryAddresses[colId].primaryAdd2).call{value: artistRoyalties2}("");
436: (bool success3, ) = payable(collectionArtistPrimaryAddresses[colId].primaryAdd3).call{value: artistRoyalties3}("");
437: (bool success4, ) = payable(tm1).call{value: teamRoyalties1}("");
438: (bool success5, ) = payable(tm2).call{value: teamRoyalties2}("");
464: (bool success, ) = payable(admin).call{value: balance}("");
[434, 435, 436, 437, 438, 464]
File: smart-contracts/RandomizerRNG.sol
82: (bool success, ) = payable(admin).call{value: balance}("");
[82]
Constants should be defined instead of using magic numbers.
There are 30 instances of this issue.
Expand findings
File: smart-contracts/MinterContract.sol
// @audit 0x0000000000000000000000000000000000000000
205: if (_delegator != 0x0000000000000000000000000000000000000000) {
// @audit 0x8888888888888888888888888888888888888888
207: isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(_delegator, 0x8888888888888888888888888888888888888888, msg.sender, 1) || dmc.retrieveGlobalStatusOfDelegation(_delegator, 0x8888888888888888888888888888888888888888, msg.sender, 2);
// @audit 0x8888888888888888888888888888888888888888
207: isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(_delegator, 0x8888888888888888888888888888888888888888, msg.sender, 1) || dmc.retrieveGlobalStatusOfDelegation(_delegator, 0x8888888888888888888888888888888888888888, msg.sender, 2);
// @audit 3
240: if (collectionPhases[col].salesOption == 3) {
// @audit 0x8888888888888888888888888888888888888888
333: isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(ownerOfToken, 0x8888888888888888888888888888888888888888, msg.sender, 1) || dmc.retrieveGlobalStatusOfDelegation(ownerOfToken, 0x8888888888888888888888888888888888888888, msg.sender, 2);
// @audit 0x8888888888888888888888888888888888888888
333: isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(ownerOfToken, 0x8888888888888888888888888888888888888888, msg.sender, 1) || dmc.retrieveGlobalStatusOfDelegation(ownerOfToken, 0x8888888888888888888888888888888888888888, msg.sender, 2);
// @audit 100
370: require(_artistPrSplit + _teamPrSplit == 100, "splits need to be 100%");
// @audit 100
371: require(_artistSecSplit + _teamSecSplit == 100, "splits need to be 100%");
// @audit 100
418: require(collectionRoyaltiesPrimarySplits[_collectionID].artistPercentage + _teamperc1 + _teamperc2 == 100, "Change percentages");
// @audit 100
429: artistRoyalties1 = royalties * collectionArtistPrimaryAddresses[colId].add1Percentage / 100;
// @audit 100
430: artistRoyalties2 = royalties * collectionArtistPrimaryAddresses[colId].add2Percentage / 100;
// @audit 100
431: artistRoyalties3 = royalties * collectionArtistPrimaryAddresses[colId].add3Percentage / 100;
// @audit 100
432: teamRoyalties1 = royalties * _teamperc1 / 100;
// @audit 100
433: teamRoyalties2 = royalties * _teamperc2 / 100;
// @audit 3
532: if (collectionPhases[_collectionId].salesOption == 3) {
[205, 207, 207, 240, 333, 333, 370, 371, 418, 429, 430, 431, 432, 433, 532]
File: smart-contracts/NextGenCore.sol
// @audit 0x1B1289E34Fe05019511d7b436a5138F361904df0
111: _setDefaultRoyalty(0x1B1289E34Fe05019511d7b436a5138F361904df0, 690);
// @audit 690
111: _setDefaultRoyalty(0x1B1289E34Fe05019511d7b436a5138F361904df0, 690);
// @audit 10000000000
148: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false) && (_collectionTotalSupply <= 10000000000), "err/freezed");
// @audit 10000000000
155: collectionAdditionalData[_collectionID].reservedMinTokensIndex = (_collectionID * 10000000000);
// @audit 10000000000
156: collectionAdditionalData[_collectionID].reservedMaxTokensIndex = (_collectionID * 10000000000) + _collectionTotalSupply - 1;
// @audit 1000
240: if (_index == 1000) {
// @audit 999
248: } else if (_index == 999) {
// @audit 0x0000000000000000000000000000000000000000000000000000000000000000
301: require(tokenToHash[_mintIndex] == 0x0000000000000000000000000000000000000000000000000000000000000000);
// @audit 10000000000
310: collectionAdditionalData[_collectionID].reservedMaxTokensIndex = (_collectionID * 10000000000) + collectionAdditionalData[_collectionID].collectionTotalSupply - 1;
// @audit 0x0000000000000000000000000000000000000000000000000000000000000000
345: if (onchainMetadata[tokenIdsToCollectionIds[tokenId]] == false && tokenToHash[tokenId] != 0x0000000000000000000000000000000000000000000000000000000000000000) {
// @audit 0x0000000000000000000000000000000000000000000000000000000000000000
348: } else if (onchainMetadata[tokenIdsToCollectionIds[tokenId]] == false && tokenToHash[tokenId] == 0x0000000000000000000000000000000000000000000000000000000000000000) {
// @audit 32
456: return string(abi.encodePacked("let hash='",Strings.toHexString(uint256(tokenToHash[tokenId]), 32),"';let tokenId=",tokenId.toString(),";let tokenData=[",tokenData[tokenId],"];", scripttext));
[111, 111, 148, 155, 156, 240, 248, 301, 310, 345, 348, 456]
File: smart-contracts/XRandoms.sol
// @audit 100
18: string[100] memory wordsList = ["Acai", "Ackee", "Apple", "Apricot", "Avocado", "Babaco", "Banana", "Bilberry", "Blackberry", "Blackcurrant", "Blood Orange",
// @audit 1000
36: uint256 randomNum = uint(keccak256(abi.encodePacked(block.prevrandao, blockhash(block.number - 1), block.timestamp))) % 1000;
// @audit 100
41: uint256 randomNum = uint(keccak256(abi.encodePacked(block.prevrandao, blockhash(block.number - 1), block.timestamp))) % 100;
Consider splitting long arithmetic calculations into multiple steps to improve the code readability.
There are 5 instances of this issue.
File: smart-contracts/MinterContract.sol
295: lastMintDate[_collectionID] = collectionPhases[_collectionID].allowlistStartTime + (collectionPhases[_collectionID].timePeriod * (gencore.viewCirSupply(_collectionID) - 1));
551: decreaserate = ((price - (collectionPhases[_collectionId].collectionMintCost / (tDiff + 2))) / collectionPhases[_collectionId].timePeriod) * ((block.timestamp - (tDiff * collectionPhases[_collectionId].timePeriod) - collectionPhases[_collectionId].allowlistStartTime));
536: return collectionPhases[_collectionId].collectionMintCost + ((collectionPhases[_collectionId].collectionMintCost / collectionPhases[_collectionId].rate) * gencore.viewCirSupply(_collectionId));
File: smart-contracts/NextGenCore.sol
156: collectionAdditionalData[_collectionID].reservedMaxTokensIndex = (_collectionID * 10000000000) + _collectionTotalSupply - 1;
310: collectionAdditionalData[_collectionID].reservedMaxTokensIndex = (_collectionID * 10000000000) + collectionAdditionalData[_collectionID].collectionTotalSupply - 1;
This is a best practice that should be followed.
There are 3 instances of this issue.
File: smart-contracts/MinterContract.sol
540: } else if (collectionPhases[_collectionId].salesOption == 2 && block.timestamp > collectionPhases[_collectionId].allowlistStartTime && block.timestamp < collectionPhases[_collectionId].publicEndTime){
// @audit should be for (
187: for(uint256 i = 0; i < _numberOfTokens[y]; i++) {
// @audit should be for (
234: for(uint256 i = 0; i < _numberOfTokens; i++) {
Locking the pragma helps avoid accidental deploys with an outdated compiler version that may introduce bugs and unexpected vulnerabilities.
Floating pragma is meant to be used for libraries and contracts that have external users and need backward compatibility.
There are 8 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
11: pragma solidity ^0.8.19;
[11]
File: smart-contracts/MinterContract.sol
11: pragma solidity ^0.8.19;
[11]
File: smart-contracts/NextGenAdmins.sol
11: pragma solidity ^0.8.19;
[11]
File: smart-contracts/NextGenCore.sol
11: pragma solidity ^0.8.19;
[11]
File: smart-contracts/RandomizerNXT.sol
11: pragma solidity ^0.8.19;
[11]
File: smart-contracts/RandomizerRNG.sol
11: pragma solidity ^0.8.19;
[11]
File: smart-contracts/RandomizerVRF.sol
11: pragma solidity ^0.8.19;
[11]
File: smart-contracts/XRandoms.sol
11: pragma solidity ^0.8.19;
[11]
Like the zero-address check, an empty bytes assignment might be undesiderable, but the following functions don't have it.
There are 3 instances of this issue.
File: smart-contracts/MinterContract.sol
// @audit _merkleRoot
170: function setCollectionPhases(uint256 _collectionID, uint _allowlistStartTime, uint _allowlistEndTime, uint _publicStartTime, uint _publicEndTime, bytes32 _merkleRoot) public CollectionAdminRequired(_collectionID, this.setCollectionPhases.selector) {
[170]
File: smart-contracts/NextGenCore.sol
// @audit _hash
299: function setTokenHash(uint256 _collectionID, uint256 _mintIndex, bytes32 _hash) external {
[299]
File: smart-contracts/RandomizerVRF.sol
// @audit _keyHash
79: function updatecallbackGasLimitAndkeyHash(uint32 _callbackGasLimit, bytes32 _keyHash) public FunctionAdminRequired(this.updatecallbackGasLimitAndkeyHash.selector){
[79]
Starting from version 0.8.4
, the recommended approach for appending bytes is to use bytes.concat
/string.concat
instead of abi.encodePacked
.
There are 4 instances of this issue.
File: smart-contracts/NextGenCore.sol
347: return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
350: return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, "pending")) : "";
File: smart-contracts/XRandoms.sol
36: uint256 randomNum = uint(keccak256(abi.encodePacked(block.prevrandao, blockhash(block.number - 1), block.timestamp))) % 1000;
41: uint256 randomNum = uint(keccak256(abi.encodePacked(block.prevrandao, blockhash(block.number - 1), block.timestamp))) % 100;
All external
/public
functions should extend an interface
. This is useful to make sure that the whole API is extracted.
There are 102 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
57: function participateToAuction(uint256 _tokenid) public payable {
65: function returnHighestBid(uint256 _tokenid) public view returns (uint256) {
87: function returnHighestBidder(uint256 _tokenid) public view returns (address) {
104: function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){
124: function cancelBid(uint256 _tokenid, uint256 index) public {
134: function cancelAllBids(uint256 _tokenid) public {
147: function returnBids(uint256 _tokenid) public view returns(auctionInfoStru[] memory) {
[57, 65, 87, 104, 124, 134, 147]
File: smart-contracts/MinterContract.sol
157: function setCollectionCosts(uint256 _collectionID, uint256 _collectionMintCost, uint256 _collectionEndMintCost, uint256 _rate, uint256 _timePeriod, uint8 _salesOption, address _delAddress) public CollectionAdminRequired(_collectionID, this.setCollectionCosts.selector) {
170: function setCollectionPhases(uint256 _collectionID, uint _allowlistStartTime, uint _allowlistEndTime, uint _publicStartTime, uint _publicEndTime, bytes32 _merkleRoot) public CollectionAdminRequired(_collectionID, this.setCollectionPhases.selector) {
181: function airDropTokens(address[] memory _recipients, string[] memory _tokenData, uint256[] memory _saltfun_o, uint256 _collectionID, uint256[] memory _numberOfTokens) public FunctionAdminRequired(this.airDropTokens.selector) {
196: function mint(uint256 _collectionID, uint256 _numberOfTokens, uint256 _maxAllowance, string memory _tokenData, address _mintTo, bytes32[] calldata merkleProof, address _delegator, uint256 _saltfun_o) public payable {
258: function burnToMint(uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, uint256 _saltfun_o) public payable {
276: function mintAndAuction(address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint _auctionEndTime) public FunctionAdminRequired(this.mintAndAuction.selector) {
302: function updateDelegationCollection(uint256 _collectionID, address _collectionAddress) public FunctionAdminRequired(this.updateDelegationCollection.selector) {
308: function initializeBurn(uint256 _burnCollectionID, uint256 _mintCollectionID, bool _status) public FunctionAdminRequired(this.initializeBurn.selector) {
315: function initializeExternalBurnOrSwap(address _erc721Collection, uint256 _burnCollectionID, uint256 _mintCollectionID, uint256 _tokmin, uint256 _tokmax, address _burnOrSwapAddress, bool _status) public FunctionAdminRequired(this.initializeExternalBurnOrSwap.selector) {
326: function burnOrSwapExternalToMint(address _erc721Collection, uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, string memory _tokenData, bytes32[] calldata merkleProof, uint256 _saltfun_o) public payable {
369: function setPrimaryAndSecondarySplits(uint256 _collectionID, uint256 _artistPrSplit, uint256 _teamPrSplit, uint256 _artistSecSplit, uint256 _teamSecSplit) public FunctionAdminRequired(this.setPrimaryAndSecondarySplits.selector) {
380: function proposePrimaryAddressesAndPercentages(uint256 _collectionID, address _primaryAdd1, address _primaryAdd2, address _primaryAdd3, uint256 _add1Percentage, uint256 _add2Percentage, uint256 _add3Percentage) public ArtistOrAdminRequired(_collectionID, this.proposePrimaryAddressesAndPercentages.selector) {
394: function proposeSecondaryAddressesAndPercentages(uint256 _collectionID, address _secondaryAdd1, address _secondaryAdd2, address _secondaryAdd3, uint256 _add1Percentage, uint256 _add2Percentage, uint256 _add3Percentage) public ArtistOrAdminRequired(_collectionID, this.proposeSecondaryAddressesAndPercentages.selector) {
408: function acceptAddressesAndPercentages(uint256 _collectionID, bool _statusPrimary, bool _statusSecondary) public FunctionAdminRequired(this.acceptAddressesAndPercentages.selector) {
415: function payArtist(uint256 _collectionID, address _team1, address _team2, uint256 _teamperc1, uint256 _teamperc2) public FunctionAdminRequired(this.payArtist.selector) {
448: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
454: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
461: function emergencyWithdraw() public FunctionAdminRequired(this.emergencyWithdraw.selector) {
470: function retrievePrimarySplits(uint256 _collectionID) public view returns(uint256, uint256){
476: function retrievePrimaryAddressesAndPercentages(uint256 _collectionID) public view returns(address, address, address, uint256, uint256, uint256, bool){
482: function retrieveSecondarySplits(uint256 _collectionID) public view returns(uint256, uint256){
488: function retrieveSecondaryAddressesAndPercentages(uint256 _collectionID) public view returns(address, address, address, uint256, uint256, uint256, bool){
494: function retrieveCollectionPhases(uint256 _collectionID) public view returns(uint, uint, bytes32, uint, uint){
500: function retrieveCollectionMintingDetails(uint256 _collectionID) public view returns(uint256, uint256, uint256, uint256, uint8, address){
506: function isMinterContract() external view returns (bool) {
512: function getEndTime(uint256 _collectionID) external view returns (uint) {
518: function getAuctionEndTime(uint256 _tokenId) external view returns (uint) {
524: function getAuctionStatus(uint256 _tokenId) external view returns (bool) {
530: function getPrice(uint256 _collectionId) public view returns (uint256) {
[157, 170, 181, 196, 258, 276, 302, 308, 315, 326, 369, 380, 394, 408, 415, 448, 454, 461, 470, 476, 482, 488, 494, 500, 506, 512, 518, 524, 530]
File: smart-contracts/NextGenAdmins.sol
38: function registerAdmin(address _admin, bool _status) public onlyOwner {
44: function registerFunctionAdmin(address _address, bytes4 _selector, bool _status) public AdminRequired {
50: function registerBatchFunctionAdmin(address _address, bytes4[] memory _selector, bool _status) public AdminRequired {
58: function registerCollectionAdmin(uint256 _collectionID, address _address, bool _status) public AdminRequired {
65: function retrieveGlobalAdmin(address _address) public view returns(bool) {
71: function retrieveFunctionAdmin(address _address, bytes4 _selector) public view returns(bool) {
77: function retrieveCollectionAdmin(address _address, uint256 _collectionID) public view returns(bool) {
83: function isAdminContract() external view returns (bool) {
[38, 44, 50, 58, 65, 71, 77, 83]
File: smart-contracts/NextGenCore.sol
130: function createCollection(string memory _collectionName, string memory _collectionArtist, string memory _collectionDescription, string memory _collectionWebsite, string memory _collectionLicense, string memory _collectionBaseURI, string memory _collectionLibrary, string[] memory _collectionScript) public FunctionAdminRequired(this.createCollection.selector) {
147: function setCollectionData(uint256 _collectionID, address _collectionArtistAddress, uint256 _maxCollectionPurchases, uint256 _collectionTotalSupply, uint _setFinalSupplyTimeAfterMint) public CollectionAdminRequired(_collectionID, this.setCollectionData.selector) {
170: function addRandomizer(uint256 _collectionID, address _randomizerContract) public FunctionAdminRequired(this.addRandomizer.selector) {
178: function airDropTokens(uint256 mintIndex, address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID) external {
189: function mint(uint256 mintIndex, address _mintingAddress , address _mintTo, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint256 phase) external {
204: function burn(uint256 _collectionID, uint256 _tokenId) public {
213: function burnToMint(uint256 mintIndex, uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, uint256 _saltfun_o, address burner) external {
238: function updateCollectionInfo(uint256 _collectionID, string memory _newCollectionName, string memory _newCollectionArtist, string memory _newCollectionDescription, string memory _newCollectionWebsite, string memory _newCollectionLicense, string memory _newCollectionBaseURI, string memory _newCollectionLibrary, uint256 _index, string[] memory _newCollectionScript) public CollectionAdminRequired(_collectionID, this.updateCollectionInfo.selector) {
257: function artistSignature(uint256 _collectionID, string memory _signature) public {
266: function changeMetadataView(uint256 _collectionID, bool _status) public CollectionAdminRequired(_collectionID, this.changeMetadataView.selector) {
273: function changeTokenData(uint256 _tokenId, string memory newData) public FunctionAdminRequired(this.changeTokenData.selector) {
281: function updateImagesAndAttributes(uint256[] memory _tokenId, string[] memory _images, string[] memory _attributes) public FunctionAdminRequired(this.updateImagesAndAttributes.selector) {
292: function freezeCollection(uint256 _collectionID) public FunctionAdminRequired(this.freezeCollection.selector) {
299: function setTokenHash(uint256 _collectionID, uint256 _mintIndex, bytes32 _hash) external {
307: function setFinalSupply(uint256 _collectionID) public FunctionAdminRequired(this.setFinalSupply.selector) {
315: function addMinterContract(address _minterContract) public FunctionAdminRequired(this.addMinterContract.selector) {
322: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
329: function setDefaultRoyalties(address _royaltyAddress, uint96 _bps) public FunctionAdminRequired(this.setDefaultRoyalties.selector) {
367: function collectionFreezeStatus(uint256 _collectionID) public view returns(bool){
372: function viewColIDforTokenID(uint256 _tokenid) public view returns (uint256) {
377: function retrievewereDataAdded(uint256 _collectionID) external view returns(bool){
383: function viewTokensIndexMin(uint256 _collectionID) external view returns (uint256) {
389: function viewTokensIndexMax(uint256 _collectionID) external view returns (uint256) {
394: function viewCirSupply(uint256 _collectionID) external view returns (uint256) {
399: function viewMaxAllowance(uint256 _collectionID) external view returns (uint256) {
404: function retrieveTokensMintedALPerAddress(uint256 _collectionID, address _address) external view returns(uint256) {
409: function retrieveTokensMintedPublicPerAddress(uint256 _collectionID, address _address) external view returns(uint256) {
415: function retrieveTokensAirdroppedPerAddress(uint256 _collectionID, address _address) public view returns(uint256) {
420: function retrieveArtistAddress(uint256 _collectionID) external view returns(address) {
426: function retrieveCollectionInfo(uint256 _collectionID) public view returns(string memory, string memory, string memory, string memory, string memory, string memory){
432: function retrieveCollectionLibraryAndScript(uint256 _collectionID) public view returns(string memory, string[] memory){
438: function retrieveCollectionAdditionalData(uint256 _collectionID) public view returns(address, uint256, uint256, uint256, uint, address){
444: function retrieveTokenHash(uint256 _tokenid) public view returns(bytes32){
450: function retrieveGenerativeScript(uint256 tokenId) public view returns(string memory){
461: function totalSupplyOfCollection(uint256 _collectionID) public view returns (uint256) {
467: function retrievetokenImageAndAttributes(uint256 _tokenId) public view returns(string memory, string memory) {
[130, 147, 170, 178, 189, 204, 213, 238, 257, 266, 273, 281, 292, 299, 307, 315, 322, 329, 367, 372, 377, 383, 389, 394, 399, 404, 409, 415, 420, 426, 432, 438, 444, 450, 461, 467]
File: smart-contracts/RandomizerNXT.sol
41: function updateRandomsContract(address _randoms) public FunctionAdminRequired(this.updateRandomsContract.selector) {
45: function updateAdminsContract(address _admin) public FunctionAdminRequired(this.updateAdminsContract.selector) {
49: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
55: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
62: function isRandomizerContract() external view returns (bool) {
File: smart-contracts/RandomizerRNG.sol
40: function requestRandomWords(uint256 tokenid, uint256 _ethRequired) public payable {
53: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
61: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
66: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
73: function updateRNGCost(uint256 _ethRequired) public FunctionAdminRequired(this.updateRNGCost.selector) {
79: function emergencyWithdraw() public FunctionAdminRequired(this.emergencyWithdraw.selector) {
89: function isRandomizerContract() external view returns (bool) {
File: smart-contracts/RandomizerVRF.sol
52: function requestRandomWords(uint256 tokenid) public {
71: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
79: function updatecallbackGasLimitAndkeyHash(uint32 _callbackGasLimit, bytes32 _keyHash) public FunctionAdminRequired(this.updatecallbackGasLimitAndkeyHash.selector){
86: function updateAdditionalData(uint64 _s_subscriptionId, uint32 _numWords, uint16 _requestConfirmations) public FunctionAdminRequired(this.updateAdditionalData.selector){
94: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
99: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
105: function isRandomizerContract() external view returns (bool) {
File: smart-contracts/XRandoms.sol
35: function randomNumber() public view returns (uint256){
40: function randomWord() public view returns (string memory) {
45: function returnIndex(uint256 id) public view returns (string memory) {
If a transaction reverts, it can be confusing to debug if there aren't any messages. Add a descriptive message to all require
/revert
statements.
There are 10 instances of this issue.
File: smart-contracts/AuctionDemo.sol
58: require(msg.value > returnHighestBid(_tokenid) && block.timestamp <= minter.getAuctionEndTime(_tokenid) && minter.getAuctionStatus(_tokenid) == true);
105: require(block.timestamp >= minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true);
126: require(auctionInfoData[_tokenid][index].bidder == msg.sender && auctionInfoData[_tokenid][index].status == true);
File: smart-contracts/NextGenCore.sol
300: require(msg.sender == collectionAdditionalData[_collectionID].randomizerContract);
301: require(tokenToHash[_mintIndex] == 0x0000000000000000000000000000000000000000000000000000000000000000);
File: smart-contracts/RandomizerNXT.sol
56: require(msg.sender == gencore);
[56]
File: smart-contracts/RandomizerRNG.sol
41: require(msg.sender == gencore);
54: require(msg.sender == gencore);
File: smart-contracts/RandomizerVRF.sol
53: require(msg.sender == gencore);
72: require(msg.sender == gencore);
Consider moving the logic outside the else
block, and then removing it (it's not required, as the function is returning a value). There will be one less level of nesting, which will improve the quality of the codebase.
There are 6 instances of this issue.
File: smart-contracts/AuctionDemo.sol
80: } else {
81: return 0;
82: }
77: } else {
78: return 0;
79: }
97: } else {
98: revert("No Active Bidder");
99: }
File: smart-contracts/MinterContract.sol
537: } else {
538: return collectionPhases[_collectionId].collectionMintCost;
539: }
561: } else {
562: return collectionPhases[_collectionId].collectionEndMintCost;
563: }
File: smart-contracts/XRandoms.sol
30: } else {
31: return wordsList[id - 1];
32: }
[30-32]
[N-33] Multiple address
/ID mappings can be combined into a single mapping of an address
/ID to a struct
, for readability
Well-organized data structures make code reviews easier, which may lead to fewer bugs. Consider combining related mappings into mappings to structs, so it's clear what data is related.
There are 12 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
// @audit consider merging auctionInfoData, auctionClaim
50: mapping (uint256 => auctionInfoStru[]) public auctionInfoData;
53: mapping (uint256 => bool) public auctionClaim;
[50]
File: smart-contracts/MinterContract.sol
// @audit consider merging collectionTotalAmount, burnToMintCollections, collectionPhases
23: mapping (uint256 => uint256) public collectionTotalAmount;
35: mapping (uint256 => mapping (uint256 => bool)) public burnToMintCollections;
59: mapping (uint256 => collectionPhasesDataStructure) private collectionPhases;
// @audit consider merging burnOrSwapAddress, burnOrSwapIds
29: mapping (bytes32 => address) public burnOrSwapAddress;
32: mapping (bytes32 => uint256[2]) private burnOrSwapIds;
// @audit consider merging collectionRoyaltiesPrimarySplits, collectionArtistPrimaryAddresses, collectionRoyaltiesSecondarySplits, collectionArtistSecondaryAddresses
70: mapping (uint256 => royaltiesPrimarySplits) private collectionRoyaltiesPrimarySplits;
84: mapping (uint256 => collectionPrimaryAddresses) private collectionArtistPrimaryAddresses;
95: mapping (uint256 => royaltiesSecondarySplits) private collectionRoyaltiesSecondarySplits;
109: mapping (uint256 => collectionSecondaryAddresses) private collectionArtistSecondaryAddresses;
// @audit consider merging mintToAuctionData, mintToAuctionStatus
112: mapping (uint256 => uint) private mintToAuctionData;
115: mapping (uint256 => bool) private mintToAuctionStatus;
File: smart-contracts/NextGenAdmins.sol
// @audit consider merging collectionAdmin, functionAdmin
21: mapping (address => mapping (uint256 => bool)) private collectionAdmin;
24: mapping (address => mapping (bytes4 => bool)) private functionAdmin;
[21]
File: smart-contracts/NextGenCore.sol
// @audit consider merging collectionInfo, collectionAdditionalData, isCollectionCreated, tokenIdsToCollectionIds, collectionFreeze
41: mapping (uint256 => collectionInfoStructure) private collectionInfo;
57: mapping (uint256 => collectionAdditonalDataStructure) private collectionAdditionalData;
62: mapping (uint256 => bool) private isCollectionCreated;
68: mapping (uint256 => uint256) private tokenIdsToCollectionIds;
98: mapping (uint256 => bool) private collectionFreeze;
// @audit consider merging tokensMintedPerAddress, tokensMintedAllowlistAddress, tokensAirdropPerAddress
74: mapping (uint256 => mapping (address => uint256)) private tokensMintedPerAddress;
77: mapping (uint256 => mapping (address => uint256)) private tokensMintedAllowlistAddress;
80: mapping (uint256 => mapping (address => uint256)) private tokensAirdropPerAddress;
// @audit consider merging artistsSignatures, artistSigned
89: mapping (uint256 => string) public artistsSignatures;
101: mapping (uint256 => bool) public artistSigned;
// @audit consider merging tokenData, tokenImageAndAttributes
92: mapping (uint256 => string) public tokenData;
95: mapping (uint256 => string[2]) private tokenImageAndAttributes;
File: smart-contracts/RandomizerRNG.sol
// @audit consider merging requestToToken, tokenToRequest
20: mapping(uint256 => uint256) public requestToToken;
26: mapping(uint256 => uint256) public tokenToRequest;
[20]
File: smart-contracts/RandomizerVRF.sol
// @audit consider merging tokenToRequest, requestToToken
32: mapping(uint256 => uint256) public tokenToRequest;
33: mapping(uint256 => uint256) public requestToToken;
[32]
It is better to use import {<identifier>} from "<file.sol>"
instead of import "<file.sol>"
to improve readability and speed up the compilation time.
There are 32 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
13: import "./IMinterContract.sol";
14: import "./IERC721.sol";
15: import "./Ownable.sol";
16: import "./INextGenAdmins.sol";
File: smart-contracts/MinterContract.sol
13: import "./INextGenCore.sol";
14: import "./Ownable.sol";
15: import "./IDelegationManagementContract.sol";
16: import "./MerkleProof.sol";
17: import "./INextGenAdmins.sol";
18: import "./IERC721.sol";
File: smart-contracts/NextGenAdmins.sol
13: import "./Ownable.sol";
[13]
File: smart-contracts/NextGenCore.sol
13: import "./ERC721Enumerable.sol";
14: import "./Ownable.sol";
15: import "./Strings.sol";
16: import "./Base64.sol";
17: import "./IRandomizer.sol";
18: import "./INextGenAdmins.sol";
19: import "./IMinterContract.sol";
20: import "./ERC2981.sol";
[13, 14, 15, 16, 17, 18, 19, 20]
File: smart-contracts/RandomizerNXT.sol
13: import "./IXRandoms.sol";
14: import "./INextGenAdmins.sol";
15: import "./Ownable.sol";
16: import "./INextGenCore.sol";
File: smart-contracts/RandomizerRNG.sol
13: import "./ArrngConsumer.sol";
14: import "./Ownable.sol";
15: import "./INextGenCore.sol";
16: import "./INextGenAdmins.sol";
File: smart-contracts/RandomizerVRF.sol
13: import "./VRFCoordinatorV2Interface.sol";
14: import "./VRFConsumerBaseV2.sol";
15: import "./Ownable.sol";
16: import "./INextGenCore.sol";
17: import "./INextGenAdmins.sol";
The contract's interface should be imported first, followed by each of the interfaces it uses, followed by all other files. The examples below do not follow this layout.
There are 4 instances of this issue.
File: smart-contracts/AuctionDemo.sol
15: import "./Ownable.sol";
[15]
File: smart-contracts/MinterContract.sol
14: import "./Ownable.sol";
[14]
File: smart-contracts/NextGenCore.sol
20: import "./ERC2981.sol";
[20]
File: smart-contracts/RandomizerVRF.sol
14: import "./VRFConsumerBaseV2.sol";
[14]
The following functions are missing some parameters when emitting an event: when dealing with a source address which uses the value of msg.sender
, the msg.sender
value should be specified in every event.
Otherwise, a contract or web page listening to events cannot react to connected users: basically, those events cannot be used properly.
There are 7 instances of this issue.
File: smart-contracts/AuctionDemo.sol
117: emit Refund(auctionInfoData[_tokenid][i].bidder, _tokenid, success, highestBid);
[117]
File: smart-contracts/MinterContract.sol
439: emit PayArtist(collectionArtistPrimaryAddresses[colId].primaryAdd1, success1, artistRoyalties1);
440: emit PayArtist(collectionArtistPrimaryAddresses[colId].primaryAdd2, success2, artistRoyalties2);
441: emit PayArtist(collectionArtistPrimaryAddresses[colId].primaryAdd3, success3, artistRoyalties3);
442: emit PayTeam(tm1, success4, teamRoyalties1);
443: emit PayTeam(tm2, success5, teamRoyalties2);
File: smart-contracts/RandomizerVRF.sol
67: emit RequestFulfilled(_requestId, _randomWords);
[67]
Surround top level declarations in Solidity source with two blank lines. Documentation
There are 10 instances of this issue.
Expand findings
File: smart-contracts/RandomizerNXT.sol
43: }
44:
45: function updateAdminsContract(address _admin) public FunctionAdminRequired(this.updateAdminsContract.selector) {
47: }
48:
49: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
File: smart-contracts/RandomizerRNG.sol
46: }
47:
48: function fulfillRandomWords(uint256 id, uint256[] memory numbers) internal override {
64: }
65:
66: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
84: }
85:
86: receive() external payable {}
File: smart-contracts/RandomizerVRF.sol
63: }
64:
65: function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override {
97: }
98:
99: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
File: smart-contracts/XRandoms.sol
33: }
34:
35: function randomNumber() public view returns (uint256){
38: }
39:
40: function randomWord() public view returns (string memory) {
43: }
44:
45: function returnIndex(uint256 id) public view returns (string memory) {
If a function has too many parameters, replacing them with a struct can improve code readability and maintainability, increase reusability, and reduce the likelihood of errors when passing the parameters.
There are 18 instances of this issue.
File: smart-contracts/MinterContract.sol
157: function setCollectionCosts(uint256 _collectionID, uint256 _collectionMintCost, uint256 _collectionEndMintCost, uint256 _rate, uint256 _timePeriod, uint8 _salesOption, address _delAddress) public CollectionAdminRequired(_collectionID, this.setCollectionCosts.selector) {
170: function setCollectionPhases(uint256 _collectionID, uint _allowlistStartTime, uint _allowlistEndTime, uint _publicStartTime, uint _publicEndTime, bytes32 _merkleRoot) public CollectionAdminRequired(_collectionID, this.setCollectionPhases.selector) {
181: function airDropTokens(address[] memory _recipients, string[] memory _tokenData, uint256[] memory _saltfun_o, uint256 _collectionID, uint256[] memory _numberOfTokens) public FunctionAdminRequired(this.airDropTokens.selector) {
196: function mint(uint256 _collectionID, uint256 _numberOfTokens, uint256 _maxAllowance, string memory _tokenData, address _mintTo, bytes32[] calldata merkleProof, address _delegator, uint256 _saltfun_o) public payable {
276: function mintAndAuction(address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint _auctionEndTime) public FunctionAdminRequired(this.mintAndAuction.selector) {
315: function initializeExternalBurnOrSwap(address _erc721Collection, uint256 _burnCollectionID, uint256 _mintCollectionID, uint256 _tokmin, uint256 _tokmax, address _burnOrSwapAddress, bool _status) public FunctionAdminRequired(this.initializeExternalBurnOrSwap.selector) {
326: function burnOrSwapExternalToMint(address _erc721Collection, uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, string memory _tokenData, bytes32[] calldata merkleProof, uint256 _saltfun_o) public payable {
369: function setPrimaryAndSecondarySplits(uint256 _collectionID, uint256 _artistPrSplit, uint256 _teamPrSplit, uint256 _artistSecSplit, uint256 _teamSecSplit) public FunctionAdminRequired(this.setPrimaryAndSecondarySplits.selector) {
380: function proposePrimaryAddressesAndPercentages(uint256 _collectionID, address _primaryAdd1, address _primaryAdd2, address _primaryAdd3, uint256 _add1Percentage, uint256 _add2Percentage, uint256 _add3Percentage) public ArtistOrAdminRequired(_collectionID, this.proposePrimaryAddressesAndPercentages.selector) {
394: function proposeSecondaryAddressesAndPercentages(uint256 _collectionID, address _secondaryAdd1, address _secondaryAdd2, address _secondaryAdd3, uint256 _add1Percentage, uint256 _add2Percentage, uint256 _add3Percentage) public ArtistOrAdminRequired(_collectionID, this.proposeSecondaryAddressesAndPercentages.selector) {
415: function payArtist(uint256 _collectionID, address _team1, address _team2, uint256 _teamperc1, uint256 _teamperc2) public FunctionAdminRequired(this.payArtist.selector) {
[157, 170, 181, 196, 276, 315, 326, 369, 380, 394, 415]
File: smart-contracts/NextGenCore.sol
130: function createCollection(string memory _collectionName, string memory _collectionArtist, string memory _collectionDescription, string memory _collectionWebsite, string memory _collectionLicense, string memory _collectionBaseURI, string memory _collectionLibrary, string[] memory _collectionScript) public FunctionAdminRequired(this.createCollection.selector) {
147: function setCollectionData(uint256 _collectionID, address _collectionArtistAddress, uint256 _maxCollectionPurchases, uint256 _collectionTotalSupply, uint _setFinalSupplyTimeAfterMint) public CollectionAdminRequired(_collectionID, this.setCollectionData.selector) {
178: function airDropTokens(uint256 mintIndex, address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID) external {
189: function mint(uint256 mintIndex, address _mintingAddress , address _mintTo, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint256 phase) external {
213: function burnToMint(uint256 mintIndex, uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, uint256 _saltfun_o, address burner) external {
227: function _mintProcessing(uint256 _mintIndex, address _recipient, string memory _tokenData, uint256 _collectionID, uint256 _saltfun_o) internal {
238: function updateCollectionInfo(uint256 _collectionID, string memory _newCollectionName, string memory _newCollectionArtist, string memory _newCollectionDescription, string memory _newCollectionWebsite, string memory _newCollectionLicense, string memory _newCollectionBaseURI, string memory _newCollectionLibrary, uint256 _index, string[] memory _newCollectionScript) public CollectionAdminRequired(_collectionID, this.updateCollectionInfo.selector) {
[130, 147, 178, 189, 213, 227, 238]
If a function returns too many variables, replacing them with a struct can improve code readability, maintainability and reusability.
There are 6 instances of this issue.
File: smart-contracts/MinterContract.sol
476: function retrievePrimaryAddressesAndPercentages(uint256 _collectionID) public view returns(address, address, address, uint256, uint256, uint256, bool){
488: function retrieveSecondaryAddressesAndPercentages(uint256 _collectionID) public view returns(address, address, address, uint256, uint256, uint256, bool){
494: function retrieveCollectionPhases(uint256 _collectionID) public view returns(uint, uint, bytes32, uint, uint){
500: function retrieveCollectionMintingDetails(uint256 _collectionID) public view returns(uint256, uint256, uint256, uint256, uint8, address){
File: smart-contracts/NextGenCore.sol
426: function retrieveCollectionInfo(uint256 _collectionID) public view returns(string memory, string memory, string memory, string memory, string memory, string memory){
438: function retrieveCollectionAdditionalData(uint256 _collectionID) public view returns(address, uint256, uint256, uint256, uint, address){
If a reentrancy occurs, some events may be emitted in an unexpected order, and this may be a problem if a third party expects a specific order for these events. Ensure that events follow the best practice of CEI.
There are 3 instances of this issue.
File: smart-contracts/AuctionDemo.sol
// @audit IERC721(gencore).ownerOf(_tokenid)
114: emit ClaimAuction(owner(), _tokenid, success, highestBid);
// @audit IERC721(gencore).ownerOf(_tokenid)
117: emit Refund(auctionInfoData[_tokenid][i].bidder, _tokenid, success, highestBid);
File: smart-contracts/RandomizerVRF.sol
// @audit gencoreContract.setTokenHash(tokenIdToCollection[requestToToken[_requestId]], requestToToken[_requestId], bytes32(abi.encodePacked(_randomWords,requestToToken[_requestId])))
67: emit RequestFulfilled(_requestId, _randomWords);
[67]
If some functions are only allowed to be called by some specific users, consider using a modifier
instead of checking with a require
statement, especially if this check is done in multiple functions.
There are 13 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
126: require(auctionInfoData[_tokenid][index].bidder == msg.sender && auctionInfoData[_tokenid][index].status == true);
[126]
File: smart-contracts/MinterContract.sol
217: require(_maxAllowance >= gencore.retrieveTokensMintedALPerAddress(col, msg.sender) + _numberOfTokens, "AL limit");
224: require(gencore.retrieveTokensMintedPublicPerAddress(col, msg.sender) + _numberOfTokens <= gencore.viewMaxAllowance(col), "Max");
File: smart-contracts/NextGenCore.sol
179: require(msg.sender == minterContract, "Caller is not the Minter Contract");
190: require(msg.sender == minterContract, "Caller is not the Minter Contract");
214: require(msg.sender == minterContract, "Caller is not the Minter Contract");
258: require(msg.sender == collectionAdditionalData[_collectionID].collectionArtistAddress, "Only artist");
300: require(msg.sender == collectionAdditionalData[_collectionID].randomizerContract);
File: smart-contracts/RandomizerNXT.sol
56: require(msg.sender == gencore);
[56]
File: smart-contracts/RandomizerRNG.sol
41: require(msg.sender == gencore);
54: require(msg.sender == gencore);
File: smart-contracts/RandomizerVRF.sol
53: require(msg.sender == gencore);
72: require(msg.sender == gencore);
Variables which are not constants or immutable should not be declared in all uppercase.
There is 1 instance of this issue.
File: smart-contracts/RandomizerVRF.sol
22: VRFCoordinatorV2Interface public COORDINATOR;
[22]
This is useful to avoid doing some typo bugs.
There are 19 instances of this issue.
File: smart-contracts/MinterContract.sol
205: if (_delegator != 0x0000000000000000000000000000000000000000) {
240: if (collectionPhases[col].salesOption == 3) {
242: if (lastMintDate[col] == 0) {
251: require(tDiff>=1 && _numberOfTokens == 1, "1 mint/period");
285: if (lastMintDate[_collectionID] == 0) {
370: require(_artistPrSplit + _teamPrSplit == 100, "splits need to be 100%");
371: require(_artistSecSplit + _teamSecSplit == 100, "splits need to be 100%");
418: require(collectionRoyaltiesPrimarySplits[_collectionID].artistPercentage + _teamperc1 + _teamperc2 == 100, "Change percentages");
532: if (collectionPhases[_collectionId].salesOption == 3) {
540: } else if (collectionPhases[_collectionId].salesOption == 2 && block.timestamp > collectionPhases[_collectionId].allowlistStartTime && block.timestamp < collectionPhases[_collectionId].publicEndTime){
549: if (collectionPhases[_collectionId].rate == 0) {
[205, 240, 242, 251, 285, 370, 371, 418, 532, 540, 549]
File: smart-contracts/NextGenCore.sol
149: if (collectionAdditionalData[_collectionID].collectionTotalSupply == 0) {
194: if (phase == 1) {
240: if (_index == 1000) {
248: } else if (_index == 999) {
301: require(tokenToHash[_mintIndex] == 0x0000000000000000000000000000000000000000000000000000000000000000);
345: if (onchainMetadata[tokenIdsToCollectionIds[tokenId]] == false && tokenToHash[tokenId] != 0x0000000000000000000000000000000000000000000000000000000000000000) {
348: } else if (onchainMetadata[tokenIdsToCollectionIds[tokenId]] == false && tokenToHash[tokenId] == 0x0000000000000000000000000000000000000000000000000000000000000000) {
[149, 194, 240, 248, 301, 345, 348]
File: smart-contracts/XRandoms.sol
28: if (id==0) {
[28]
The delete
keyword more closely matches the semantics of what is being done, and draws more attention to the changing of state, which may lead to a more thorough audit of its associated logic.
There are 6 instances of this issue.
File: smart-contracts/AuctionDemo.sol
127: auctionInfoData[_tokenid][index].status = false;
138: auctionInfoData[_tokenid][i].status = false;
File: smart-contracts/MinterContract.sol
389: collectionArtistPrimaryAddresses[_collectionID].status = false;
403: collectionArtistSecondaryAddresses[_collectionID].status = false;
420: collectionTotalAmount[_collectionID] = 0;
File: smart-contracts/NextGenCore.sol
152: collectionAdditionalData[_collectionID].collectionCirculationSupply = 0;
[152]
The if
/else
statement can be written in a shorthand way using the ternary operator, as it increases readability and reduces the number of lines of code.
There is 1 instance of this issue.
File: smart-contracts/MinterContract.sol
535: if (collectionPhases[_collectionId].rate > 0) {
536: return collectionPhases[_collectionId].collectionMintCost + ((collectionPhases[_collectionId].collectionMintCost / collectionPhases[_collectionId].rate) * gencore.viewCirSupply(_collectionId));
537: } else {
538: return collectionPhases[_collectionId].collectionMintCost;
539: }
[535-539]
Named mappings improve the readability of the code, even if they are optional, as it's possible to infer the usage of both key and value, instead of looking just at the type.
There are 48 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
50: mapping (uint256 => auctionInfoStru[]) public auctionInfoData;
53: mapping (uint256 => bool) public auctionClaim;
File: smart-contracts/MinterContract.sol
23: mapping (uint256 => uint256) public collectionTotalAmount;
26: mapping (uint256 => uint) public lastMintDate;
29: mapping (bytes32 => address) public burnOrSwapAddress;
32: mapping (bytes32 => uint256[2]) private burnOrSwapIds;
35: mapping (uint256 => mapping (uint256 => bool)) public burnToMintCollections;
35: mapping (uint256 => mapping (uint256 => bool)) public burnToMintCollections;
38: mapping (bytes32 => mapping (uint256 => bool)) public burnExternalToMintCollections;
38: mapping (bytes32 => mapping (uint256 => bool)) public burnExternalToMintCollections;
41: mapping (uint256 => bool) private setMintingCosts;
59: mapping (uint256 => collectionPhasesDataStructure) private collectionPhases;
70: mapping (uint256 => royaltiesPrimarySplits) private collectionRoyaltiesPrimarySplits;
84: mapping (uint256 => collectionPrimaryAddresses) private collectionArtistPrimaryAddresses;
95: mapping (uint256 => royaltiesSecondarySplits) private collectionRoyaltiesSecondarySplits;
109: mapping (uint256 => collectionSecondaryAddresses) private collectionArtistSecondaryAddresses;
112: mapping (uint256 => uint) private mintToAuctionData;
115: mapping (uint256 => bool) private mintToAuctionStatus;
[23, 26, 29, 32, 35, 35, 38, 38, 41, 59, 70, 84, 95, 109, 112, 115]
File: smart-contracts/NextGenAdmins.sol
18: mapping(address => bool) public adminPermissions;
21: mapping (address => mapping (uint256 => bool)) private collectionAdmin;
21: mapping (address => mapping (uint256 => bool)) private collectionAdmin;
24: mapping (address => mapping (bytes4 => bool)) private functionAdmin;
24: mapping (address => mapping (bytes4 => bool)) private functionAdmin;
File: smart-contracts/NextGenCore.sol
41: mapping (uint256 => collectionInfoStructure) private collectionInfo;
57: mapping (uint256 => collectionAdditonalDataStructure) private collectionAdditionalData;
62: mapping (uint256 => bool) private isCollectionCreated;
65: mapping (uint256 => bool) private wereDataAdded;
68: mapping (uint256 => uint256) private tokenIdsToCollectionIds;
71: mapping(uint256 => bytes32) private tokenToHash;
74: mapping (uint256 => mapping (address => uint256)) private tokensMintedPerAddress;
74: mapping (uint256 => mapping (address => uint256)) private tokensMintedPerAddress;
77: mapping (uint256 => mapping (address => uint256)) private tokensMintedAllowlistAddress;
77: mapping (uint256 => mapping (address => uint256)) private tokensMintedAllowlistAddress;
80: mapping (uint256 => mapping (address => uint256)) private tokensAirdropPerAddress;
80: mapping (uint256 => mapping (address => uint256)) private tokensAirdropPerAddress;
83: mapping (uint256 => uint256) public burnAmount;
86: mapping (uint256 => bool) public onchainMetadata;
89: mapping (uint256 => string) public artistsSignatures;
92: mapping (uint256 => string) public tokenData;
95: mapping (uint256 => string[2]) private tokenImageAndAttributes;
98: mapping (uint256 => bool) private collectionFreeze;
101: mapping (uint256 => bool) public artistSigned;
[41, 57, 62, 65, 68, 71, 74, 74, 77, 77, 80, 80, 83, 86, 89, 92, 95, 98, 101]
File: smart-contracts/RandomizerRNG.sol
20: mapping(uint256 => uint256) public requestToToken;
26: mapping(uint256 => uint256) public tokenToRequest;
27: mapping(uint256 => uint256) public tokenIdToCollection;
File: smart-contracts/RandomizerVRF.sol
31: mapping(uint256 => uint256) public tokenIdToCollection;
32: mapping(uint256 => uint256) public tokenToRequest;
33: mapping(uint256 => uint256) public requestToToken;
This is a best practice that should be followed.
Inside each contract, library or interface, use the following order:
- Type declarations
- State variables
- Events
- Errors
- Modifiers
- Functions
There are 7 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
// @audit event CancelBid found on line 24
26: IMinterContract public minter;
[26]
File: smart-contracts/MinterContract.sol
// @audit function constructor found on line 129
136: modifier ArtistOrAdminRequired(uint256 _collectionID, bytes4 _selector) {
[136]
File: smart-contracts/NextGenAdmins.sol
// @audit function constructor found on line 26
31: modifier AdminRequired {
[31]
File: smart-contracts/NextGenCore.sol
// @audit function constructor found on line 108
116: modifier FunctionAdminRequired(bytes4 _selector) {
[116]
File: smart-contracts/RandomizerNXT.sol
// @audit function constructor found on line 25
34: modifier FunctionAdminRequired(bytes4 _selector) {
[34]
File: smart-contracts/RandomizerRNG.sol
// @audit event Withdraw found on line 24
25: uint256 ethRequired;
// @audit function constructor found on line 29
35: modifier FunctionAdminRequired(bytes4 _selector) {
[25]
File: smart-contracts/RandomizerVRF.sol
// @audit event RequestFulfilled found on line 20
22: VRFCoordinatorV2Interface public COORDINATOR;
// @audit function constructor found on line 39
47: modifier FunctionAdminRequired(bytes4 _selector) {
[22]
This is a best practice that should be followed. In variable declarations, do not separate the keyword mapping from its type by a space. Do not separate any nested mapping keyword from its type by whitespace.
There are 40 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
50: mapping (uint256 => auctionInfoStru[]) public auctionInfoData;
53: mapping (uint256 => bool) public auctionClaim;
File: smart-contracts/MinterContract.sol
23: mapping (uint256 => uint256) public collectionTotalAmount;
26: mapping (uint256 => uint) public lastMintDate;
29: mapping (bytes32 => address) public burnOrSwapAddress;
32: mapping (bytes32 => uint256[2]) private burnOrSwapIds;
35: mapping (uint256 => mapping (uint256 => bool)) public burnToMintCollections;
35: mapping (uint256 => mapping (uint256 => bool)) public burnToMintCollections;
38: mapping (bytes32 => mapping (uint256 => bool)) public burnExternalToMintCollections;
38: mapping (bytes32 => mapping (uint256 => bool)) public burnExternalToMintCollections;
41: mapping (uint256 => bool) private setMintingCosts;
59: mapping (uint256 => collectionPhasesDataStructure) private collectionPhases;
70: mapping (uint256 => royaltiesPrimarySplits) private collectionRoyaltiesPrimarySplits;
84: mapping (uint256 => collectionPrimaryAddresses) private collectionArtistPrimaryAddresses;
95: mapping (uint256 => royaltiesSecondarySplits) private collectionRoyaltiesSecondarySplits;
109: mapping (uint256 => collectionSecondaryAddresses) private collectionArtistSecondaryAddresses;
112: mapping (uint256 => uint) private mintToAuctionData;
115: mapping (uint256 => bool) private mintToAuctionStatus;
[23, 26, 29, 32, 35, 35, 38, 38, 41, 59, 70, 84, 95, 109, 112, 115]
File: smart-contracts/NextGenAdmins.sol
21: mapping (address => mapping (uint256 => bool)) private collectionAdmin;
21: mapping (address => mapping (uint256 => bool)) private collectionAdmin;
24: mapping (address => mapping (bytes4 => bool)) private functionAdmin;
24: mapping (address => mapping (bytes4 => bool)) private functionAdmin;
File: smart-contracts/NextGenCore.sol
41: mapping (uint256 => collectionInfoStructure) private collectionInfo;
57: mapping (uint256 => collectionAdditonalDataStructure) private collectionAdditionalData;
62: mapping (uint256 => bool) private isCollectionCreated;
65: mapping (uint256 => bool) private wereDataAdded;
68: mapping (uint256 => uint256) private tokenIdsToCollectionIds;
74: mapping (uint256 => mapping (address => uint256)) private tokensMintedPerAddress;
74: mapping (uint256 => mapping (address => uint256)) private tokensMintedPerAddress;
77: mapping (uint256 => mapping (address => uint256)) private tokensMintedAllowlistAddress;
77: mapping (uint256 => mapping (address => uint256)) private tokensMintedAllowlistAddress;
80: mapping (uint256 => mapping (address => uint256)) private tokensAirdropPerAddress;
80: mapping (uint256 => mapping (address => uint256)) private tokensAirdropPerAddress;
83: mapping (uint256 => uint256) public burnAmount;
86: mapping (uint256 => bool) public onchainMetadata;
89: mapping (uint256 => string) public artistsSignatures;
92: mapping (uint256 => string) public tokenData;
95: mapping (uint256 => string[2]) private tokenImageAndAttributes;
98: mapping (uint256 => bool) private collectionFreeze;
101: mapping (uint256 => bool) public artistSigned;
[41, 57, 62, 65, 68, 74, 74, 77, 77, 80, 80, 83, 86, 89, 92, 95, 98, 101]
This is a best practice that should be followed.
Functions should be grouped according to their visibility and ordered:
- constructor
- receive function (if exists)
- fallback function (if exists)
- external
- public
- internal
- private
Within a grouping, place the view and pure functions last.
There are 56 instances of this issue.
Expand findings
File: smart-contracts/MinterContract.sol
// @audit retrieveCollectionMintingDetails on line 500, which is public
506: function isMinterContract() external view returns (bool) {
// @audit retrieveCollectionMintingDetails on line 500, which is public
512: function getEndTime(uint256 _collectionID) external view returns (uint) {
// @audit retrieveCollectionMintingDetails on line 500, which is public
518: function getAuctionEndTime(uint256 _tokenId) external view returns (uint) {
// @audit retrieveCollectionMintingDetails on line 500, which is public
524: function getAuctionStatus(uint256 _tokenId) external view returns (bool) {
File: smart-contracts/NextGenAdmins.sol
// @audit retrieveCollectionAdmin on line 77, which is public
83: function isAdminContract() external view returns (bool) {
[83]
File: smart-contracts/NextGenCore.sol
// @audit addRandomizer on line 170, which is public
178: function airDropTokens(uint256 mintIndex, address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID) external {
// @audit addRandomizer on line 170, which is public
189: function mint(uint256 mintIndex, address _mintingAddress , address _mintTo, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint256 phase) external {
// @audit burn on line 204, which is public
213: function burnToMint(uint256 mintIndex, uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, uint256 _saltfun_o, address burner) external {
// @audit _mintProcessing on line 227, which is internal
238: function updateCollectionInfo(uint256 _collectionID, string memory _newCollectionName, string memory _newCollectionArtist, string memory _newCollectionDescription, string memory _newCollectionWebsite, string memory _newCollectionLicense, string memory _newCollectionBaseURI, string memory _newCollectionLibrary, uint256 _index, string[] memory _newCollectionScript) public CollectionAdminRequired(_collectionID, this.updateCollectionInfo.selector) {
// @audit _mintProcessing on line 227, which is internal
257: function artistSignature(uint256 _collectionID, string memory _signature) public {
// @audit _mintProcessing on line 227, which is internal
266: function changeMetadataView(uint256 _collectionID, bool _status) public CollectionAdminRequired(_collectionID, this.changeMetadataView.selector) {
// @audit _mintProcessing on line 227, which is internal
273: function changeTokenData(uint256 _tokenId, string memory newData) public FunctionAdminRequired(this.changeTokenData.selector) {
// @audit _mintProcessing on line 227, which is internal
281: function updateImagesAndAttributes(uint256[] memory _tokenId, string[] memory _images, string[] memory _attributes) public FunctionAdminRequired(this.updateImagesAndAttributes.selector) {
// @audit _mintProcessing on line 227, which is internal
292: function freezeCollection(uint256 _collectionID) public FunctionAdminRequired(this.freezeCollection.selector) {
// @audit _mintProcessing on line 227, which is internal
299: function setTokenHash(uint256 _collectionID, uint256 _mintIndex, bytes32 _hash) external {
// @audit _mintProcessing on line 227, which is internal
307: function setFinalSupply(uint256 _collectionID) public FunctionAdminRequired(this.setFinalSupply.selector) {
// @audit _mintProcessing on line 227, which is internal
315: function addMinterContract(address _minterContract) public FunctionAdminRequired(this.addMinterContract.selector) {
// @audit _mintProcessing on line 227, which is internal
322: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
// @audit _mintProcessing on line 227, which is internal
329: function setDefaultRoyalties(address _royaltyAddress, uint96 _bps) public FunctionAdminRequired(this.setDefaultRoyalties.selector) {
// @audit _mintProcessing on line 227, which is internal
337: function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721Enumerable, ERC2981) returns (bool) {
// @audit _mintProcessing on line 227, which is internal
343: function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
// @audit getTokenName on line 361, which is private
367: function collectionFreezeStatus(uint256 _collectionID) public view returns(bool){
// @audit getTokenName on line 361, which is private
372: function viewColIDforTokenID(uint256 _tokenid) public view returns (uint256) {
// @audit getTokenName on line 361, which is private
377: function retrievewereDataAdded(uint256 _collectionID) external view returns(bool){
// @audit getTokenName on line 361, which is private
383: function viewTokensIndexMin(uint256 _collectionID) external view returns (uint256) {
// @audit getTokenName on line 361, which is private
389: function viewTokensIndexMax(uint256 _collectionID) external view returns (uint256) {
// @audit getTokenName on line 361, which is private
394: function viewCirSupply(uint256 _collectionID) external view returns (uint256) {
// @audit getTokenName on line 361, which is private
399: function viewMaxAllowance(uint256 _collectionID) external view returns (uint256) {
// @audit getTokenName on line 361, which is private
404: function retrieveTokensMintedALPerAddress(uint256 _collectionID, address _address) external view returns(uint256) {
// @audit getTokenName on line 361, which is private
409: function retrieveTokensMintedPublicPerAddress(uint256 _collectionID, address _address) external view returns(uint256) {
// @audit getTokenName on line 361, which is private
415: function retrieveTokensAirdroppedPerAddress(uint256 _collectionID, address _address) public view returns(uint256) {
// @audit getTokenName on line 361, which is private
420: function retrieveArtistAddress(uint256 _collectionID) external view returns(address) {
// @audit getTokenName on line 361, which is private
426: function retrieveCollectionInfo(uint256 _collectionID) public view returns(string memory, string memory, string memory, string memory, string memory, string memory){
// @audit getTokenName on line 361, which is private
432: function retrieveCollectionLibraryAndScript(uint256 _collectionID) public view returns(string memory, string[] memory){
// @audit getTokenName on line 361, which is private
438: function retrieveCollectionAdditionalData(uint256 _collectionID) public view returns(address, uint256, uint256, uint256, uint, address){
// @audit getTokenName on line 361, which is private
444: function retrieveTokenHash(uint256 _tokenid) public view returns(bytes32){
// @audit getTokenName on line 361, which is private
450: function retrieveGenerativeScript(uint256 tokenId) public view returns(string memory){
// @audit getTokenName on line 361, which is private
461: function totalSupplyOfCollection(uint256 _collectionID) public view returns (uint256) {
// @audit getTokenName on line 361, which is private
467: function retrievetokenImageAndAttributes(uint256 _tokenId) public view returns(string memory, string memory) {
[178, 189, 213, 238, 257, 266, 273, 281, 292, 299, 307, 315, 322, 329, 337, 343, 367, 372, 377, 383, 389, 394, 399, 404, 409, 415, 420, 426, 432, 438, 444, 450, 461, 467]
File: smart-contracts/RandomizerNXT.sol
// @audit calculateTokenHash on line 55, which is public
62: function isRandomizerContract() external view returns (bool) {
[62]
File: smart-contracts/RandomizerRNG.sol
// @audit fulfillRandomWords on line 48, which is internal
53: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
// @audit fulfillRandomWords on line 48, which is internal
61: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
// @audit fulfillRandomWords on line 48, which is internal
66: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
// @audit fulfillRandomWords on line 48, which is internal
73: function updateRNGCost(uint256 _ethRequired) public FunctionAdminRequired(this.updateRNGCost.selector) {
// @audit fulfillRandomWords on line 48, which is internal
79: function emergencyWithdraw() public FunctionAdminRequired(this.emergencyWithdraw.selector) {
// @audit fulfillRandomWords on line 48, which is internal
86: receive() external payable {}
// @audit fulfillRandomWords on line 48, which is internal
89: function isRandomizerContract() external view returns (bool) {
File: smart-contracts/RandomizerVRF.sol
// @audit fulfillRandomWords on line 65, which is internal
71: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
// @audit fulfillRandomWords on line 65, which is internal
79: function updatecallbackGasLimitAndkeyHash(uint32 _callbackGasLimit, bytes32 _keyHash) public FunctionAdminRequired(this.updatecallbackGasLimitAndkeyHash.selector){
// @audit fulfillRandomWords on line 65, which is internal
86: function updateAdditionalData(uint64 _s_subscriptionId, uint32 _numWords, uint16 _requestConfirmations) public FunctionAdminRequired(this.updateAdditionalData.selector){
// @audit fulfillRandomWords on line 65, which is internal
94: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
// @audit fulfillRandomWords on line 65, which is internal
99: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
// @audit fulfillRandomWords on line 65, which is internal
105: function isRandomizerContract() external view returns (bool) {
File: smart-contracts/XRandoms.sol
// @audit getWord on line 15, which is private
35: function randomNumber() public view returns (uint256){
// @audit getWord on line 15, which is private
40: function randomWord() public view returns (string memory) {
// @audit getWord on line 15, which is private
45: function returnIndex(uint256 id) public view returns (string memory) {
Consider splitting long functions into multiple, smaller functions to improve the code readability.
There is 1 instance of this issue.
File: smart-contracts/MinterContract.sol
196: function mint(uint256 _collectionID, uint256 _numberOfTokens, uint256 _maxAllowance, string memory _tokenData, address _mintTo, bytes32[] calldata merkleProof, address _delegator, uint256 _saltfun_o) public payable {
[196]
According to the documentation strings should use a double quote instead of a single one.
There are 4 instances of this issue.
File: smart-contracts/MinterContract.sol
220: require(MerkleProof.verifyCalldata(merkleProof, collectionPhases[col].merkleRoot, node), 'invalid proof');
226: tokData = '"public"';
350: require(MerkleProof.verifyCalldata(merkleProof, collectionPhases[col].merkleRoot, node), 'invalid proof');
354: tokData = '"public"';
Maximum suggested line length is 120 characters according to the documentation.
There are 117 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
32: require(msg.sender == returnHighestBidder(_tokenId) || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
58: require(msg.value > returnHighestBid(_tokenid) && block.timestamp <= minter.getAuctionEndTime(_tokenid) && minter.getAuctionStatus(_tokenid) == true);
105: require(block.timestamp >= minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true);
111: if (auctionInfoData[_tokenid][i].bidder == highestBidder && auctionInfoData[_tokenid][i].bid == highestBid && auctionInfoData[_tokenid][i].status == true) {
128: (bool success, ) = payable(auctionInfoData[_tokenid][index].bidder).call{value: auctionInfoData[_tokenid][index].bid}("");
File: smart-contracts/MinterContract.sol
137: require(msg.sender == gencore.retrieveArtistAddress(_collectionID) || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
144: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
151: require(adminsContract.retrieveCollectionAdmin(msg.sender,_collectionID) == true || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
157: function setCollectionCosts(uint256 _collectionID, uint256 _collectionMintCost, uint256 _collectionEndMintCost, uint256 _rate, uint256 _timePeriod, uint8 _salesOption, address _delAddress) public CollectionAdminRequired(_collectionID, this.setCollectionCosts.selector) {
170: function setCollectionPhases(uint256 _collectionID, uint _allowlistStartTime, uint _allowlistEndTime, uint _publicStartTime, uint _publicEndTime, bytes32 _merkleRoot) public CollectionAdminRequired(_collectionID, this.setCollectionPhases.selector) {
181: function airDropTokens(address[] memory _recipients, string[] memory _tokenData, uint256[] memory _saltfun_o, uint256 _collectionID, uint256[] memory _numberOfTokens) public FunctionAdminRequired(this.airDropTokens.selector) {
185: collectionTokenMintIndex = gencore.viewTokensIndexMin(_collectionID) + gencore.viewCirSupply(_collectionID) + _numberOfTokens[y] - 1;
196: function mint(uint256 _collectionID, uint256 _numberOfTokens, uint256 _maxAllowance, string memory _tokenData, address _mintTo, bytes32[] calldata merkleProof, address _delegator, uint256 _saltfun_o) public payable {
202: if (block.timestamp >= collectionPhases[col].allowlistStartTime && block.timestamp <= collectionPhases[col].allowlistEndTime) {
207: isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(_delegator, 0x8888888888888888888888888888888888888888, msg.sender, 1) || dmc.retrieveGlobalStatusOfDelegation(_delegator, 0x8888888888888888888888888888888888888888, msg.sender, 2);
209: isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(_delegator, collectionPhases[col].delAddress, msg.sender, 1) || dmc.retrieveGlobalStatusOfDelegation(_delegator, collectionPhases[col].delAddress, msg.sender, 2);
221: } else if (block.timestamp >= collectionPhases[col].publicStartTime && block.timestamp <= collectionPhases[col].publicEndTime) {
224: require(gencore.retrieveTokensMintedPublicPerAddress(col, msg.sender) + _numberOfTokens <= gencore.viewMaxAllowance(col), "Max");
252: lastMintDate[col] = collectionPhases[col].allowlistStartTime + (collectionPhases[col].timePeriod * (gencore.viewCirSupply(col) - 1));
258: function burnToMint(uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, uint256 _saltfun_o) public payable {
260: require(block.timestamp >= collectionPhases[_mintCollectionID].publicStartTime && block.timestamp<=collectionPhases[_mintCollectionID].publicEndTime,"No minting");
261: require ((_tokenId >= gencore.viewTokensIndexMin(_burnCollectionID)) && (_tokenId <= gencore.viewTokensIndexMax(_burnCollectionID)), "col/token id error");
276: function mintAndAuction(address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint _auctionEndTime) public FunctionAdminRequired(this.mintAndAuction.selector) {
295: lastMintDate[_collectionID] = collectionPhases[_collectionID].allowlistStartTime + (collectionPhases[_collectionID].timePeriod * (gencore.viewCirSupply(_collectionID) - 1));
302: function updateDelegationCollection(uint256 _collectionID, address _collectionAddress) public FunctionAdminRequired(this.updateDelegationCollection.selector) {
308: function initializeBurn(uint256 _burnCollectionID, uint256 _mintCollectionID, bool _status) public FunctionAdminRequired(this.initializeBurn.selector) {
309: require((gencore.retrievewereDataAdded(_burnCollectionID) == true) && (gencore.retrievewereDataAdded(_mintCollectionID) == true), "No data");
315: function initializeExternalBurnOrSwap(address _erc721Collection, uint256 _burnCollectionID, uint256 _mintCollectionID, uint256 _tokmin, uint256 _tokmax, address _burnOrSwapAddress, bool _status) public FunctionAdminRequired(this.initializeExternalBurnOrSwap.selector) {
326: function burnOrSwapExternalToMint(address _erc721Collection, uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, string memory _tokenData, bytes32[] calldata merkleProof, uint256 _saltfun_o) public payable {
333: isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(ownerOfToken, 0x8888888888888888888888888888888888888888, msg.sender, 1) || dmc.retrieveGlobalStatusOfDelegation(ownerOfToken, 0x8888888888888888888888888888888888888888, msg.sender, 2);
335: isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(ownerOfToken, _erc721Collection, msg.sender, 1) || dmc.retrieveGlobalStatusOfDelegation(ownerOfToken, _erc721Collection, msg.sender, 2);
339: require(_tokenId >= burnOrSwapIds[externalCol][0] && _tokenId <= burnOrSwapIds[externalCol][1], "Token id does not match");
345: if (block.timestamp >= collectionPhases[col].allowlistStartTime && block.timestamp <= collectionPhases[col].allowlistEndTime) {
351: } else if (block.timestamp >= collectionPhases[col].publicStartTime && block.timestamp <= collectionPhases[col].publicEndTime) {
369: function setPrimaryAndSecondarySplits(uint256 _collectionID, uint256 _artistPrSplit, uint256 _teamPrSplit, uint256 _artistSecSplit, uint256 _teamSecSplit) public FunctionAdminRequired(this.setPrimaryAndSecondarySplits.selector) {
380: function proposePrimaryAddressesAndPercentages(uint256 _collectionID, address _primaryAdd1, address _primaryAdd2, address _primaryAdd3, uint256 _add1Percentage, uint256 _add2Percentage, uint256 _add3Percentage) public ArtistOrAdminRequired(_collectionID, this.proposePrimaryAddressesAndPercentages.selector) {
382: require (_add1Percentage + _add2Percentage + _add3Percentage == collectionRoyaltiesPrimarySplits[_collectionID].artistPercentage, "Check %");
394: function proposeSecondaryAddressesAndPercentages(uint256 _collectionID, address _secondaryAdd1, address _secondaryAdd2, address _secondaryAdd3, uint256 _add1Percentage, uint256 _add2Percentage, uint256 _add3Percentage) public ArtistOrAdminRequired(_collectionID, this.proposeSecondaryAddressesAndPercentages.selector) {
396: require (_add1Percentage + _add2Percentage + _add3Percentage == collectionRoyaltiesSecondarySplits[_collectionID].artistPercentage, "Check %");
408: function acceptAddressesAndPercentages(uint256 _collectionID, bool _statusPrimary, bool _statusSecondary) public FunctionAdminRequired(this.acceptAddressesAndPercentages.selector) {
415: function payArtist(uint256 _collectionID, address _team1, address _team2, uint256 _teamperc1, uint256 _teamperc2) public FunctionAdminRequired(this.payArtist.selector) {
418: require(collectionRoyaltiesPrimarySplits[_collectionID].artistPercentage + _teamperc1 + _teamperc2 == 100, "Change percentages");
454: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
471: return (collectionRoyaltiesPrimarySplits[_collectionID].artistPercentage, collectionRoyaltiesPrimarySplits[_collectionID].teamPercentage);
476: function retrievePrimaryAddressesAndPercentages(uint256 _collectionID) public view returns(address, address, address, uint256, uint256, uint256, bool){
477: return (collectionArtistPrimaryAddresses[_collectionID].primaryAdd1, collectionArtistPrimaryAddresses[_collectionID].primaryAdd2, collectionArtistPrimaryAddresses[_collectionID].primaryAdd3, collectionArtistPrimaryAddresses[_collectionID].add1Percentage, collectionArtistPrimaryAddresses[_collectionID].add2Percentage, collectionArtistPrimaryAddresses[_collectionID].add3Percentage, collectionArtistPrimaryAddresses[_collectionID].status);
483: return (collectionRoyaltiesSecondarySplits[_collectionID].artistPercentage, collectionRoyaltiesSecondarySplits[_collectionID].teamPercentage);
488: function retrieveSecondaryAddressesAndPercentages(uint256 _collectionID) public view returns(address, address, address, uint256, uint256, uint256, bool){
489: return (collectionArtistSecondaryAddresses[_collectionID].secondaryAdd1, collectionArtistSecondaryAddresses[_collectionID].secondaryAdd2, collectionArtistSecondaryAddresses[_collectionID].secondaryAdd3, collectionArtistSecondaryAddresses[_collectionID].add1Percentage, collectionArtistSecondaryAddresses[_collectionID].add2Percentage, collectionArtistSecondaryAddresses[_collectionID].add3Percentage, collectionArtistSecondaryAddresses[_collectionID].status);
495: return (collectionPhases[_collectionID].allowlistStartTime, collectionPhases[_collectionID].allowlistEndTime, collectionPhases[_collectionID].merkleRoot, collectionPhases[_collectionID].publicStartTime, collectionPhases[_collectionID].publicEndTime);
500: function retrieveCollectionMintingDetails(uint256 _collectionID) public view returns(uint256, uint256, uint256, uint256, uint8, address){
501: return (collectionPhases[_collectionID].collectionMintCost, collectionPhases[_collectionID].collectionEndMintCost, collectionPhases[_collectionID].rate, collectionPhases[_collectionID].timePeriod, collectionPhases[_collectionID].salesOption, collectionPhases[_collectionID].delAddress);
536: return collectionPhases[_collectionId].collectionMintCost + ((collectionPhases[_collectionId].collectionMintCost / collectionPhases[_collectionId].rate) * gencore.viewCirSupply(_collectionId));
540: } else if (collectionPhases[_collectionId].salesOption == 2 && block.timestamp > collectionPhases[_collectionId].allowlistStartTime && block.timestamp < collectionPhases[_collectionId].publicEndTime){
546: tDiff = (block.timestamp - collectionPhases[_collectionId].allowlistStartTime) / collectionPhases[_collectionId].timePeriod;
551: decreaserate = ((price - (collectionPhases[_collectionId].collectionMintCost / (tDiff + 2))) / collectionPhases[_collectionId].timePeriod) * ((block.timestamp - (tDiff * collectionPhases[_collectionId].timePeriod) - collectionPhases[_collectionId].allowlistStartTime));
553: if (((collectionPhases[_collectionId].collectionMintCost - collectionPhases[_collectionId].collectionEndMintCost) / (collectionPhases[_collectionId].rate)) > tDiff) {
[137, 144, 151, 157, 170, 181, 185, 196, 202, 207, 209, 221, 224, 252, 258, 260, 261, 276, 295, 302, 308, 309, 315, 326, 333, 335, 339, 345, 351, 369, 380, 382, 394, 396, 408, 415, 418, 454, 471, 476, 477, 483, 488, 489, 495, 500, 501, 536, 540, 546, 551, 553]
File: smart-contracts/NextGenCore.sol
117: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
124: require(adminsContract.retrieveCollectionAdmin(msg.sender,_collectionID) == true || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
130: function createCollection(string memory _collectionName, string memory _collectionArtist, string memory _collectionDescription, string memory _collectionWebsite, string memory _collectionLicense, string memory _collectionBaseURI, string memory _collectionLibrary, string[] memory _collectionScript) public FunctionAdminRequired(this.createCollection.selector) {
147: function setCollectionData(uint256 _collectionID, address _collectionArtistAddress, uint256 _maxCollectionPurchases, uint256 _collectionTotalSupply, uint _setFinalSupplyTimeAfterMint) public CollectionAdminRequired(_collectionID, this.setCollectionData.selector) {
148: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false) && (_collectionTotalSupply <= 10000000000), "err/freezed");
156: collectionAdditionalData[_collectionID].reservedMaxTokensIndex = (_collectionID * 10000000000) + _collectionTotalSupply - 1;
170: function addRandomizer(uint256 _collectionID, address _randomizerContract) public FunctionAdminRequired(this.addRandomizer.selector) {
178: function airDropTokens(uint256 mintIndex, address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID) external {
180: collectionAdditionalData[_collectionID].collectionCirculationSupply = collectionAdditionalData[_collectionID].collectionCirculationSupply + 1;
181: if (collectionAdditionalData[_collectionID].collectionTotalSupply >= collectionAdditionalData[_collectionID].collectionCirculationSupply) {
189: function mint(uint256 mintIndex, address _mintingAddress , address _mintTo, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint256 phase) external {
191: collectionAdditionalData[_collectionID].collectionCirculationSupply = collectionAdditionalData[_collectionID].collectionCirculationSupply + 1;
192: if (collectionAdditionalData[_collectionID].collectionTotalSupply >= collectionAdditionalData[_collectionID].collectionCirculationSupply) {
195: tokensMintedAllowlistAddress[_collectionID][_mintingAddress] = tokensMintedAllowlistAddress[_collectionID][_mintingAddress] + 1;
206: require ((_tokenId >= collectionAdditionalData[_collectionID].reservedMinTokensIndex) && (_tokenId <= collectionAdditionalData[_collectionID].reservedMaxTokensIndex), "id err");
213: function burnToMint(uint256 mintIndex, uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, uint256 _saltfun_o, address burner) external {
216: collectionAdditionalData[_mintCollectionID].collectionCirculationSupply = collectionAdditionalData[_mintCollectionID].collectionCirculationSupply + 1;
217: if (collectionAdditionalData[_mintCollectionID].collectionTotalSupply >= collectionAdditionalData[_mintCollectionID].collectionCirculationSupply) {
227: function _mintProcessing(uint256 _mintIndex, address _recipient, string memory _tokenData, uint256 _collectionID, uint256 _saltfun_o) internal {
238: function updateCollectionInfo(uint256 _collectionID, string memory _newCollectionName, string memory _newCollectionArtist, string memory _newCollectionDescription, string memory _newCollectionWebsite, string memory _newCollectionLicense, string memory _newCollectionBaseURI, string memory _newCollectionLibrary, uint256 _index, string[] memory _newCollectionScript) public CollectionAdminRequired(_collectionID, this.updateCollectionInfo.selector) {
266: function changeMetadataView(uint256 _collectionID, bool _status) public CollectionAdminRequired(_collectionID, this.changeMetadataView.selector) {
273: function changeTokenData(uint256 _tokenId, string memory newData) public FunctionAdminRequired(this.changeTokenData.selector) {
281: function updateImagesAndAttributes(uint256[] memory _tokenId, string[] memory _images, string[] memory _attributes) public FunctionAdminRequired(this.updateImagesAndAttributes.selector) {
308: require (block.timestamp > IMinterContract(minterContract).getEndTime(_collectionID) + collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint, "Time has not passed");
309: collectionAdditionalData[_collectionID].collectionTotalSupply = collectionAdditionalData[_collectionID].collectionCirculationSupply;
310: collectionAdditionalData[_collectionID].reservedMaxTokensIndex = (_collectionID * 10000000000) + collectionAdditionalData[_collectionID].collectionTotalSupply - 1;
322: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
329: function setDefaultRoyalties(address _royaltyAddress, uint96 _bps) public FunctionAdminRequired(this.setDefaultRoyalties.selector) {
337: function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721Enumerable, ERC2981) returns (bool) {
345: if (onchainMetadata[tokenIdsToCollectionIds[tokenId]] == false && tokenToHash[tokenId] != 0x0000000000000000000000000000000000000000000000000000000000000000) {
348: } else if (onchainMetadata[tokenIdsToCollectionIds[tokenId]] == false && tokenToHash[tokenId] == 0x0000000000000000000000000000000000000000000000000000000000000000) {
353: string memory b64 = Base64.encode(abi.encodePacked("<html><head></head><body><script src=\"",collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionLibrary,"\"></script><script>",retrieveGenerativeScript(tokenId),"</script></body></html>"));
354: string memory _uri = string(abi.encodePacked("data:application/json;utf8,{\"name\":\"",getTokenName(tokenId),"\",\"description\":\"",collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionDescription,"\",\"image\":\"",tokenImageAndAttributes[tokenId][0],"\",\"attributes\":[",tokenImageAndAttributes[tokenId][1],"],\"animation_url\":\"data:text/html;base64,",b64,"\"}"));
426: function retrieveCollectionInfo(uint256 _collectionID) public view returns(string memory, string memory, string memory, string memory, string memory, string memory){
427: return (collectionInfo[_collectionID].collectionName, collectionInfo[_collectionID].collectionArtist, collectionInfo[_collectionID].collectionDescription, collectionInfo[_collectionID].collectionWebsite, collectionInfo[_collectionID].collectionLicense, collectionInfo[_collectionID].collectionBaseURI);
438: function retrieveCollectionAdditionalData(uint256 _collectionID) public view returns(address, uint256, uint256, uint256, uint, address){
439: return (collectionAdditionalData[_collectionID].collectionArtistAddress, collectionAdditionalData[_collectionID].maxCollectionPurchases, collectionAdditionalData[_collectionID].collectionCirculationSupply, collectionAdditionalData[_collectionID].collectionTotalSupply, collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint, collectionAdditionalData[_collectionID].randomizerContract);
454: scripttext = string(abi.encodePacked(scripttext, collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionScript[i]));
456: return string(abi.encodePacked("let hash='",Strings.toHexString(uint256(tokenToHash[tokenId]), 32),"';let tokenId=",tokenId.toString(),";let tokenData=[",tokenData[tokenId],"];", scripttext));
[117, 124, 130, 147, 148, 156, 170, 178, 180, 181, 189, 191, 192, 195, 206, 213, 216, 217, 227, 238, 266, 273, 281, 308, 309, 310, 322, 329, 337, 345, 348, 353, 354, 426, 427, 438, 439, 454, 456]
File: smart-contracts/RandomizerNXT.sol
35: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
57: bytes32 hash = keccak256(abi.encodePacked(_mintIndex, blockhash(block.number - 1), randoms.randomNumber(), randoms.randomWord()));
File: smart-contracts/RandomizerRNG.sol
36: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
49: gencoreContract.setTokenHash(tokenIdToCollection[requestToToken[id]], requestToToken[id], bytes32(abi.encodePacked(numbers,requestToToken[id])));
61: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
File: smart-contracts/RandomizerVRF.sol
39: constructor(uint64 subscriptionId, address vrfCoordinator, address _gencore, address _adminsContract) VRFConsumerBaseV2(vrfCoordinator) {
48: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
66: gencoreContract.setTokenHash(tokenIdToCollection[requestToToken[_requestId]], requestToToken[_requestId], bytes32(abi.encodePacked(_randomWords,requestToToken[_requestId])));
79: function updatecallbackGasLimitAndkeyHash(uint32 _callbackGasLimit, bytes32 _keyHash) public FunctionAdminRequired(this.updatecallbackGasLimitAndkeyHash.selector){
86: function updateAdditionalData(uint64 _s_subscriptionId, uint32 _numWords, uint16 _requestConfirmations) public FunctionAdminRequired(this.updateAdditionalData.selector){
94: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
File: smart-contracts/XRandoms.sol
18: string[100] memory wordsList = ["Acai", "Ackee", "Apple", "Apricot", "Avocado", "Babaco", "Banana", "Bilberry", "Blackberry", "Blackcurrant", "Blood Orange",
19: "Blueberry", "Boysenberry", "Breadfruit", "Brush Cherry", "Canary Melon", "Cantaloupe", "Carambola", "Casaba Melon", "Cherimoya", "Cherry", "Clementine",
20: "Cloudberry", "Coconut", "Cranberry", "Crenshaw Melon", "Cucumber", "Currant", "Curry Berry", "Custard Apple", "Damson Plum", "Date", "Dragonfruit", "Durian",
21: "Eggplant", "Elderberry", "Feijoa", "Finger Lime", "Fig", "Gooseberry", "Grapes", "Grapefruit", "Guava", "Honeydew Melon", "Huckleberry", "Italian Prune Plum",
22: "Jackfruit", "Java Plum", "Jujube", "Kaffir Lime", "Kiwi", "Kumquat", "Lemon", "Lime", "Loganberry", "Longan", "Loquat", "Lychee", "Mammee", "Mandarin", "Mango",
23: "Mangosteen", "Mulberry", "Nance", "Nectarine", "Noni", "Olive", "Orange", "Papaya", "Passion fruit", "Pawpaw", "Peach", "Pear", "Persimmon", "Pineapple",
24: "Plantain", "Plum", "Pomegranate", "Pomelo", "Prickly Pear", "Pulasan", "Quine", "Rambutan", "Raspberries", "Rhubarb", "Rose Apple", "Sapodilla", "Satsuma",
25: "Soursop", "Star Apple", "Star Fruit", "Strawberry", "Sugar Apple", "Tamarillo", "Tamarind", "Tangelo", "Tangerine", "Ugli", "Velvet Apple", "Watermelon"];
36: uint256 randomNum = uint(keccak256(abi.encodePacked(block.prevrandao, blockhash(block.number - 1), block.timestamp))) % 1000;
41: uint256 randomNum = uint(keccak256(abi.encodePacked(block.prevrandao, blockhash(block.number - 1), block.timestamp))) % 100;
Consider always adding an explicit visibility modifier for variables, as the default is internal
.
There are 6 instances of this issue.
File: smart-contracts/AuctionDemo.sol
28: address gencore;
[28]
File: smart-contracts/RandomizerNXT.sol
23: address gencore;
[23]
File: smart-contracts/RandomizerRNG.sol
21: address gencore;
25: uint256 ethRequired;
File: smart-contracts/RandomizerVRF.sol
25: uint64 s_subscriptionId;
35: address gencore;
This can help to prevent hackers from using stolen tokens, but as a side effect it will increase the project centralization.
There are 6 instances of this issue.
File: smart-contracts/AuctionDemo.sol
18: contract auctionDemo is Ownable {
[18]
File: smart-contracts/MinterContract.sol
20: contract NextGenMinterContract is Ownable {
[20]
File: smart-contracts/NextGenAdmins.sol
15: contract NextGenAdmins is Ownable{
[15]
File: smart-contracts/NextGenCore.sol
22: contract NextGenCore is ERC721Enumerable, Ownable, ERC2981 {
[22]
File: smart-contracts/RandomizerRNG.sol
18: contract NextGenRandomizerRNG is ArrngConsumer, Ownable {
[18]
File: smart-contracts/RandomizerVRF.sol
19: contract NextGenRandomizerVRF is VRFConsumerBaseV2, Ownable {
[19]
Starting with Solidity version 0.8.8, using the override keyword when the function solely overrides an interface function, and the function doesn't exist in multiple base contracts, is unnecessary.
There are 3 instances of this issue.
File: smart-contracts/NextGenCore.sol
343: function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
[343]
File: smart-contracts/RandomizerRNG.sol
48: function fulfillRandomWords(uint256 id, uint256[] memory numbers) internal override {
[48]
File: smart-contracts/RandomizerVRF.sol
65: function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override {
[65]
Avoid typos, and proper nouns should be capitalized.
There are 3 instances of this issue.
File: smart-contracts/MinterContract.sol
// @audit exponetialy
544: // if rate = 0 exponetialy decrease
// @audit decrase
545: // if rate is set the linear decrase each period per rate
File: smart-contracts/NextGenCore.sol
// @audit tokends, collectionsids
67: // maps tokends ids with collectionsids
[67]
A 100% test coverage is not foolproof, but it helps immensely in reducing the amount of bugs that may occur.
This includes: large code bases, or code with lots of inline-assembly, complicated math, or complicated interactions between multiple contracts.
Invariant fuzzers such as Echidna require the test writer to come up with invariants which should not be violated under any circumstances, and the fuzzer tests various inputs and function calls to ensure that the invariants always hold.
Even code with 100% code coverage can still have bugs due to the order of the operations a user performs, and invariant fuzzers may help significantly.
Formal verification is the act of proving or disproving the correctness of intended algorithms underlying a system with respect to a certain formal specification/property/invariant, using formal methods of mathematics.
Some tools that are currently available to perform these tests on smart contracts are SMTChecker and Certora Prover.
Some lines use // x
and some use //x
. The instances below point out the usages that don't follow the majority, within each file.
There are 2 instances of this issue.
File: smart-contracts/AuctionDemo.sol
20: //events
[20]
File: smart-contracts/MinterContract.sol
117: //external contracts declaration
[117]
Consider adding some comments on critical state variables to explain what they are supposed to do: this will help for future code reviews.
There are 30 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
26: IMinterContract public minter;
27: INextGenAdmins public adminsContract;
28: address gencore;
File: smart-contracts/MinterContract.sol
70: mapping (uint256 => royaltiesPrimarySplits) private collectionRoyaltiesPrimarySplits;
95: mapping (uint256 => royaltiesSecondarySplits) private collectionRoyaltiesSecondarySplits;
119: IDelegationManagementContract private dmc;
120: INextGenAdmins private adminsContract;
File: smart-contracts/NextGenCore.sol
105: address public minterContract;
[105]
File: smart-contracts/RandomizerNXT.sol
20: IXRandoms public randoms;
21: INextGenAdmins private adminsContract;
22: INextGenCore public gencoreContract;
23: address gencore;
File: smart-contracts/RandomizerRNG.sol
20: mapping(uint256 => uint256) public requestToToken;
21: address gencore;
22: INextGenCore public gencoreContract;
23: INextGenAdmins private adminsContract;
25: uint256 ethRequired;
26: mapping(uint256 => uint256) public tokenToRequest;
27: mapping(uint256 => uint256) public tokenIdToCollection;
File: smart-contracts/RandomizerVRF.sol
22: VRFCoordinatorV2Interface public COORDINATOR;
26: bytes32 public keyHash = 0x79d3d8832d904592c0bf9818b621522c988bb8b0c05cdc3b15aea1b6e8db0c15;
27: uint32 public callbackGasLimit = 40000;
28: uint16 public requestConfirmations = 3;
29: uint32 public numWords = 1;
31: mapping(uint256 => uint256) public tokenIdToCollection;
32: mapping(uint256 => uint256) public tokenToRequest;
33: mapping(uint256 => uint256) public requestToToken;
35: address gencore;
36: INextGenCore public gencoreContract;
37: INextGenAdmins private adminsContract;
@inheritdoc
Copies all missing tags from the base function. Documentation
There are 4 instances of this issue.
File: smart-contracts/NextGenCore.sol
337: function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721Enumerable, ERC2981) returns (bool) {
343: function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
File: smart-contracts/RandomizerRNG.sol
48: function fulfillRandomWords(uint256 id, uint256[] memory numbers) internal override {
[48]
File: smart-contracts/RandomizerVRF.sol
65: function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override {
[65]
Follow the Solidity naming convention by naming all the contracts in CamelCase.
There are 2 instances of this issue.
File: smart-contracts/AuctionDemo.sol
18: contract auctionDemo is Ownable {
[18]
File: smart-contracts/XRandoms.sol
13: contract randomPool {
[13]
Structs should be named using the CapWords style. Examples: MyCoin, Position, PositionXY
. Documentation
There are 8 instances of this issue.
File: smart-contracts/AuctionDemo.sol
43: struct auctionInfoStru {
[43]
File: smart-contracts/MinterContract.sol
44: struct collectionPhasesDataStructure {
63: struct royaltiesPrimarySplits {
73: struct collectionPrimaryAddresses {
88: struct royaltiesSecondarySplits {
98: struct collectionSecondaryAddresses {
File: smart-contracts/NextGenCore.sol
29: struct collectionInfoStructure {
44: struct collectionAdditonalDataStructure {
Use mixedCase. Examples: onlyBy, onlyAfter, onlyDuringThePreSale
. Documentation
There are 10 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
31: modifier WinnerOrAdminRequired(uint256 _tokenId, bytes4 _selector) {
[31]
File: smart-contracts/MinterContract.sol
136: modifier ArtistOrAdminRequired(uint256 _collectionID, bytes4 _selector) {
143: modifier FunctionAdminRequired(bytes4 _selector) {
150: modifier CollectionAdminRequired(uint256 _collectionID, bytes4 _selector) {
File: smart-contracts/NextGenAdmins.sol
31: modifier AdminRequired {
[31]
File: smart-contracts/NextGenCore.sol
116: modifier FunctionAdminRequired(bytes4 _selector) {
123: modifier CollectionAdminRequired(uint256 _collectionID, bytes4 _selector) {
File: smart-contracts/RandomizerNXT.sol
34: modifier FunctionAdminRequired(bytes4 _selector) {
[34]
File: smart-contracts/RandomizerRNG.sol
35: modifier FunctionAdminRequired(bytes4 _selector) {
[35]
File: smart-contracts/RandomizerVRF.sol
47: modifier FunctionAdminRequired(bytes4 _selector) {
[47]
Use mixedCase
for local and state variables that are not constants, and add a trailing underscore for non-external variables. Documentation
There are 15 instances of this issue.
Expand findings
File: smart-contracts/MinterContract.sol
// @audit _saltfun_o
181: function airDropTokens(address[] memory _recipients, string[] memory _tokenData, uint256[] memory _saltfun_o, uint256 _collectionID, uint256[] memory _numberOfTokens) public FunctionAdminRequired(this.airDropTokens.selector) {
// @audit _saltfun_o
196: function mint(uint256 _collectionID, uint256 _numberOfTokens, uint256 _maxAllowance, string memory _tokenData, address _mintTo, bytes32[] calldata merkleProof, address _delegator, uint256 _saltfun_o) public payable {
// @audit _saltfun_o
258: function burnToMint(uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, uint256 _saltfun_o) public payable {
// @audit _saltfun_o
276: function mintAndAuction(address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint _auctionEndTime) public FunctionAdminRequired(this.mintAndAuction.selector) {
// @audit _saltfun_o
326: function burnOrSwapExternalToMint(address _erc721Collection, uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, string memory _tokenData, bytes32[] calldata merkleProof, uint256 _saltfun_o) public payable {
File: smart-contracts/NextGenCore.sol
// @audit _saltfun_o
178: function airDropTokens(uint256 mintIndex, address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID) external {
// @audit _saltfun_o
189: function mint(uint256 mintIndex, address _mintingAddress , address _mintTo, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint256 phase) external {
// @audit _saltfun_o
213: function burnToMint(uint256 mintIndex, uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, uint256 _saltfun_o, address burner) external {
// @audit _saltfun_o
227: function _mintProcessing(uint256 _mintIndex, address _recipient, string memory _tokenData, uint256 _collectionID, uint256 _saltfun_o) internal {
File: smart-contracts/RandomizerNXT.sol
// @audit _saltfun_o
55: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
[55]
File: smart-contracts/RandomizerRNG.sol
// @audit _saltfun_o
53: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
[53]
File: smart-contracts/RandomizerVRF.sol
// @audit COORDINATOR
22: VRFCoordinatorV2Interface public COORDINATOR;
// @audit s_subscriptionId
25: uint64 s_subscriptionId;
// @audit _saltfun_o
71: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
// @audit _s_subscriptionId
86: function updateAdditionalData(uint64 _s_subscriptionId, uint32 _numWords, uint16 _requestConfirmations) public FunctionAdminRequired(this.updateAdditionalData.selector){
Enums, in the style of simple type declarations, should be named using the CapWords style. Examples: TokenGroup, Frame, HashStyle, CharacterLocation
. Documentation
There are 8 instances of this issue.
File: smart-contracts/AuctionDemo.sol
43: struct auctionInfoStru {
[43]
File: smart-contracts/MinterContract.sol
44: struct collectionPhasesDataStructure {
63: struct royaltiesPrimarySplits {
73: struct collectionPrimaryAddresses {
88: struct royaltiesSecondarySplits {
98: struct collectionSecondaryAddresses {
File: smart-contracts/NextGenCore.sol
29: struct collectionInfoStructure {
44: struct collectionAdditonalDataStructure {
This convention is suggested for non-external functions (private or internal). Documentation
There are 4 instances of this issue.
File: smart-contracts/NextGenCore.sol
361: function getTokenName(uint256 tokenId) private view returns(string memory) {
[361]
File: smart-contracts/RandomizerRNG.sol
48: function fulfillRandomWords(uint256 id, uint256[] memory numbers) internal override {
[48]
File: smart-contracts/RandomizerVRF.sol
65: function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override {
[65]
File: smart-contracts/XRandoms.sol
15: function getWord(uint256 id) private pure returns (string memory) {
[15]
This convention is suggested for non-external state variables (private or internal). Documentation
There are 28 instances of this issue.
Expand findings
File: smart-contracts/MinterContract.sol
32: mapping (bytes32 => uint256[2]) private burnOrSwapIds;
41: mapping (uint256 => bool) private setMintingCosts;
59: mapping (uint256 => collectionPhasesDataStructure) private collectionPhases;
70: mapping (uint256 => royaltiesPrimarySplits) private collectionRoyaltiesPrimarySplits;
84: mapping (uint256 => collectionPrimaryAddresses) private collectionArtistPrimaryAddresses;
95: mapping (uint256 => royaltiesSecondarySplits) private collectionRoyaltiesSecondarySplits;
109: mapping (uint256 => collectionSecondaryAddresses) private collectionArtistSecondaryAddresses;
112: mapping (uint256 => uint) private mintToAuctionData;
115: mapping (uint256 => bool) private mintToAuctionStatus;
119: IDelegationManagementContract private dmc;
120: INextGenAdmins private adminsContract;
[32, 41, 59, 70, 84, 95, 109, 112, 115, 119, 120]
File: smart-contracts/NextGenAdmins.sol
21: mapping (address => mapping (uint256 => bool)) private collectionAdmin;
24: mapping (address => mapping (bytes4 => bool)) private functionAdmin;
File: smart-contracts/NextGenCore.sol
41: mapping (uint256 => collectionInfoStructure) private collectionInfo;
57: mapping (uint256 => collectionAdditonalDataStructure) private collectionAdditionalData;
62: mapping (uint256 => bool) private isCollectionCreated;
65: mapping (uint256 => bool) private wereDataAdded;
68: mapping (uint256 => uint256) private tokenIdsToCollectionIds;
71: mapping(uint256 => bytes32) private tokenToHash;
74: mapping (uint256 => mapping (address => uint256)) private tokensMintedPerAddress;
77: mapping (uint256 => mapping (address => uint256)) private tokensMintedAllowlistAddress;
80: mapping (uint256 => mapping (address => uint256)) private tokensAirdropPerAddress;
95: mapping (uint256 => string[2]) private tokenImageAndAttributes;
98: mapping (uint256 => bool) private collectionFreeze;
104: INextGenAdmins private adminsContract;
[41, 57, 62, 65, 68, 71, 74, 77, 80, 95, 98, 104]
File: smart-contracts/RandomizerNXT.sol
21: INextGenAdmins private adminsContract;
[21]
File: smart-contracts/RandomizerRNG.sol
23: INextGenAdmins private adminsContract;
[23]
File: smart-contracts/RandomizerVRF.sol
37: INextGenAdmins private adminsContract;
[37]
Some contracts miss a @dev/@notice
NatSpec, which should be a best practice to add as a documentation.
There are 8 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
18: contract auctionDemo is Ownable {
[18]
File: smart-contracts/MinterContract.sol
20: contract NextGenMinterContract is Ownable {
[20]
File: smart-contracts/NextGenAdmins.sol
15: contract NextGenAdmins is Ownable{
[15]
File: smart-contracts/NextGenCore.sol
22: contract NextGenCore is ERC721Enumerable, Ownable, ERC2981 {
[22]
File: smart-contracts/RandomizerNXT.sol
18: contract NextGenRandomizerNXT {
[18]
File: smart-contracts/RandomizerRNG.sol
18: contract NextGenRandomizerRNG is ArrngConsumer, Ownable {
[18]
File: smart-contracts/RandomizerVRF.sol
19: contract NextGenRandomizerVRF is VRFConsumerBaseV2, Ownable {
[19]
File: smart-contracts/XRandoms.sol
13: contract randomPool {
[13]
Some contract definitions have an incomplete NatSpec: add a @author
notation to improve the code documentation.
There are 8 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
18: contract auctionDemo is Ownable {
[18]
File: smart-contracts/MinterContract.sol
20: contract NextGenMinterContract is Ownable {
[20]
File: smart-contracts/NextGenAdmins.sol
15: contract NextGenAdmins is Ownable{
[15]
File: smart-contracts/NextGenCore.sol
22: contract NextGenCore is ERC721Enumerable, Ownable, ERC2981 {
[22]
File: smart-contracts/RandomizerNXT.sol
18: contract NextGenRandomizerNXT {
[18]
File: smart-contracts/RandomizerRNG.sol
18: contract NextGenRandomizerRNG is ArrngConsumer, Ownable {
[18]
File: smart-contracts/RandomizerVRF.sol
19: contract NextGenRandomizerVRF is VRFConsumerBaseV2, Ownable {
[19]
File: smart-contracts/XRandoms.sol
13: contract randomPool {
[13]
Some contract definitions have an incomplete NatSpec: add a @dev
notation to describe the contract to improve the code documentation.
There are 8 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
18: contract auctionDemo is Ownable {
[18]
File: smart-contracts/MinterContract.sol
20: contract NextGenMinterContract is Ownable {
[20]
File: smart-contracts/NextGenAdmins.sol
15: contract NextGenAdmins is Ownable{
[15]
File: smart-contracts/NextGenCore.sol
22: contract NextGenCore is ERC721Enumerable, Ownable, ERC2981 {
[22]
File: smart-contracts/RandomizerNXT.sol
18: contract NextGenRandomizerNXT {
[18]
File: smart-contracts/RandomizerRNG.sol
18: contract NextGenRandomizerRNG is ArrngConsumer, Ownable {
[18]
File: smart-contracts/RandomizerVRF.sol
19: contract NextGenRandomizerVRF is VRFConsumerBaseV2, Ownable {
[19]
File: smart-contracts/XRandoms.sol
13: contract randomPool {
[13]
Some contract definitions have an incomplete NatSpec: add a @notice
notation to describe the contract to improve the code documentation.
There are 8 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
18: contract auctionDemo is Ownable {
[18]
File: smart-contracts/MinterContract.sol
20: contract NextGenMinterContract is Ownable {
[20]
File: smart-contracts/NextGenAdmins.sol
15: contract NextGenAdmins is Ownable{
[15]
File: smart-contracts/NextGenCore.sol
22: contract NextGenCore is ERC721Enumerable, Ownable, ERC2981 {
[22]
File: smart-contracts/RandomizerNXT.sol
18: contract NextGenRandomizerNXT {
[18]
File: smart-contracts/RandomizerRNG.sol
18: contract NextGenRandomizerRNG is ArrngConsumer, Ownable {
[18]
File: smart-contracts/RandomizerVRF.sol
19: contract NextGenRandomizerVRF is VRFConsumerBaseV2, Ownable {
[19]
File: smart-contracts/XRandoms.sol
13: contract randomPool {
[13]
Some contract definitions have an incomplete NatSpec: add a @title
notation to describe the contract to improve the code documentation.
There are 8 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
18: contract auctionDemo is Ownable {
[18]
File: smart-contracts/MinterContract.sol
20: contract NextGenMinterContract is Ownable {
[20]
File: smart-contracts/NextGenAdmins.sol
15: contract NextGenAdmins is Ownable{
[15]
File: smart-contracts/NextGenCore.sol
22: contract NextGenCore is ERC721Enumerable, Ownable, ERC2981 {
[22]
File: smart-contracts/RandomizerNXT.sol
18: contract NextGenRandomizerNXT {
[18]
File: smart-contracts/RandomizerRNG.sol
18: contract NextGenRandomizerRNG is ArrngConsumer, Ownable {
[18]
File: smart-contracts/RandomizerVRF.sol
19: contract NextGenRandomizerVRF is VRFConsumerBaseV2, Ownable {
[19]
File: smart-contracts/XRandoms.sol
13: contract randomPool {
[13]
Consider adding some comments on event declarations to explain what they are supposed to do: this will help for future code reviews.
There are 8 instances of this issue.
File: smart-contracts/AuctionDemo.sol
22: event ClaimAuction(address indexed _add, uint256 indexed tokenid, bool status, uint256 indexed funds);
23: event Refund(address indexed _add, uint256 indexed tokenid, bool status, uint256 indexed funds);
24: event CancelBid(address indexed _add, uint256 indexed tokenid, uint256 index, bool status, uint256 indexed funds);
File: smart-contracts/MinterContract.sol
124: event PayArtist(address indexed _add, bool status, uint256 indexed funds);
125: event PayTeam(address indexed _add, bool status, uint256 indexed funds);
126: event Withdraw(address indexed _add, bool status, uint256 indexed funds);
File: smart-contracts/RandomizerRNG.sol
24: event Withdraw(address indexed _add, bool status, uint256 indexed funds);
[24]
File: smart-contracts/RandomizerVRF.sol
20: event RequestFulfilled(uint256 requestId, uint256[] randomWords);
[20]
Some events have an incomplete NatSpec: add a @dev
notation to describe the event to improve the code documentation.
There are 8 instances of this issue.
File: smart-contracts/AuctionDemo.sol
22: event ClaimAuction(address indexed _add, uint256 indexed tokenid, bool status, uint256 indexed funds);
23: event Refund(address indexed _add, uint256 indexed tokenid, bool status, uint256 indexed funds);
24: event CancelBid(address indexed _add, uint256 indexed tokenid, uint256 index, bool status, uint256 indexed funds);
File: smart-contracts/MinterContract.sol
124: event PayArtist(address indexed _add, bool status, uint256 indexed funds);
125: event PayTeam(address indexed _add, bool status, uint256 indexed funds);
126: event Withdraw(address indexed _add, bool status, uint256 indexed funds);
File: smart-contracts/RandomizerRNG.sol
24: event Withdraw(address indexed _add, bool status, uint256 indexed funds);
[24]
File: smart-contracts/RandomizerVRF.sol
20: event RequestFulfilled(uint256 requestId, uint256[] randomWords);
[20]
Some events have an incomplete NatSpec: add a @notice
notation to describe the event to improve the code documentation.
There are 8 instances of this issue.
File: smart-contracts/AuctionDemo.sol
22: event ClaimAuction(address indexed _add, uint256 indexed tokenid, bool status, uint256 indexed funds);
23: event Refund(address indexed _add, uint256 indexed tokenid, bool status, uint256 indexed funds);
24: event CancelBid(address indexed _add, uint256 indexed tokenid, uint256 index, bool status, uint256 indexed funds);
File: smart-contracts/MinterContract.sol
124: event PayArtist(address indexed _add, bool status, uint256 indexed funds);
125: event PayTeam(address indexed _add, bool status, uint256 indexed funds);
126: event Withdraw(address indexed _add, bool status, uint256 indexed funds);
File: smart-contracts/RandomizerRNG.sol
24: event Withdraw(address indexed _add, bool status, uint256 indexed funds);
[24]
File: smart-contracts/RandomizerVRF.sol
20: event RequestFulfilled(uint256 requestId, uint256[] randomWords);
[20]
Some events have an incomplete NatSpec: add a @param
notation to describe the event to improve the code documentation.
There are 8 instances of this issue.
File: smart-contracts/AuctionDemo.sol
// @audit missing _add, tokenid, status, funds
22: event ClaimAuction(address indexed _add, uint256 indexed tokenid, bool status, uint256 indexed funds);
// @audit missing _add, tokenid, status, funds
23: event Refund(address indexed _add, uint256 indexed tokenid, bool status, uint256 indexed funds);
// @audit missing _add, tokenid, index, status, funds
24: event CancelBid(address indexed _add, uint256 indexed tokenid, uint256 index, bool status, uint256 indexed funds);
File: smart-contracts/MinterContract.sol
// @audit missing _add, status, funds
124: event PayArtist(address indexed _add, bool status, uint256 indexed funds);
// @audit missing _add, status, funds
125: event PayTeam(address indexed _add, bool status, uint256 indexed funds);
// @audit missing _add, status, funds
126: event Withdraw(address indexed _add, bool status, uint256 indexed funds);
File: smart-contracts/RandomizerRNG.sol
// @audit missing _add, status, funds
24: event Withdraw(address indexed _add, bool status, uint256 indexed funds);
[24]
File: smart-contracts/RandomizerVRF.sol
// @audit missing requestId, randomWords
20: event RequestFulfilled(uint256 requestId, uint256[] randomWords);
[20]
Consider adding some comments on modifier declarations to explain what they are supposed to do: this will help for future code reviews.
There are 10 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
31: modifier WinnerOrAdminRequired(uint256 _tokenId, bytes4 _selector) {
[31]
File: smart-contracts/MinterContract.sol
136: modifier ArtistOrAdminRequired(uint256 _collectionID, bytes4 _selector) {
143: modifier FunctionAdminRequired(bytes4 _selector) {
150: modifier CollectionAdminRequired(uint256 _collectionID, bytes4 _selector) {
File: smart-contracts/NextGenAdmins.sol
31: modifier AdminRequired {
[31]
File: smart-contracts/NextGenCore.sol
116: modifier FunctionAdminRequired(bytes4 _selector) {
123: modifier CollectionAdminRequired(uint256 _collectionID, bytes4 _selector) {
File: smart-contracts/RandomizerNXT.sol
34: modifier FunctionAdminRequired(bytes4 _selector) {
[34]
File: smart-contracts/RandomizerRNG.sol
35: modifier FunctionAdminRequired(bytes4 _selector) {
[35]
File: smart-contracts/RandomizerVRF.sol
47: modifier FunctionAdminRequired(bytes4 _selector) {
[47]
Some modifiers have an incomplete NatSpec: add a @dev
notation to describe the modifier to improve the code documentation.
There are 10 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
31: modifier WinnerOrAdminRequired(uint256 _tokenId, bytes4 _selector) {
[31]
File: smart-contracts/MinterContract.sol
136: modifier ArtistOrAdminRequired(uint256 _collectionID, bytes4 _selector) {
143: modifier FunctionAdminRequired(bytes4 _selector) {
150: modifier CollectionAdminRequired(uint256 _collectionID, bytes4 _selector) {
File: smart-contracts/NextGenAdmins.sol
31: modifier AdminRequired {
[31]
File: smart-contracts/NextGenCore.sol
116: modifier FunctionAdminRequired(bytes4 _selector) {
123: modifier CollectionAdminRequired(uint256 _collectionID, bytes4 _selector) {
File: smart-contracts/RandomizerNXT.sol
34: modifier FunctionAdminRequired(bytes4 _selector) {
[34]
File: smart-contracts/RandomizerRNG.sol
35: modifier FunctionAdminRequired(bytes4 _selector) {
[35]
File: smart-contracts/RandomizerVRF.sol
47: modifier FunctionAdminRequired(bytes4 _selector) {
[47]
Some modifiers have an incomplete NatSpec: add a @notice
notation to describe the modifier to improve the code documentation.
There are 10 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
31: modifier WinnerOrAdminRequired(uint256 _tokenId, bytes4 _selector) {
[31]
File: smart-contracts/MinterContract.sol
136: modifier ArtistOrAdminRequired(uint256 _collectionID, bytes4 _selector) {
143: modifier FunctionAdminRequired(bytes4 _selector) {
150: modifier CollectionAdminRequired(uint256 _collectionID, bytes4 _selector) {
File: smart-contracts/NextGenAdmins.sol
31: modifier AdminRequired {
[31]
File: smart-contracts/NextGenCore.sol
116: modifier FunctionAdminRequired(bytes4 _selector) {
123: modifier CollectionAdminRequired(uint256 _collectionID, bytes4 _selector) {
File: smart-contracts/RandomizerNXT.sol
34: modifier FunctionAdminRequired(bytes4 _selector) {
[34]
File: smart-contracts/RandomizerRNG.sol
35: modifier FunctionAdminRequired(bytes4 _selector) {
[35]
File: smart-contracts/RandomizerVRF.sol
47: modifier FunctionAdminRequired(bytes4 _selector) {
[47]
Some modifiers have an incomplete NatSpec: add a @param
notation to describe the modifier parameters to improve the code documentation.
There are 9 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
// @audit missing _tokenId, _selector
31: modifier WinnerOrAdminRequired(uint256 _tokenId, bytes4 _selector) {
[31]
File: smart-contracts/MinterContract.sol
// @audit missing _collectionID, _selector
136: modifier ArtistOrAdminRequired(uint256 _collectionID, bytes4 _selector) {
// @audit missing _selector
143: modifier FunctionAdminRequired(bytes4 _selector) {
// @audit missing _collectionID, _selector
150: modifier CollectionAdminRequired(uint256 _collectionID, bytes4 _selector) {
File: smart-contracts/NextGenCore.sol
// @audit missing _selector
116: modifier FunctionAdminRequired(bytes4 _selector) {
// @audit missing _collectionID, _selector
123: modifier CollectionAdminRequired(uint256 _collectionID, bytes4 _selector) {
File: smart-contracts/RandomizerNXT.sol
// @audit missing _selector
34: modifier FunctionAdminRequired(bytes4 _selector) {
[34]
File: smart-contracts/RandomizerRNG.sol
// @audit missing _selector
35: modifier FunctionAdminRequired(bytes4 _selector) {
[35]
File: smart-contracts/RandomizerVRF.sol
// @audit missing _selector
47: modifier FunctionAdminRequired(bytes4 _selector) {
[47]
Some functions miss a NatSpec, which should be a best practice to add as a documentation.
Even if Natspec for internal and private function is not parsed (but this may change in the future, according to the official docs), it still helps while reviewing the codebase.
There are 110 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
57: function participateToAuction(uint256 _tokenid) public payable {
65: function returnHighestBid(uint256 _tokenid) public view returns (uint256) {
87: function returnHighestBidder(uint256 _tokenid) public view returns (address) {
104: function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){
124: function cancelBid(uint256 _tokenid, uint256 index) public {
134: function cancelAllBids(uint256 _tokenid) public {
147: function returnBids(uint256 _tokenid) public view returns(auctionInfoStru[] memory) {
[57, 65, 87, 104, 124, 134, 147]
File: smart-contracts/MinterContract.sol
157: function setCollectionCosts(uint256 _collectionID, uint256 _collectionMintCost, uint256 _collectionEndMintCost, uint256 _rate, uint256 _timePeriod, uint8 _salesOption, address _delAddress) public CollectionAdminRequired(_collectionID, this.setCollectionCosts.selector) {
170: function setCollectionPhases(uint256 _collectionID, uint _allowlistStartTime, uint _allowlistEndTime, uint _publicStartTime, uint _publicEndTime, bytes32 _merkleRoot) public CollectionAdminRequired(_collectionID, this.setCollectionPhases.selector) {
181: function airDropTokens(address[] memory _recipients, string[] memory _tokenData, uint256[] memory _saltfun_o, uint256 _collectionID, uint256[] memory _numberOfTokens) public FunctionAdminRequired(this.airDropTokens.selector) {
196: function mint(uint256 _collectionID, uint256 _numberOfTokens, uint256 _maxAllowance, string memory _tokenData, address _mintTo, bytes32[] calldata merkleProof, address _delegator, uint256 _saltfun_o) public payable {
258: function burnToMint(uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, uint256 _saltfun_o) public payable {
276: function mintAndAuction(address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint _auctionEndTime) public FunctionAdminRequired(this.mintAndAuction.selector) {
302: function updateDelegationCollection(uint256 _collectionID, address _collectionAddress) public FunctionAdminRequired(this.updateDelegationCollection.selector) {
308: function initializeBurn(uint256 _burnCollectionID, uint256 _mintCollectionID, bool _status) public FunctionAdminRequired(this.initializeBurn.selector) {
315: function initializeExternalBurnOrSwap(address _erc721Collection, uint256 _burnCollectionID, uint256 _mintCollectionID, uint256 _tokmin, uint256 _tokmax, address _burnOrSwapAddress, bool _status) public FunctionAdminRequired(this.initializeExternalBurnOrSwap.selector) {
326: function burnOrSwapExternalToMint(address _erc721Collection, uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, string memory _tokenData, bytes32[] calldata merkleProof, uint256 _saltfun_o) public payable {
369: function setPrimaryAndSecondarySplits(uint256 _collectionID, uint256 _artistPrSplit, uint256 _teamPrSplit, uint256 _artistSecSplit, uint256 _teamSecSplit) public FunctionAdminRequired(this.setPrimaryAndSecondarySplits.selector) {
380: function proposePrimaryAddressesAndPercentages(uint256 _collectionID, address _primaryAdd1, address _primaryAdd2, address _primaryAdd3, uint256 _add1Percentage, uint256 _add2Percentage, uint256 _add3Percentage) public ArtistOrAdminRequired(_collectionID, this.proposePrimaryAddressesAndPercentages.selector) {
394: function proposeSecondaryAddressesAndPercentages(uint256 _collectionID, address _secondaryAdd1, address _secondaryAdd2, address _secondaryAdd3, uint256 _add1Percentage, uint256 _add2Percentage, uint256 _add3Percentage) public ArtistOrAdminRequired(_collectionID, this.proposeSecondaryAddressesAndPercentages.selector) {
408: function acceptAddressesAndPercentages(uint256 _collectionID, bool _statusPrimary, bool _statusSecondary) public FunctionAdminRequired(this.acceptAddressesAndPercentages.selector) {
415: function payArtist(uint256 _collectionID, address _team1, address _team2, uint256 _teamperc1, uint256 _teamperc2) public FunctionAdminRequired(this.payArtist.selector) {
448: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
454: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
461: function emergencyWithdraw() public FunctionAdminRequired(this.emergencyWithdraw.selector) {
470: function retrievePrimarySplits(uint256 _collectionID) public view returns(uint256, uint256){
476: function retrievePrimaryAddressesAndPercentages(uint256 _collectionID) public view returns(address, address, address, uint256, uint256, uint256, bool){
482: function retrieveSecondarySplits(uint256 _collectionID) public view returns(uint256, uint256){
488: function retrieveSecondaryAddressesAndPercentages(uint256 _collectionID) public view returns(address, address, address, uint256, uint256, uint256, bool){
494: function retrieveCollectionPhases(uint256 _collectionID) public view returns(uint, uint, bytes32, uint, uint){
500: function retrieveCollectionMintingDetails(uint256 _collectionID) public view returns(uint256, uint256, uint256, uint256, uint8, address){
506: function isMinterContract() external view returns (bool) {
512: function getEndTime(uint256 _collectionID) external view returns (uint) {
518: function getAuctionEndTime(uint256 _tokenId) external view returns (uint) {
524: function getAuctionStatus(uint256 _tokenId) external view returns (bool) {
530: function getPrice(uint256 _collectionId) public view returns (uint256) {
[157, 170, 181, 196, 258, 276, 302, 308, 315, 326, 369, 380, 394, 408, 415, 448, 454, 461, 470, 476, 482, 488, 494, 500, 506, 512, 518, 524, 530]
File: smart-contracts/NextGenAdmins.sol
38: function registerAdmin(address _admin, bool _status) public onlyOwner {
44: function registerFunctionAdmin(address _address, bytes4 _selector, bool _status) public AdminRequired {
50: function registerBatchFunctionAdmin(address _address, bytes4[] memory _selector, bool _status) public AdminRequired {
58: function registerCollectionAdmin(uint256 _collectionID, address _address, bool _status) public AdminRequired {
65: function retrieveGlobalAdmin(address _address) public view returns(bool) {
71: function retrieveFunctionAdmin(address _address, bytes4 _selector) public view returns(bool) {
77: function retrieveCollectionAdmin(address _address, uint256 _collectionID) public view returns(bool) {
83: function isAdminContract() external view returns (bool) {
[38, 44, 50, 58, 65, 71, 77, 83]
File: smart-contracts/NextGenCore.sol
130: function createCollection(string memory _collectionName, string memory _collectionArtist, string memory _collectionDescription, string memory _collectionWebsite, string memory _collectionLicense, string memory _collectionBaseURI, string memory _collectionLibrary, string[] memory _collectionScript) public FunctionAdminRequired(this.createCollection.selector) {
147: function setCollectionData(uint256 _collectionID, address _collectionArtistAddress, uint256 _maxCollectionPurchases, uint256 _collectionTotalSupply, uint _setFinalSupplyTimeAfterMint) public CollectionAdminRequired(_collectionID, this.setCollectionData.selector) {
170: function addRandomizer(uint256 _collectionID, address _randomizerContract) public FunctionAdminRequired(this.addRandomizer.selector) {
178: function airDropTokens(uint256 mintIndex, address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID) external {
189: function mint(uint256 mintIndex, address _mintingAddress , address _mintTo, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint256 phase) external {
204: function burn(uint256 _collectionID, uint256 _tokenId) public {
213: function burnToMint(uint256 mintIndex, uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, uint256 _saltfun_o, address burner) external {
227: function _mintProcessing(uint256 _mintIndex, address _recipient, string memory _tokenData, uint256 _collectionID, uint256 _saltfun_o) internal {
238: function updateCollectionInfo(uint256 _collectionID, string memory _newCollectionName, string memory _newCollectionArtist, string memory _newCollectionDescription, string memory _newCollectionWebsite, string memory _newCollectionLicense, string memory _newCollectionBaseURI, string memory _newCollectionLibrary, uint256 _index, string[] memory _newCollectionScript) public CollectionAdminRequired(_collectionID, this.updateCollectionInfo.selector) {
257: function artistSignature(uint256 _collectionID, string memory _signature) public {
266: function changeMetadataView(uint256 _collectionID, bool _status) public CollectionAdminRequired(_collectionID, this.changeMetadataView.selector) {
273: function changeTokenData(uint256 _tokenId, string memory newData) public FunctionAdminRequired(this.changeTokenData.selector) {
281: function updateImagesAndAttributes(uint256[] memory _tokenId, string[] memory _images, string[] memory _attributes) public FunctionAdminRequired(this.updateImagesAndAttributes.selector) {
292: function freezeCollection(uint256 _collectionID) public FunctionAdminRequired(this.freezeCollection.selector) {
299: function setTokenHash(uint256 _collectionID, uint256 _mintIndex, bytes32 _hash) external {
307: function setFinalSupply(uint256 _collectionID) public FunctionAdminRequired(this.setFinalSupply.selector) {
315: function addMinterContract(address _minterContract) public FunctionAdminRequired(this.addMinterContract.selector) {
322: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
329: function setDefaultRoyalties(address _royaltyAddress, uint96 _bps) public FunctionAdminRequired(this.setDefaultRoyalties.selector) {
337: function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721Enumerable, ERC2981) returns (bool) {
343: function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
361: function getTokenName(uint256 tokenId) private view returns(string memory) {
367: function collectionFreezeStatus(uint256 _collectionID) public view returns(bool){
372: function viewColIDforTokenID(uint256 _tokenid) public view returns (uint256) {
377: function retrievewereDataAdded(uint256 _collectionID) external view returns(bool){
383: function viewTokensIndexMin(uint256 _collectionID) external view returns (uint256) {
389: function viewTokensIndexMax(uint256 _collectionID) external view returns (uint256) {
394: function viewCirSupply(uint256 _collectionID) external view returns (uint256) {
399: function viewMaxAllowance(uint256 _collectionID) external view returns (uint256) {
404: function retrieveTokensMintedALPerAddress(uint256 _collectionID, address _address) external view returns(uint256) {
409: function retrieveTokensMintedPublicPerAddress(uint256 _collectionID, address _address) external view returns(uint256) {
415: function retrieveTokensAirdroppedPerAddress(uint256 _collectionID, address _address) public view returns(uint256) {
420: function retrieveArtistAddress(uint256 _collectionID) external view returns(address) {
426: function retrieveCollectionInfo(uint256 _collectionID) public view returns(string memory, string memory, string memory, string memory, string memory, string memory){
432: function retrieveCollectionLibraryAndScript(uint256 _collectionID) public view returns(string memory, string[] memory){
438: function retrieveCollectionAdditionalData(uint256 _collectionID) public view returns(address, uint256, uint256, uint256, uint, address){
444: function retrieveTokenHash(uint256 _tokenid) public view returns(bytes32){
450: function retrieveGenerativeScript(uint256 tokenId) public view returns(string memory){
461: function totalSupplyOfCollection(uint256 _collectionID) public view returns (uint256) {
467: function retrievetokenImageAndAttributes(uint256 _tokenId) public view returns(string memory, string memory) {
[130, 147, 170, 178, 189, 204, 213, 227, 238, 257, 266, 273, 281, 292, 299, 307, 315, 322, 329, 337, 343, 361, 367, 372, 377, 383, 389, 394, 399, 404, 409, 415, 420, 426, 432, 438, 444, 450, 461, 467]
File: smart-contracts/RandomizerNXT.sol
41: function updateRandomsContract(address _randoms) public FunctionAdminRequired(this.updateRandomsContract.selector) {
45: function updateAdminsContract(address _admin) public FunctionAdminRequired(this.updateAdminsContract.selector) {
49: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
55: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
62: function isRandomizerContract() external view returns (bool) {
File: smart-contracts/RandomizerRNG.sol
40: function requestRandomWords(uint256 tokenid, uint256 _ethRequired) public payable {
48: function fulfillRandomWords(uint256 id, uint256[] memory numbers) internal override {
53: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
61: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
66: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
73: function updateRNGCost(uint256 _ethRequired) public FunctionAdminRequired(this.updateRNGCost.selector) {
79: function emergencyWithdraw() public FunctionAdminRequired(this.emergencyWithdraw.selector) {
86: receive() external payable {}
89: function isRandomizerContract() external view returns (bool) {
[40, 48, 53, 61, 66, 73, 79, 86, 89]
File: smart-contracts/RandomizerVRF.sol
52: function requestRandomWords(uint256 tokenid) public {
65: function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override {
71: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
79: function updatecallbackGasLimitAndkeyHash(uint32 _callbackGasLimit, bytes32 _keyHash) public FunctionAdminRequired(this.updatecallbackGasLimitAndkeyHash.selector){
86: function updateAdditionalData(uint64 _s_subscriptionId, uint32 _numWords, uint16 _requestConfirmations) public FunctionAdminRequired(this.updateAdditionalData.selector){
94: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
99: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
105: function isRandomizerContract() external view returns (bool) {
[52, 65, 71, 79, 86, 94, 99, 105]
File: smart-contracts/XRandoms.sol
15: function getWord(uint256 id) private pure returns (string memory) {
35: function randomNumber() public view returns (uint256){
40: function randomWord() public view returns (string memory) {
45: function returnIndex(uint256 id) public view returns (string memory) {
Some functions have an incomplete NatSpec: add a @dev
notation to describe the function to improve the code documentation.
There are 110 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
57: function participateToAuction(uint256 _tokenid) public payable {
65: function returnHighestBid(uint256 _tokenid) public view returns (uint256) {
87: function returnHighestBidder(uint256 _tokenid) public view returns (address) {
104: function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){
124: function cancelBid(uint256 _tokenid, uint256 index) public {
134: function cancelAllBids(uint256 _tokenid) public {
147: function returnBids(uint256 _tokenid) public view returns(auctionInfoStru[] memory) {
[57, 65, 87, 104, 124, 134, 147]
File: smart-contracts/MinterContract.sol
157: function setCollectionCosts(uint256 _collectionID, uint256 _collectionMintCost, uint256 _collectionEndMintCost, uint256 _rate, uint256 _timePeriod, uint8 _salesOption, address _delAddress) public CollectionAdminRequired(_collectionID, this.setCollectionCosts.selector) {
170: function setCollectionPhases(uint256 _collectionID, uint _allowlistStartTime, uint _allowlistEndTime, uint _publicStartTime, uint _publicEndTime, bytes32 _merkleRoot) public CollectionAdminRequired(_collectionID, this.setCollectionPhases.selector) {
181: function airDropTokens(address[] memory _recipients, string[] memory _tokenData, uint256[] memory _saltfun_o, uint256 _collectionID, uint256[] memory _numberOfTokens) public FunctionAdminRequired(this.airDropTokens.selector) {
196: function mint(uint256 _collectionID, uint256 _numberOfTokens, uint256 _maxAllowance, string memory _tokenData, address _mintTo, bytes32[] calldata merkleProof, address _delegator, uint256 _saltfun_o) public payable {
258: function burnToMint(uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, uint256 _saltfun_o) public payable {
276: function mintAndAuction(address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint _auctionEndTime) public FunctionAdminRequired(this.mintAndAuction.selector) {
302: function updateDelegationCollection(uint256 _collectionID, address _collectionAddress) public FunctionAdminRequired(this.updateDelegationCollection.selector) {
308: function initializeBurn(uint256 _burnCollectionID, uint256 _mintCollectionID, bool _status) public FunctionAdminRequired(this.initializeBurn.selector) {
315: function initializeExternalBurnOrSwap(address _erc721Collection, uint256 _burnCollectionID, uint256 _mintCollectionID, uint256 _tokmin, uint256 _tokmax, address _burnOrSwapAddress, bool _status) public FunctionAdminRequired(this.initializeExternalBurnOrSwap.selector) {
326: function burnOrSwapExternalToMint(address _erc721Collection, uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, string memory _tokenData, bytes32[] calldata merkleProof, uint256 _saltfun_o) public payable {
369: function setPrimaryAndSecondarySplits(uint256 _collectionID, uint256 _artistPrSplit, uint256 _teamPrSplit, uint256 _artistSecSplit, uint256 _teamSecSplit) public FunctionAdminRequired(this.setPrimaryAndSecondarySplits.selector) {
380: function proposePrimaryAddressesAndPercentages(uint256 _collectionID, address _primaryAdd1, address _primaryAdd2, address _primaryAdd3, uint256 _add1Percentage, uint256 _add2Percentage, uint256 _add3Percentage) public ArtistOrAdminRequired(_collectionID, this.proposePrimaryAddressesAndPercentages.selector) {
394: function proposeSecondaryAddressesAndPercentages(uint256 _collectionID, address _secondaryAdd1, address _secondaryAdd2, address _secondaryAdd3, uint256 _add1Percentage, uint256 _add2Percentage, uint256 _add3Percentage) public ArtistOrAdminRequired(_collectionID, this.proposeSecondaryAddressesAndPercentages.selector) {
408: function acceptAddressesAndPercentages(uint256 _collectionID, bool _statusPrimary, bool _statusSecondary) public FunctionAdminRequired(this.acceptAddressesAndPercentages.selector) {
415: function payArtist(uint256 _collectionID, address _team1, address _team2, uint256 _teamperc1, uint256 _teamperc2) public FunctionAdminRequired(this.payArtist.selector) {
448: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
454: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
461: function emergencyWithdraw() public FunctionAdminRequired(this.emergencyWithdraw.selector) {
470: function retrievePrimarySplits(uint256 _collectionID) public view returns(uint256, uint256){
476: function retrievePrimaryAddressesAndPercentages(uint256 _collectionID) public view returns(address, address, address, uint256, uint256, uint256, bool){
482: function retrieveSecondarySplits(uint256 _collectionID) public view returns(uint256, uint256){
488: function retrieveSecondaryAddressesAndPercentages(uint256 _collectionID) public view returns(address, address, address, uint256, uint256, uint256, bool){
494: function retrieveCollectionPhases(uint256 _collectionID) public view returns(uint, uint, bytes32, uint, uint){
500: function retrieveCollectionMintingDetails(uint256 _collectionID) public view returns(uint256, uint256, uint256, uint256, uint8, address){
506: function isMinterContract() external view returns (bool) {
512: function getEndTime(uint256 _collectionID) external view returns (uint) {
518: function getAuctionEndTime(uint256 _tokenId) external view returns (uint) {
524: function getAuctionStatus(uint256 _tokenId) external view returns (bool) {
530: function getPrice(uint256 _collectionId) public view returns (uint256) {
[157, 170, 181, 196, 258, 276, 302, 308, 315, 326, 369, 380, 394, 408, 415, 448, 454, 461, 470, 476, 482, 488, 494, 500, 506, 512, 518, 524, 530]
File: smart-contracts/NextGenAdmins.sol
38: function registerAdmin(address _admin, bool _status) public onlyOwner {
44: function registerFunctionAdmin(address _address, bytes4 _selector, bool _status) public AdminRequired {
50: function registerBatchFunctionAdmin(address _address, bytes4[] memory _selector, bool _status) public AdminRequired {
58: function registerCollectionAdmin(uint256 _collectionID, address _address, bool _status) public AdminRequired {
65: function retrieveGlobalAdmin(address _address) public view returns(bool) {
71: function retrieveFunctionAdmin(address _address, bytes4 _selector) public view returns(bool) {
77: function retrieveCollectionAdmin(address _address, uint256 _collectionID) public view returns(bool) {
83: function isAdminContract() external view returns (bool) {
[38, 44, 50, 58, 65, 71, 77, 83]
File: smart-contracts/NextGenCore.sol
130: function createCollection(string memory _collectionName, string memory _collectionArtist, string memory _collectionDescription, string memory _collectionWebsite, string memory _collectionLicense, string memory _collectionBaseURI, string memory _collectionLibrary, string[] memory _collectionScript) public FunctionAdminRequired(this.createCollection.selector) {
147: function setCollectionData(uint256 _collectionID, address _collectionArtistAddress, uint256 _maxCollectionPurchases, uint256 _collectionTotalSupply, uint _setFinalSupplyTimeAfterMint) public CollectionAdminRequired(_collectionID, this.setCollectionData.selector) {
170: function addRandomizer(uint256 _collectionID, address _randomizerContract) public FunctionAdminRequired(this.addRandomizer.selector) {
178: function airDropTokens(uint256 mintIndex, address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID) external {
189: function mint(uint256 mintIndex, address _mintingAddress , address _mintTo, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint256 phase) external {
204: function burn(uint256 _collectionID, uint256 _tokenId) public {
213: function burnToMint(uint256 mintIndex, uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, uint256 _saltfun_o, address burner) external {
227: function _mintProcessing(uint256 _mintIndex, address _recipient, string memory _tokenData, uint256 _collectionID, uint256 _saltfun_o) internal {
238: function updateCollectionInfo(uint256 _collectionID, string memory _newCollectionName, string memory _newCollectionArtist, string memory _newCollectionDescription, string memory _newCollectionWebsite, string memory _newCollectionLicense, string memory _newCollectionBaseURI, string memory _newCollectionLibrary, uint256 _index, string[] memory _newCollectionScript) public CollectionAdminRequired(_collectionID, this.updateCollectionInfo.selector) {
257: function artistSignature(uint256 _collectionID, string memory _signature) public {
266: function changeMetadataView(uint256 _collectionID, bool _status) public CollectionAdminRequired(_collectionID, this.changeMetadataView.selector) {
273: function changeTokenData(uint256 _tokenId, string memory newData) public FunctionAdminRequired(this.changeTokenData.selector) {
281: function updateImagesAndAttributes(uint256[] memory _tokenId, string[] memory _images, string[] memory _attributes) public FunctionAdminRequired(this.updateImagesAndAttributes.selector) {
292: function freezeCollection(uint256 _collectionID) public FunctionAdminRequired(this.freezeCollection.selector) {
299: function setTokenHash(uint256 _collectionID, uint256 _mintIndex, bytes32 _hash) external {
307: function setFinalSupply(uint256 _collectionID) public FunctionAdminRequired(this.setFinalSupply.selector) {
315: function addMinterContract(address _minterContract) public FunctionAdminRequired(this.addMinterContract.selector) {
322: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
329: function setDefaultRoyalties(address _royaltyAddress, uint96 _bps) public FunctionAdminRequired(this.setDefaultRoyalties.selector) {
337: function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721Enumerable, ERC2981) returns (bool) {
343: function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
361: function getTokenName(uint256 tokenId) private view returns(string memory) {
367: function collectionFreezeStatus(uint256 _collectionID) public view returns(bool){
372: function viewColIDforTokenID(uint256 _tokenid) public view returns (uint256) {
377: function retrievewereDataAdded(uint256 _collectionID) external view returns(bool){
383: function viewTokensIndexMin(uint256 _collectionID) external view returns (uint256) {
389: function viewTokensIndexMax(uint256 _collectionID) external view returns (uint256) {
394: function viewCirSupply(uint256 _collectionID) external view returns (uint256) {
399: function viewMaxAllowance(uint256 _collectionID) external view returns (uint256) {
404: function retrieveTokensMintedALPerAddress(uint256 _collectionID, address _address) external view returns(uint256) {
409: function retrieveTokensMintedPublicPerAddress(uint256 _collectionID, address _address) external view returns(uint256) {
415: function retrieveTokensAirdroppedPerAddress(uint256 _collectionID, address _address) public view returns(uint256) {
420: function retrieveArtistAddress(uint256 _collectionID) external view returns(address) {
426: function retrieveCollectionInfo(uint256 _collectionID) public view returns(string memory, string memory, string memory, string memory, string memory, string memory){
432: function retrieveCollectionLibraryAndScript(uint256 _collectionID) public view returns(string memory, string[] memory){
438: function retrieveCollectionAdditionalData(uint256 _collectionID) public view returns(address, uint256, uint256, uint256, uint, address){
444: function retrieveTokenHash(uint256 _tokenid) public view returns(bytes32){
450: function retrieveGenerativeScript(uint256 tokenId) public view returns(string memory){
461: function totalSupplyOfCollection(uint256 _collectionID) public view returns (uint256) {
467: function retrievetokenImageAndAttributes(uint256 _tokenId) public view returns(string memory, string memory) {
[130, 147, 170, 178, 189, 204, 213, 227, 238, 257, 266, 273, 281, 292, 299, 307, 315, 322, 329, 337, 343, 361, 367, 372, 377, 383, 389, 394, 399, 404, 409, 415, 420, 426, 432, 438, 444, 450, 461, 467]
File: smart-contracts/RandomizerNXT.sol
41: function updateRandomsContract(address _randoms) public FunctionAdminRequired(this.updateRandomsContract.selector) {
45: function updateAdminsContract(address _admin) public FunctionAdminRequired(this.updateAdminsContract.selector) {
49: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
55: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
62: function isRandomizerContract() external view returns (bool) {
File: smart-contracts/RandomizerRNG.sol
40: function requestRandomWords(uint256 tokenid, uint256 _ethRequired) public payable {
48: function fulfillRandomWords(uint256 id, uint256[] memory numbers) internal override {
53: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
61: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
66: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
73: function updateRNGCost(uint256 _ethRequired) public FunctionAdminRequired(this.updateRNGCost.selector) {
79: function emergencyWithdraw() public FunctionAdminRequired(this.emergencyWithdraw.selector) {
86: receive() external payable {}
89: function isRandomizerContract() external view returns (bool) {
[40, 48, 53, 61, 66, 73, 79, 86, 89]
File: smart-contracts/RandomizerVRF.sol
52: function requestRandomWords(uint256 tokenid) public {
65: function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override {
71: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
79: function updatecallbackGasLimitAndkeyHash(uint32 _callbackGasLimit, bytes32 _keyHash) public FunctionAdminRequired(this.updatecallbackGasLimitAndkeyHash.selector){
86: function updateAdditionalData(uint64 _s_subscriptionId, uint32 _numWords, uint16 _requestConfirmations) public FunctionAdminRequired(this.updateAdditionalData.selector){
94: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
99: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
105: function isRandomizerContract() external view returns (bool) {
[52, 65, 71, 79, 86, 94, 99, 105]
File: smart-contracts/XRandoms.sol
15: function getWord(uint256 id) private pure returns (string memory) {
35: function randomNumber() public view returns (uint256){
40: function randomWord() public view returns (string memory) {
45: function returnIndex(uint256 id) public view returns (string memory) {
Some functions have an incomplete NatSpec: add a @notice
notation to describe the function to improve the code documentation.
There are 110 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
57: function participateToAuction(uint256 _tokenid) public payable {
65: function returnHighestBid(uint256 _tokenid) public view returns (uint256) {
87: function returnHighestBidder(uint256 _tokenid) public view returns (address) {
104: function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){
124: function cancelBid(uint256 _tokenid, uint256 index) public {
134: function cancelAllBids(uint256 _tokenid) public {
147: function returnBids(uint256 _tokenid) public view returns(auctionInfoStru[] memory) {
[57, 65, 87, 104, 124, 134, 147]
File: smart-contracts/MinterContract.sol
157: function setCollectionCosts(uint256 _collectionID, uint256 _collectionMintCost, uint256 _collectionEndMintCost, uint256 _rate, uint256 _timePeriod, uint8 _salesOption, address _delAddress) public CollectionAdminRequired(_collectionID, this.setCollectionCosts.selector) {
170: function setCollectionPhases(uint256 _collectionID, uint _allowlistStartTime, uint _allowlistEndTime, uint _publicStartTime, uint _publicEndTime, bytes32 _merkleRoot) public CollectionAdminRequired(_collectionID, this.setCollectionPhases.selector) {
181: function airDropTokens(address[] memory _recipients, string[] memory _tokenData, uint256[] memory _saltfun_o, uint256 _collectionID, uint256[] memory _numberOfTokens) public FunctionAdminRequired(this.airDropTokens.selector) {
196: function mint(uint256 _collectionID, uint256 _numberOfTokens, uint256 _maxAllowance, string memory _tokenData, address _mintTo, bytes32[] calldata merkleProof, address _delegator, uint256 _saltfun_o) public payable {
258: function burnToMint(uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, uint256 _saltfun_o) public payable {
276: function mintAndAuction(address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint _auctionEndTime) public FunctionAdminRequired(this.mintAndAuction.selector) {
302: function updateDelegationCollection(uint256 _collectionID, address _collectionAddress) public FunctionAdminRequired(this.updateDelegationCollection.selector) {
308: function initializeBurn(uint256 _burnCollectionID, uint256 _mintCollectionID, bool _status) public FunctionAdminRequired(this.initializeBurn.selector) {
315: function initializeExternalBurnOrSwap(address _erc721Collection, uint256 _burnCollectionID, uint256 _mintCollectionID, uint256 _tokmin, uint256 _tokmax, address _burnOrSwapAddress, bool _status) public FunctionAdminRequired(this.initializeExternalBurnOrSwap.selector) {
326: function burnOrSwapExternalToMint(address _erc721Collection, uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, string memory _tokenData, bytes32[] calldata merkleProof, uint256 _saltfun_o) public payable {
369: function setPrimaryAndSecondarySplits(uint256 _collectionID, uint256 _artistPrSplit, uint256 _teamPrSplit, uint256 _artistSecSplit, uint256 _teamSecSplit) public FunctionAdminRequired(this.setPrimaryAndSecondarySplits.selector) {
380: function proposePrimaryAddressesAndPercentages(uint256 _collectionID, address _primaryAdd1, address _primaryAdd2, address _primaryAdd3, uint256 _add1Percentage, uint256 _add2Percentage, uint256 _add3Percentage) public ArtistOrAdminRequired(_collectionID, this.proposePrimaryAddressesAndPercentages.selector) {
394: function proposeSecondaryAddressesAndPercentages(uint256 _collectionID, address _secondaryAdd1, address _secondaryAdd2, address _secondaryAdd3, uint256 _add1Percentage, uint256 _add2Percentage, uint256 _add3Percentage) public ArtistOrAdminRequired(_collectionID, this.proposeSecondaryAddressesAndPercentages.selector) {
408: function acceptAddressesAndPercentages(uint256 _collectionID, bool _statusPrimary, bool _statusSecondary) public FunctionAdminRequired(this.acceptAddressesAndPercentages.selector) {
415: function payArtist(uint256 _collectionID, address _team1, address _team2, uint256 _teamperc1, uint256 _teamperc2) public FunctionAdminRequired(this.payArtist.selector) {
448: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
454: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
461: function emergencyWithdraw() public FunctionAdminRequired(this.emergencyWithdraw.selector) {
470: function retrievePrimarySplits(uint256 _collectionID) public view returns(uint256, uint256){
476: function retrievePrimaryAddressesAndPercentages(uint256 _collectionID) public view returns(address, address, address, uint256, uint256, uint256, bool){
482: function retrieveSecondarySplits(uint256 _collectionID) public view returns(uint256, uint256){
488: function retrieveSecondaryAddressesAndPercentages(uint256 _collectionID) public view returns(address, address, address, uint256, uint256, uint256, bool){
494: function retrieveCollectionPhases(uint256 _collectionID) public view returns(uint, uint, bytes32, uint, uint){
500: function retrieveCollectionMintingDetails(uint256 _collectionID) public view returns(uint256, uint256, uint256, uint256, uint8, address){
506: function isMinterContract() external view returns (bool) {
512: function getEndTime(uint256 _collectionID) external view returns (uint) {
518: function getAuctionEndTime(uint256 _tokenId) external view returns (uint) {
524: function getAuctionStatus(uint256 _tokenId) external view returns (bool) {
530: function getPrice(uint256 _collectionId) public view returns (uint256) {
[157, 170, 181, 196, 258, 276, 302, 308, 315, 326, 369, 380, 394, 408, 415, 448, 454, 461, 470, 476, 482, 488, 494, 500, 506, 512, 518, 524, 530]
File: smart-contracts/NextGenAdmins.sol
38: function registerAdmin(address _admin, bool _status) public onlyOwner {
44: function registerFunctionAdmin(address _address, bytes4 _selector, bool _status) public AdminRequired {
50: function registerBatchFunctionAdmin(address _address, bytes4[] memory _selector, bool _status) public AdminRequired {
58: function registerCollectionAdmin(uint256 _collectionID, address _address, bool _status) public AdminRequired {
65: function retrieveGlobalAdmin(address _address) public view returns(bool) {
71: function retrieveFunctionAdmin(address _address, bytes4 _selector) public view returns(bool) {
77: function retrieveCollectionAdmin(address _address, uint256 _collectionID) public view returns(bool) {
83: function isAdminContract() external view returns (bool) {
[38, 44, 50, 58, 65, 71, 77, 83]
File: smart-contracts/NextGenCore.sol
130: function createCollection(string memory _collectionName, string memory _collectionArtist, string memory _collectionDescription, string memory _collectionWebsite, string memory _collectionLicense, string memory _collectionBaseURI, string memory _collectionLibrary, string[] memory _collectionScript) public FunctionAdminRequired(this.createCollection.selector) {
147: function setCollectionData(uint256 _collectionID, address _collectionArtistAddress, uint256 _maxCollectionPurchases, uint256 _collectionTotalSupply, uint _setFinalSupplyTimeAfterMint) public CollectionAdminRequired(_collectionID, this.setCollectionData.selector) {
170: function addRandomizer(uint256 _collectionID, address _randomizerContract) public FunctionAdminRequired(this.addRandomizer.selector) {
178: function airDropTokens(uint256 mintIndex, address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID) external {
189: function mint(uint256 mintIndex, address _mintingAddress , address _mintTo, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint256 phase) external {
204: function burn(uint256 _collectionID, uint256 _tokenId) public {
213: function burnToMint(uint256 mintIndex, uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, uint256 _saltfun_o, address burner) external {
227: function _mintProcessing(uint256 _mintIndex, address _recipient, string memory _tokenData, uint256 _collectionID, uint256 _saltfun_o) internal {
238: function updateCollectionInfo(uint256 _collectionID, string memory _newCollectionName, string memory _newCollectionArtist, string memory _newCollectionDescription, string memory _newCollectionWebsite, string memory _newCollectionLicense, string memory _newCollectionBaseURI, string memory _newCollectionLibrary, uint256 _index, string[] memory _newCollectionScript) public CollectionAdminRequired(_collectionID, this.updateCollectionInfo.selector) {
257: function artistSignature(uint256 _collectionID, string memory _signature) public {
266: function changeMetadataView(uint256 _collectionID, bool _status) public CollectionAdminRequired(_collectionID, this.changeMetadataView.selector) {
273: function changeTokenData(uint256 _tokenId, string memory newData) public FunctionAdminRequired(this.changeTokenData.selector) {
281: function updateImagesAndAttributes(uint256[] memory _tokenId, string[] memory _images, string[] memory _attributes) public FunctionAdminRequired(this.updateImagesAndAttributes.selector) {
292: function freezeCollection(uint256 _collectionID) public FunctionAdminRequired(this.freezeCollection.selector) {
299: function setTokenHash(uint256 _collectionID, uint256 _mintIndex, bytes32 _hash) external {
307: function setFinalSupply(uint256 _collectionID) public FunctionAdminRequired(this.setFinalSupply.selector) {
315: function addMinterContract(address _minterContract) public FunctionAdminRequired(this.addMinterContract.selector) {
322: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
329: function setDefaultRoyalties(address _royaltyAddress, uint96 _bps) public FunctionAdminRequired(this.setDefaultRoyalties.selector) {
337: function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721Enumerable, ERC2981) returns (bool) {
343: function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
361: function getTokenName(uint256 tokenId) private view returns(string memory) {
367: function collectionFreezeStatus(uint256 _collectionID) public view returns(bool){
372: function viewColIDforTokenID(uint256 _tokenid) public view returns (uint256) {
377: function retrievewereDataAdded(uint256 _collectionID) external view returns(bool){
383: function viewTokensIndexMin(uint256 _collectionID) external view returns (uint256) {
389: function viewTokensIndexMax(uint256 _collectionID) external view returns (uint256) {
394: function viewCirSupply(uint256 _collectionID) external view returns (uint256) {
399: function viewMaxAllowance(uint256 _collectionID) external view returns (uint256) {
404: function retrieveTokensMintedALPerAddress(uint256 _collectionID, address _address) external view returns(uint256) {
409: function retrieveTokensMintedPublicPerAddress(uint256 _collectionID, address _address) external view returns(uint256) {
415: function retrieveTokensAirdroppedPerAddress(uint256 _collectionID, address _address) public view returns(uint256) {
420: function retrieveArtistAddress(uint256 _collectionID) external view returns(address) {
426: function retrieveCollectionInfo(uint256 _collectionID) public view returns(string memory, string memory, string memory, string memory, string memory, string memory){
432: function retrieveCollectionLibraryAndScript(uint256 _collectionID) public view returns(string memory, string[] memory){
438: function retrieveCollectionAdditionalData(uint256 _collectionID) public view returns(address, uint256, uint256, uint256, uint, address){
444: function retrieveTokenHash(uint256 _tokenid) public view returns(bytes32){
450: function retrieveGenerativeScript(uint256 tokenId) public view returns(string memory){
461: function totalSupplyOfCollection(uint256 _collectionID) public view returns (uint256) {
467: function retrievetokenImageAndAttributes(uint256 _tokenId) public view returns(string memory, string memory) {
[130, 147, 170, 178, 189, 204, 213, 227, 238, 257, 266, 273, 281, 292, 299, 307, 315, 322, 329, 337, 343, 361, 367, 372, 377, 383, 389, 394, 399, 404, 409, 415, 420, 426, 432, 438, 444, 450, 461, 467]
File: smart-contracts/RandomizerNXT.sol
41: function updateRandomsContract(address _randoms) public FunctionAdminRequired(this.updateRandomsContract.selector) {
45: function updateAdminsContract(address _admin) public FunctionAdminRequired(this.updateAdminsContract.selector) {
49: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
55: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
62: function isRandomizerContract() external view returns (bool) {
File: smart-contracts/RandomizerRNG.sol
40: function requestRandomWords(uint256 tokenid, uint256 _ethRequired) public payable {
48: function fulfillRandomWords(uint256 id, uint256[] memory numbers) internal override {
53: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
61: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
66: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
73: function updateRNGCost(uint256 _ethRequired) public FunctionAdminRequired(this.updateRNGCost.selector) {
79: function emergencyWithdraw() public FunctionAdminRequired(this.emergencyWithdraw.selector) {
86: receive() external payable {}
89: function isRandomizerContract() external view returns (bool) {
[40, 48, 53, 61, 66, 73, 79, 86, 89]
File: smart-contracts/RandomizerVRF.sol
52: function requestRandomWords(uint256 tokenid) public {
65: function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override {
71: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
79: function updatecallbackGasLimitAndkeyHash(uint32 _callbackGasLimit, bytes32 _keyHash) public FunctionAdminRequired(this.updatecallbackGasLimitAndkeyHash.selector){
86: function updateAdditionalData(uint64 _s_subscriptionId, uint32 _numWords, uint16 _requestConfirmations) public FunctionAdminRequired(this.updateAdditionalData.selector){
94: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
99: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
105: function isRandomizerContract() external view returns (bool) {
[52, 65, 71, 79, 86, 94, 99, 105]
File: smart-contracts/XRandoms.sol
15: function getWord(uint256 id) private pure returns (string memory) {
35: function randomNumber() public view returns (uint256){
40: function randomWord() public view returns (string memory) {
45: function returnIndex(uint256 id) public view returns (string memory) {
Some functions have an incomplete NatSpec: add a @param
notation to describe the function parameters to improve the code documentation.
There are 110 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
// @audit missing _tokenid
57: function participateToAuction(uint256 _tokenid) public payable {
// @audit missing _tokenid
65: function returnHighestBid(uint256 _tokenid) public view returns (uint256) {
// @audit missing _tokenid
87: function returnHighestBidder(uint256 _tokenid) public view returns (address) {
// @audit missing _tokenid
104: function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){
// @audit missing _tokenid, index
124: function cancelBid(uint256 _tokenid, uint256 index) public {
// @audit missing _tokenid
134: function cancelAllBids(uint256 _tokenid) public {
// @audit missing _tokenid
147: function returnBids(uint256 _tokenid) public view returns(auctionInfoStru[] memory) {
[57, 65, 87, 104, 124, 134, 147]
File: smart-contracts/MinterContract.sol
// @audit missing _collectionID, _collectionMintCost, _collectionEndMintCost, _rate, _timePeriod, _salesOption, _delAddress
157: function setCollectionCosts(uint256 _collectionID, uint256 _collectionMintCost, uint256 _collectionEndMintCost, uint256 _rate, uint256 _timePeriod, uint8 _salesOption, address _delAddress) public CollectionAdminRequired(_collectionID, this.setCollectionCosts.selector) {
// @audit missing _collectionID, _allowlistStartTime, _allowlistEndTime, _publicStartTime, _publicEndTime, _merkleRoot
170: function setCollectionPhases(uint256 _collectionID, uint _allowlistStartTime, uint _allowlistEndTime, uint _publicStartTime, uint _publicEndTime, bytes32 _merkleRoot) public CollectionAdminRequired(_collectionID, this.setCollectionPhases.selector) {
// @audit missing _recipients, _tokenData, _saltfun_o, _collectionID, _numberOfTokens
181: function airDropTokens(address[] memory _recipients, string[] memory _tokenData, uint256[] memory _saltfun_o, uint256 _collectionID, uint256[] memory _numberOfTokens) public FunctionAdminRequired(this.airDropTokens.selector) {
// @audit missing _collectionID, _numberOfTokens, _maxAllowance, _tokenData, _mintTo, merkleProof, _delegator, _saltfun_o
196: function mint(uint256 _collectionID, uint256 _numberOfTokens, uint256 _maxAllowance, string memory _tokenData, address _mintTo, bytes32[] calldata merkleProof, address _delegator, uint256 _saltfun_o) public payable {
// @audit missing _burnCollectionID, _tokenId, _mintCollectionID, _saltfun_o
258: function burnToMint(uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, uint256 _saltfun_o) public payable {
// @audit missing _recipient, _tokenData, _saltfun_o, _collectionID, _auctionEndTime
276: function mintAndAuction(address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint _auctionEndTime) public FunctionAdminRequired(this.mintAndAuction.selector) {
// @audit missing _collectionID, _collectionAddress
302: function updateDelegationCollection(uint256 _collectionID, address _collectionAddress) public FunctionAdminRequired(this.updateDelegationCollection.selector) {
// @audit missing _burnCollectionID, _mintCollectionID, _status
308: function initializeBurn(uint256 _burnCollectionID, uint256 _mintCollectionID, bool _status) public FunctionAdminRequired(this.initializeBurn.selector) {
// @audit missing _erc721Collection, _burnCollectionID, _mintCollectionID, _tokmin, _tokmax, _burnOrSwapAddress, _status
315: function initializeExternalBurnOrSwap(address _erc721Collection, uint256 _burnCollectionID, uint256 _mintCollectionID, uint256 _tokmin, uint256 _tokmax, address _burnOrSwapAddress, bool _status) public FunctionAdminRequired(this.initializeExternalBurnOrSwap.selector) {
// @audit missing _erc721Collection, _burnCollectionID, _tokenId, _mintCollectionID, _tokenData, merkleProof, _saltfun_o
326: function burnOrSwapExternalToMint(address _erc721Collection, uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, string memory _tokenData, bytes32[] calldata merkleProof, uint256 _saltfun_o) public payable {
// @audit missing _collectionID, _artistPrSplit, _teamPrSplit, _artistSecSplit, _teamSecSplit
369: function setPrimaryAndSecondarySplits(uint256 _collectionID, uint256 _artistPrSplit, uint256 _teamPrSplit, uint256 _artistSecSplit, uint256 _teamSecSplit) public FunctionAdminRequired(this.setPrimaryAndSecondarySplits.selector) {
// @audit missing _collectionID, _primaryAdd1, _primaryAdd2, _primaryAdd3, _add1Percentage, _add2Percentage, _add3Percentage
380: function proposePrimaryAddressesAndPercentages(uint256 _collectionID, address _primaryAdd1, address _primaryAdd2, address _primaryAdd3, uint256 _add1Percentage, uint256 _add2Percentage, uint256 _add3Percentage) public ArtistOrAdminRequired(_collectionID, this.proposePrimaryAddressesAndPercentages.selector) {
// @audit missing _collectionID, _secondaryAdd1, _secondaryAdd2, _secondaryAdd3, _add1Percentage, _add2Percentage, _add3Percentage
394: function proposeSecondaryAddressesAndPercentages(uint256 _collectionID, address _secondaryAdd1, address _secondaryAdd2, address _secondaryAdd3, uint256 _add1Percentage, uint256 _add2Percentage, uint256 _add3Percentage) public ArtistOrAdminRequired(_collectionID, this.proposeSecondaryAddressesAndPercentages.selector) {
// @audit missing _collectionID, _statusPrimary, _statusSecondary
408: function acceptAddressesAndPercentages(uint256 _collectionID, bool _statusPrimary, bool _statusSecondary) public FunctionAdminRequired(this.acceptAddressesAndPercentages.selector) {
// @audit missing _collectionID, _team1, _team2, _teamperc1, _teamperc2
415: function payArtist(uint256 _collectionID, address _team1, address _team2, uint256 _teamperc1, uint256 _teamperc2) public FunctionAdminRequired(this.payArtist.selector) {
// @audit missing _gencore
448: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
// @audit missing _newadminsContract
454: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
461: function emergencyWithdraw() public FunctionAdminRequired(this.emergencyWithdraw.selector) {
// @audit missing _collectionID
470: function retrievePrimarySplits(uint256 _collectionID) public view returns(uint256, uint256){
// @audit missing _collectionID
476: function retrievePrimaryAddressesAndPercentages(uint256 _collectionID) public view returns(address, address, address, uint256, uint256, uint256, bool){
// @audit missing _collectionID
482: function retrieveSecondarySplits(uint256 _collectionID) public view returns(uint256, uint256){
// @audit missing _collectionID
488: function retrieveSecondaryAddressesAndPercentages(uint256 _collectionID) public view returns(address, address, address, uint256, uint256, uint256, bool){
// @audit missing _collectionID
494: function retrieveCollectionPhases(uint256 _collectionID) public view returns(uint, uint, bytes32, uint, uint){
// @audit missing _collectionID
500: function retrieveCollectionMintingDetails(uint256 _collectionID) public view returns(uint256, uint256, uint256, uint256, uint8, address){
506: function isMinterContract() external view returns (bool) {
// @audit missing _collectionID
512: function getEndTime(uint256 _collectionID) external view returns (uint) {
// @audit missing _tokenId
518: function getAuctionEndTime(uint256 _tokenId) external view returns (uint) {
// @audit missing _tokenId
524: function getAuctionStatus(uint256 _tokenId) external view returns (bool) {
// @audit missing _collectionId
530: function getPrice(uint256 _collectionId) public view returns (uint256) {
[157, 170, 181, 196, 258, 276, 302, 308, 315, 326, 369, 380, 394, 408, 415, 448, 454, 461, 470, 476, 482, 488, 494, 500, 506, 512, 518, 524, 530]
File: smart-contracts/NextGenAdmins.sol
// @audit missing _admin, _status
38: function registerAdmin(address _admin, bool _status) public onlyOwner {
// @audit missing _address, _selector, _status
44: function registerFunctionAdmin(address _address, bytes4 _selector, bool _status) public AdminRequired {
// @audit missing _address, _selector, _status
50: function registerBatchFunctionAdmin(address _address, bytes4[] memory _selector, bool _status) public AdminRequired {
// @audit missing _collectionID, _address, _status
58: function registerCollectionAdmin(uint256 _collectionID, address _address, bool _status) public AdminRequired {
// @audit missing _address
65: function retrieveGlobalAdmin(address _address) public view returns(bool) {
// @audit missing _address, _selector
71: function retrieveFunctionAdmin(address _address, bytes4 _selector) public view returns(bool) {
// @audit missing _address, _collectionID
77: function retrieveCollectionAdmin(address _address, uint256 _collectionID) public view returns(bool) {
83: function isAdminContract() external view returns (bool) {
[38, 44, 50, 58, 65, 71, 77, 83]
File: smart-contracts/NextGenCore.sol
// @audit missing _collectionName, _collectionArtist, _collectionDescription, _collectionWebsite, _collectionLicense, _collectionBaseURI, _collectionLibrary, _collectionScript
130: function createCollection(string memory _collectionName, string memory _collectionArtist, string memory _collectionDescription, string memory _collectionWebsite, string memory _collectionLicense, string memory _collectionBaseURI, string memory _collectionLibrary, string[] memory _collectionScript) public FunctionAdminRequired(this.createCollection.selector) {
// @audit missing _collectionID, _collectionArtistAddress, _maxCollectionPurchases, _collectionTotalSupply, _setFinalSupplyTimeAfterMint
147: function setCollectionData(uint256 _collectionID, address _collectionArtistAddress, uint256 _maxCollectionPurchases, uint256 _collectionTotalSupply, uint _setFinalSupplyTimeAfterMint) public CollectionAdminRequired(_collectionID, this.setCollectionData.selector) {
// @audit missing _collectionID, _randomizerContract
170: function addRandomizer(uint256 _collectionID, address _randomizerContract) public FunctionAdminRequired(this.addRandomizer.selector) {
// @audit missing mintIndex, _recipient, _tokenData, _saltfun_o, _collectionID
178: function airDropTokens(uint256 mintIndex, address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID) external {
// @audit missing mintIndex, _mintingAddress, _mintTo, _tokenData, _saltfun_o, _collectionID, phase
189: function mint(uint256 mintIndex, address _mintingAddress , address _mintTo, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint256 phase) external {
// @audit missing _collectionID, _tokenId
204: function burn(uint256 _collectionID, uint256 _tokenId) public {
// @audit missing mintIndex, _burnCollectionID, _tokenId, _mintCollectionID, _saltfun_o, burner
213: function burnToMint(uint256 mintIndex, uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, uint256 _saltfun_o, address burner) external {
// @audit missing _mintIndex, _recipient, _tokenData, _collectionID, _saltfun_o
227: function _mintProcessing(uint256 _mintIndex, address _recipient, string memory _tokenData, uint256 _collectionID, uint256 _saltfun_o) internal {
// @audit missing _collectionID, _newCollectionName, _newCollectionArtist, _newCollectionDescription, _newCollectionWebsite, _newCollectionLicense, _newCollectionBaseURI, _newCollectionLibrary, _index, _newCollectionScript
238: function updateCollectionInfo(uint256 _collectionID, string memory _newCollectionName, string memory _newCollectionArtist, string memory _newCollectionDescription, string memory _newCollectionWebsite, string memory _newCollectionLicense, string memory _newCollectionBaseURI, string memory _newCollectionLibrary, uint256 _index, string[] memory _newCollectionScript) public CollectionAdminRequired(_collectionID, this.updateCollectionInfo.selector) {
// @audit missing _collectionID, _signature
257: function artistSignature(uint256 _collectionID, string memory _signature) public {
// @audit missing _collectionID, _status
266: function changeMetadataView(uint256 _collectionID, bool _status) public CollectionAdminRequired(_collectionID, this.changeMetadataView.selector) {
// @audit missing _tokenId, newData
273: function changeTokenData(uint256 _tokenId, string memory newData) public FunctionAdminRequired(this.changeTokenData.selector) {
// @audit missing _tokenId, _images, _attributes
281: function updateImagesAndAttributes(uint256[] memory _tokenId, string[] memory _images, string[] memory _attributes) public FunctionAdminRequired(this.updateImagesAndAttributes.selector) {
// @audit missing _collectionID
292: function freezeCollection(uint256 _collectionID) public FunctionAdminRequired(this.freezeCollection.selector) {
// @audit missing _collectionID, _mintIndex, _hash
299: function setTokenHash(uint256 _collectionID, uint256 _mintIndex, bytes32 _hash) external {
// @audit missing _collectionID
307: function setFinalSupply(uint256 _collectionID) public FunctionAdminRequired(this.setFinalSupply.selector) {
// @audit missing _minterContract
315: function addMinterContract(address _minterContract) public FunctionAdminRequired(this.addMinterContract.selector) {
// @audit missing _newadminsContract
322: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
// @audit missing _royaltyAddress, _bps
329: function setDefaultRoyalties(address _royaltyAddress, uint96 _bps) public FunctionAdminRequired(this.setDefaultRoyalties.selector) {
// @audit missing interfaceId
337: function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721Enumerable, ERC2981) returns (bool) {
// @audit missing tokenId
343: function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
// @audit missing tokenId
361: function getTokenName(uint256 tokenId) private view returns(string memory) {
// @audit missing _collectionID
367: function collectionFreezeStatus(uint256 _collectionID) public view returns(bool){
// @audit missing _tokenid
372: function viewColIDforTokenID(uint256 _tokenid) public view returns (uint256) {
// @audit missing _collectionID
377: function retrievewereDataAdded(uint256 _collectionID) external view returns(bool){
// @audit missing _collectionID
383: function viewTokensIndexMin(uint256 _collectionID) external view returns (uint256) {
// @audit missing _collectionID
389: function viewTokensIndexMax(uint256 _collectionID) external view returns (uint256) {
// @audit missing _collectionID
394: function viewCirSupply(uint256 _collectionID) external view returns (uint256) {
// @audit missing _collectionID
399: function viewMaxAllowance(uint256 _collectionID) external view returns (uint256) {
// @audit missing _collectionID, _address
404: function retrieveTokensMintedALPerAddress(uint256 _collectionID, address _address) external view returns(uint256) {
// @audit missing _collectionID, _address
409: function retrieveTokensMintedPublicPerAddress(uint256 _collectionID, address _address) external view returns(uint256) {
// @audit missing _collectionID, _address
415: function retrieveTokensAirdroppedPerAddress(uint256 _collectionID, address _address) public view returns(uint256) {
// @audit missing _collectionID
420: function retrieveArtistAddress(uint256 _collectionID) external view returns(address) {
// @audit missing _collectionID
426: function retrieveCollectionInfo(uint256 _collectionID) public view returns(string memory, string memory, string memory, string memory, string memory, string memory){
// @audit missing _collectionID
432: function retrieveCollectionLibraryAndScript(uint256 _collectionID) public view returns(string memory, string[] memory){
// @audit missing _collectionID
438: function retrieveCollectionAdditionalData(uint256 _collectionID) public view returns(address, uint256, uint256, uint256, uint, address){
// @audit missing _tokenid
444: function retrieveTokenHash(uint256 _tokenid) public view returns(bytes32){
// @audit missing tokenId
450: function retrieveGenerativeScript(uint256 tokenId) public view returns(string memory){
// @audit missing _collectionID
461: function totalSupplyOfCollection(uint256 _collectionID) public view returns (uint256) {
// @audit missing _tokenId
467: function retrievetokenImageAndAttributes(uint256 _tokenId) public view returns(string memory, string memory) {
[130, 147, 170, 178, 189, 204, 213, 227, 238, 257, 266, 273, 281, 292, 299, 307, 315, 322, 329, 337, 343, 361, 367, 372, 377, 383, 389, 394, 399, 404, 409, 415, 420, 426, 432, 438, 444, 450, 461, 467]
File: smart-contracts/RandomizerNXT.sol
// @audit missing _randoms
41: function updateRandomsContract(address _randoms) public FunctionAdminRequired(this.updateRandomsContract.selector) {
// @audit missing _admin
45: function updateAdminsContract(address _admin) public FunctionAdminRequired(this.updateAdminsContract.selector) {
// @audit missing _gencore
49: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
// @audit missing _collectionID, _mintIndex, _saltfun_o
55: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
62: function isRandomizerContract() external view returns (bool) {
File: smart-contracts/RandomizerRNG.sol
// @audit missing tokenid, _ethRequired
40: function requestRandomWords(uint256 tokenid, uint256 _ethRequired) public payable {
// @audit missing id, numbers
48: function fulfillRandomWords(uint256 id, uint256[] memory numbers) internal override {
// @audit missing _collectionID, _mintIndex, _saltfun_o
53: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
// @audit missing _newadminsContract
61: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
// @audit missing _gencore
66: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
// @audit missing _ethRequired
73: function updateRNGCost(uint256 _ethRequired) public FunctionAdminRequired(this.updateRNGCost.selector) {
79: function emergencyWithdraw() public FunctionAdminRequired(this.emergencyWithdraw.selector) {
86: receive() external payable {}
89: function isRandomizerContract() external view returns (bool) {
[40, 48, 53, 61, 66, 73, 79, 86, 89]
File: smart-contracts/RandomizerVRF.sol
// @audit missing tokenid
52: function requestRandomWords(uint256 tokenid) public {
// @audit missing _requestId, _randomWords
65: function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override {
// @audit missing _collectionID, _mintIndex, _saltfun_o
71: function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
// @audit missing _callbackGasLimit, _keyHash
79: function updatecallbackGasLimitAndkeyHash(uint32 _callbackGasLimit, bytes32 _keyHash) public FunctionAdminRequired(this.updatecallbackGasLimitAndkeyHash.selector){
// @audit missing _s_subscriptionId, _numWords, _requestConfirmations
86: function updateAdditionalData(uint64 _s_subscriptionId, uint32 _numWords, uint16 _requestConfirmations) public FunctionAdminRequired(this.updateAdditionalData.selector){
// @audit missing _newadminsContract
94: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
// @audit missing _gencore
99: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
105: function isRandomizerContract() external view returns (bool) {
[52, 65, 71, 79, 86, 94, 99, 105]
File: smart-contracts/XRandoms.sol
// @audit missing id
15: function getWord(uint256 id) private pure returns (string memory) {
35: function randomNumber() public view returns (uint256){
40: function randomWord() public view returns (string memory) {
// @audit missing id
45: function returnIndex(uint256 id) public view returns (string memory) {
Some functions have an incomplete NatSpec: add a @return
notation to describe the function return value to improve the code documentation.
There are 46 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
65: function returnHighestBid(uint256 _tokenid) public view returns (uint256) {
87: function returnHighestBidder(uint256 _tokenid) public view returns (address) {
147: function returnBids(uint256 _tokenid) public view returns(auctionInfoStru[] memory) {
File: smart-contracts/MinterContract.sol
470: function retrievePrimarySplits(uint256 _collectionID) public view returns(uint256, uint256){
476: function retrievePrimaryAddressesAndPercentages(uint256 _collectionID) public view returns(address, address, address, uint256, uint256, uint256, bool){
482: function retrieveSecondarySplits(uint256 _collectionID) public view returns(uint256, uint256){
488: function retrieveSecondaryAddressesAndPercentages(uint256 _collectionID) public view returns(address, address, address, uint256, uint256, uint256, bool){
494: function retrieveCollectionPhases(uint256 _collectionID) public view returns(uint, uint, bytes32, uint, uint){
500: function retrieveCollectionMintingDetails(uint256 _collectionID) public view returns(uint256, uint256, uint256, uint256, uint8, address){
506: function isMinterContract() external view returns (bool) {
512: function getEndTime(uint256 _collectionID) external view returns (uint) {
518: function getAuctionEndTime(uint256 _tokenId) external view returns (uint) {
524: function getAuctionStatus(uint256 _tokenId) external view returns (bool) {
530: function getPrice(uint256 _collectionId) public view returns (uint256) {
[470, 476, 482, 488, 494, 500, 506, 512, 518, 524, 530]
File: smart-contracts/NextGenAdmins.sol
65: function retrieveGlobalAdmin(address _address) public view returns(bool) {
71: function retrieveFunctionAdmin(address _address, bytes4 _selector) public view returns(bool) {
77: function retrieveCollectionAdmin(address _address, uint256 _collectionID) public view returns(bool) {
83: function isAdminContract() external view returns (bool) {
File: smart-contracts/NextGenCore.sol
337: function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721Enumerable, ERC2981) returns (bool) {
343: function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
361: function getTokenName(uint256 tokenId) private view returns(string memory) {
367: function collectionFreezeStatus(uint256 _collectionID) public view returns(bool){
372: function viewColIDforTokenID(uint256 _tokenid) public view returns (uint256) {
377: function retrievewereDataAdded(uint256 _collectionID) external view returns(bool){
383: function viewTokensIndexMin(uint256 _collectionID) external view returns (uint256) {
389: function viewTokensIndexMax(uint256 _collectionID) external view returns (uint256) {
394: function viewCirSupply(uint256 _collectionID) external view returns (uint256) {
399: function viewMaxAllowance(uint256 _collectionID) external view returns (uint256) {
404: function retrieveTokensMintedALPerAddress(uint256 _collectionID, address _address) external view returns(uint256) {
409: function retrieveTokensMintedPublicPerAddress(uint256 _collectionID, address _address) external view returns(uint256) {
415: function retrieveTokensAirdroppedPerAddress(uint256 _collectionID, address _address) public view returns(uint256) {
420: function retrieveArtistAddress(uint256 _collectionID) external view returns(address) {
426: function retrieveCollectionInfo(uint256 _collectionID) public view returns(string memory, string memory, string memory, string memory, string memory, string memory){
432: function retrieveCollectionLibraryAndScript(uint256 _collectionID) public view returns(string memory, string[] memory){
438: function retrieveCollectionAdditionalData(uint256 _collectionID) public view returns(address, uint256, uint256, uint256, uint, address){
444: function retrieveTokenHash(uint256 _tokenid) public view returns(bytes32){
450: function retrieveGenerativeScript(uint256 tokenId) public view returns(string memory){
461: function totalSupplyOfCollection(uint256 _collectionID) public view returns (uint256) {
467: function retrievetokenImageAndAttributes(uint256 _tokenId) public view returns(string memory, string memory) {
[337, 343, 361, 367, 372, 377, 383, 389, 394, 399, 404, 409, 415, 420, 426, 432, 438, 444, 450, 461, 467]
File: smart-contracts/RandomizerNXT.sol
62: function isRandomizerContract() external view returns (bool) {
[62]
File: smart-contracts/RandomizerRNG.sol
89: function isRandomizerContract() external view returns (bool) {
[89]
File: smart-contracts/RandomizerVRF.sol
105: function isRandomizerContract() external view returns (bool) {
[105]
File: smart-contracts/XRandoms.sol
15: function getWord(uint256 id) private pure returns (string memory) {
35: function randomNumber() public view returns (uint256){
40: function randomWord() public view returns (string memory) {
45: function returnIndex(uint256 id) public view returns (string memory) {
Each slot saved can avoid an extra Gsset (20000 gas). Reads and writes (if two variables that occupy the same slot are written by the same function) will have a cheaper gas consumption.
There is 1 instance of this issue.
File: smart-contracts/RandomizerVRF.sol
// @audit Can save 1 storage slot (from 9 to 8)
// @audit Consider using the following order:
/*
* bytes32 keyHash (32)
* mapping(uint256 => uint256) tokenIdToCollection (32)
* mapping(uint256 => uint256) tokenToRequest (32)
* mapping(uint256 => uint256) requestToToken (32)
* VRFCoordinatorV2Interface COORDINATOR (20)
* uint64 s_subscriptionId (8)
* uint32 callbackGasLimit (4)
* address gencore (20)
* uint32 numWords (4)
* uint16 requestConfirmations (2)
* INextGenCore gencoreContract (20)
* INextGenAdmins adminsContract (20)
*/
19: contract NextGenRandomizerVRF is VRFConsumerBaseV2, Ownable {
[19]
Each slot saved can avoid an extra Gsset (20000 gas) for the first setting of the struct. Subsequent reads as well as writes have smaller gas savings.
There are 3 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
// @audit Can save 1 storage slot (from 3 to 2)
// @audit Consider using the following order:
/*
* uint256 bid (32)
* address bidder (20)
* bool status (1)
*/
43: struct auctionInfoStru {
44: address bidder;
45: uint256 bid;
46: bool status;
47: }
[43-47]
File: smart-contracts/MinterContract.sol
// @audit Can save 1 storage slot (from 7 to 6)
// @audit Consider using the following order:
/*
* uint256 add1Percentage (32)
* uint256 add2Percentage (32)
* uint256 add3Percentage (32)
* address primaryAdd1 (20)
* bool status (1)
* address primaryAdd2 (20)
* address primaryAdd3 (20)
*/
73: struct collectionPrimaryAddresses {
74: address primaryAdd1;
75: address primaryAdd2;
76: address primaryAdd3;
77: uint256 add1Percentage;
78: uint256 add2Percentage;
79: uint256 add3Percentage;
80: bool status;
81: }
// @audit Can save 1 storage slot (from 7 to 6)
// @audit Consider using the following order:
/*
* uint256 add1Percentage (32)
* uint256 add2Percentage (32)
* uint256 add3Percentage (32)
* address secondaryAdd1 (20)
* bool status (1)
* address secondaryAdd2 (20)
* address secondaryAdd3 (20)
*/
98: struct collectionSecondaryAddresses {
99: address secondaryAdd1;
100: address secondaryAdd2;
101: address secondaryAdd3;
102: uint256 add1Percentage;
103: uint256 add2Percentage;
104: uint256 add3Percentage;
105: bool status;
106: }
Some member types can be safely modified, and as result, these struct
will fit in fewer storage slots. Each slot saved can avoid an extra Gsset (20000 gas) for the first setting of the struct. Subsequent reads as well as writes have smaller gas savings.
There is 1 instance of this issue.
File: smart-contracts/MinterContract.sol
// @audit Supposing an already optimal order, this can save 1 storage slot (from 7 to 6) by modifying the following variables:
// @audit uint allowlistStartTime -> uint32 allowlistStartTime
// @audit Consider using the following order:
/*
* bytes32 merkleRoot (32)
* uint256 collectionMintCost (32)
* uint256 collectionEndMintCost (32)
* uint256 rate (32)
* address delAddress (20)
* uint32 allowlistStartTime (4)
* uint32 allowlistEndTime (4)
* uint32 publicStartTime (4)
* uint32 publicEndTime (4)
* uint32 timePeriod (4)
* uint8 salesOption (1)
*/
44: struct collectionPhasesDataStructure {
45: uint allowlistStartTime;
46: uint allowlistEndTime;
47: uint publicStartTime;
48: uint publicEndTime;
49: bytes32 merkleRoot;
50: uint256 collectionMintCost;
51: uint256 collectionEndMintCost;
52: uint256 timePeriod;
53: uint256 rate;
54: uint8 salesOption;
55: address delAddress;
56: }
[44-56]
This can avoid a Gsset (20000 Gas) per mapping combined. Reads and writes will also be cheaper when a function requires both values as they both can fit in the same storage slot.
Finally, if both fields are accessed in the same function, this can save ~42 gas per access due to not having to recalculate the key's keccak256
hash (Gkeccak256 - 30 Gas) and that calculation's associated stack operations.
There are 12 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
// @audit consider merging auctionInfoData, auctionClaim
50: mapping (uint256 => auctionInfoStru[]) public auctionInfoData;
53: mapping (uint256 => bool) public auctionClaim;
[50]
File: smart-contracts/MinterContract.sol
// @audit consider merging collectionTotalAmount, burnToMintCollections, collectionPhases
23: mapping (uint256 => uint256) public collectionTotalAmount;
35: mapping (uint256 => mapping (uint256 => bool)) public burnToMintCollections;
59: mapping (uint256 => collectionPhasesDataStructure) private collectionPhases;
// @audit consider merging burnOrSwapAddress, burnOrSwapIds
29: mapping (bytes32 => address) public burnOrSwapAddress;
32: mapping (bytes32 => uint256[2]) private burnOrSwapIds;
// @audit consider merging collectionRoyaltiesPrimarySplits, collectionArtistPrimaryAddresses, collectionRoyaltiesSecondarySplits, collectionArtistSecondaryAddresses
70: mapping (uint256 => royaltiesPrimarySplits) private collectionRoyaltiesPrimarySplits;
84: mapping (uint256 => collectionPrimaryAddresses) private collectionArtistPrimaryAddresses;
95: mapping (uint256 => royaltiesSecondarySplits) private collectionRoyaltiesSecondarySplits;
109: mapping (uint256 => collectionSecondaryAddresses) private collectionArtistSecondaryAddresses;
// @audit consider merging mintToAuctionData, mintToAuctionStatus
112: mapping (uint256 => uint) private mintToAuctionData;
115: mapping (uint256 => bool) private mintToAuctionStatus;
File: smart-contracts/NextGenAdmins.sol
// @audit consider merging collectionAdmin, functionAdmin
21: mapping (address => mapping (uint256 => bool)) private collectionAdmin;
24: mapping (address => mapping (bytes4 => bool)) private functionAdmin;
[21]
File: smart-contracts/NextGenCore.sol
// @audit consider merging collectionInfo, collectionAdditionalData, isCollectionCreated, tokenIdsToCollectionIds, collectionFreeze
41: mapping (uint256 => collectionInfoStructure) private collectionInfo;
57: mapping (uint256 => collectionAdditonalDataStructure) private collectionAdditionalData;
62: mapping (uint256 => bool) private isCollectionCreated;
68: mapping (uint256 => uint256) private tokenIdsToCollectionIds;
98: mapping (uint256 => bool) private collectionFreeze;
// @audit consider merging tokensMintedPerAddress, tokensMintedAllowlistAddress, tokensAirdropPerAddress
74: mapping (uint256 => mapping (address => uint256)) private tokensMintedPerAddress;
77: mapping (uint256 => mapping (address => uint256)) private tokensMintedAllowlistAddress;
80: mapping (uint256 => mapping (address => uint256)) private tokensAirdropPerAddress;
// @audit consider merging artistsSignatures, artistSigned
89: mapping (uint256 => string) public artistsSignatures;
101: mapping (uint256 => bool) public artistSigned;
// @audit consider merging tokenData, tokenImageAndAttributes
92: mapping (uint256 => string) public tokenData;
95: mapping (uint256 => string[2]) private tokenImageAndAttributes;
File: smart-contracts/RandomizerRNG.sol
// @audit consider merging requestToToken, tokenToRequest
20: mapping(uint256 => uint256) public requestToToken;
26: mapping(uint256 => uint256) public tokenToRequest;
[20]
File: smart-contracts/RandomizerVRF.sol
// @audit consider merging tokenToRequest, requestToToken
32: mapping(uint256 => uint256) public tokenToRequest;
33: mapping(uint256 => uint256) public requestToToken;
[32]
State variable reads and writes are more expensive than local variable reads and writes. Therefore, it is recommended to replace state variable reads and writes within loops with a local variable. Gas savings should be multiplied by the average loop length.
There are 9 instances of this issue.
File: smart-contracts/MinterContract.sol
// @audit gencore
185: collectionTokenMintIndex = gencore.viewTokensIndexMin(_collectionID) + gencore.viewCirSupply(_collectionID) + _numberOfTokens[y] - 1;
// @audit gencore
185: collectionTokenMintIndex = gencore.viewTokensIndexMin(_collectionID) + gencore.viewCirSupply(_collectionID) + _numberOfTokens[y] - 1;
// @audit gencore
186: require(collectionTokenMintIndex <= gencore.viewTokensIndexMax(_collectionID), "No supply");
// @audit gencore
188: uint256 mintIndex = gencore.viewTokensIndexMin(_collectionID) + gencore.viewCirSupply(_collectionID);
// @audit gencore
188: uint256 mintIndex = gencore.viewTokensIndexMin(_collectionID) + gencore.viewCirSupply(_collectionID);
// @audit gencore
189: gencore.airDropTokens(mintIndex, _recipients[y], _tokenData[y], _saltfun_o[y], _collectionID);
// @audit gencore
235: uint256 mintIndex = gencore.viewTokensIndexMin(col) + gencore.viewCirSupply(col);
// @audit gencore
235: uint256 mintIndex = gencore.viewTokensIndexMin(col) + gencore.viewCirSupply(col);
// @audit gencore
236: gencore.mint(mintIndex, mintingAddress, _mintTo, tokData, _saltfun_o, col, phase);
[185, 185, 186, 188, 188, 189, 235, 235, 236]
Accessing state variables within a function involves an SLOAD operation, but immutable
variables can be accessed directly without the need of it, thus reducing gas costs. As these state variables are assigned only in the constructor, consider declaring them immutable
.
There are 5 instances of this issue.
File: smart-contracts/AuctionDemo.sol
26: IMinterContract public minter;
28: address gencore;
27: INextGenAdmins public adminsContract;
File: smart-contracts/MinterContract.sol
119: IDelegationManagementContract private dmc;
[119]
File: smart-contracts/RandomizerVRF.sol
22: VRFCoordinatorV2Interface public COORDINATOR;
[22]
Caching of a state variable replaces each Gwarmaccess (100 gas) with a cheaper stack read. Other less obvious fixes/optimizations include having local memory caches of state variable structs, or having local caches of state variable contracts/addresses.
There are 9 instances of this issue.
File: smart-contracts/AuctionDemo.sol
// @audit gencore on line 108
112: IERC721(gencore).safeTransferFrom(ownerOfToken, highestBidder, _tokenid);
[112]
File: smart-contracts/MinterContract.sol
// @audit gencore on lines 182, 185, 186, 188
189: gencore.airDropTokens(mintIndex, _recipients[y], _tokenData[y], _saltfun_o[y], _collectionID);
// @audit dmc on line 207
209: isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(_delegator, collectionPhases[col].delAddress, msg.sender, 1) || dmc.retrieveGlobalStatusOfDelegation(_delegator, collectionPhases[col].delAddress, msg.sender, 2);
// @audit gencore on lines 213, 217, 223, 224, 231, 232, 235, 236
252: lastMintDate[col] = collectionPhases[col].allowlistStartTime + (collectionPhases[col].timePeriod * (gencore.viewCirSupply(col) - 1));
// @audit gencore on lines 261, 264, 265, 267
270: gencore.burnToMint(mintIndex, _burnCollectionID, _tokenId, _mintCollectionID, _saltfun_o, burner);
// @audit gencore on lines 277, 279, 280, 281, 282
295: lastMintDate[_collectionID] = collectionPhases[_collectionID].allowlistStartTime + (collectionPhases[_collectionID].timePeriod * (gencore.viewCirSupply(_collectionID) - 1));
// @audit dmc on line 333
335: isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(ownerOfToken, _erc721Collection, msg.sender, 1) || dmc.retrieveGlobalStatusOfDelegation(ownerOfToken, _erc721Collection, msg.sender, 2);
// @audit gencore on lines 359, 360, 362
363: gencore.mint(mintIndex, mintingAddress, ownerOfToken, tokData, _saltfun_o, col, phase);
[189, 209, 252, 270, 295, 335, 363]
File: smart-contracts/NextGenCore.sol
// @audit newCollectionIndex on lines 131, 132, 133, 134, 135, 136, 137, 138, 140
139: isCollectionCreated[newCollectionIndex] = true;
[139]
returnData
is copied to memory even if the variable is not utilized: the proper way to handle this is through a low level assembly call.
// before
(bool success,) = payable(receiver).call{gas: gas, value: value}("");
//after
bool success;
assembly {
success := call(gas, receiver, value, 0, 0, 0, 0)
}
There are 11 instances of this issue.
File: smart-contracts/AuctionDemo.sol
113: (bool success, ) = payable(owner()).call{value: highestBid}("");
116: (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}("");
128: (bool success, ) = payable(auctionInfoData[_tokenid][index].bidder).call{value: auctionInfoData[_tokenid][index].bid}("");
139: (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}("");
File: smart-contracts/MinterContract.sol
434: (bool success1, ) = payable(collectionArtistPrimaryAddresses[colId].primaryAdd1).call{value: artistRoyalties1}("");
435: (bool success2, ) = payable(collectionArtistPrimaryAddresses[colId].primaryAdd2).call{value: artistRoyalties2}("");
436: (bool success3, ) = payable(collectionArtistPrimaryAddresses[colId].primaryAdd3).call{value: artistRoyalties3}("");
437: (bool success4, ) = payable(tm1).call{value: teamRoyalties1}("");
438: (bool success5, ) = payable(tm2).call{value: teamRoyalties2}("");
464: (bool success, ) = payable(admin).call{value: balance}("");
[434, 435, 436, 437, 438, 464]
File: smart-contracts/RandomizerRNG.sol
82: (bool success, ) = payable(admin).call{value: balance}("");
[82]
Consider refactoring the function arguments from memory
to calldata
when they are immutable, as calldata
is cheaper.
There are 13 instances of this issue.
File: smart-contracts/MinterContract.sol
// @audit _recipients, _tokenData, _saltfun_o, _numberOfTokens
181: function airDropTokens(address[] memory _recipients, string[] memory _tokenData, uint256[] memory _saltfun_o, uint256 _collectionID, uint256[] memory _numberOfTokens) public FunctionAdminRequired(this.airDropTokens.selector) {
// @audit _tokenData
196: function mint(uint256 _collectionID, uint256 _numberOfTokens, uint256 _maxAllowance, string memory _tokenData, address _mintTo, bytes32[] calldata merkleProof, address _delegator, uint256 _saltfun_o) public payable {
// @audit _tokenData
276: function mintAndAuction(address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint _auctionEndTime) public FunctionAdminRequired(this.mintAndAuction.selector) {
// @audit _tokenData
326: function burnOrSwapExternalToMint(address _erc721Collection, uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, string memory _tokenData, bytes32[] calldata merkleProof, uint256 _saltfun_o) public payable {
File: smart-contracts/NextGenAdmins.sol
// @audit _selector
50: function registerBatchFunctionAdmin(address _address, bytes4[] memory _selector, bool _status) public AdminRequired {
[50]
File: smart-contracts/NextGenCore.sol
// @audit _collectionName, _collectionArtist, _collectionDescription, _collectionWebsite, _collectionLicense, _collectionBaseURI, _collectionLibrary, _collectionScript
130: function createCollection(string memory _collectionName, string memory _collectionArtist, string memory _collectionDescription, string memory _collectionWebsite, string memory _collectionLicense, string memory _collectionBaseURI, string memory _collectionLibrary, string[] memory _collectionScript) public FunctionAdminRequired(this.createCollection.selector) {
// @audit _tokenData
178: function airDropTokens(uint256 mintIndex, address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID) external {
// @audit _tokenData
189: function mint(uint256 mintIndex, address _mintingAddress , address _mintTo, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint256 phase) external {
// @audit _tokenData
227: function _mintProcessing(uint256 _mintIndex, address _recipient, string memory _tokenData, uint256 _collectionID, uint256 _saltfun_o) internal {
// @audit _newCollectionName, _newCollectionArtist, _newCollectionDescription, _newCollectionWebsite, _newCollectionLicense, _newCollectionBaseURI, _newCollectionLibrary, _newCollectionScript
238: function updateCollectionInfo(uint256 _collectionID, string memory _newCollectionName, string memory _newCollectionArtist, string memory _newCollectionDescription, string memory _newCollectionWebsite, string memory _newCollectionLicense, string memory _newCollectionBaseURI, string memory _newCollectionLibrary, uint256 _index, string[] memory _newCollectionScript) public CollectionAdminRequired(_collectionID, this.updateCollectionInfo.selector) {
// @audit _signature
257: function artistSignature(uint256 _collectionID, string memory _signature) public {
// @audit newData
273: function changeTokenData(uint256 _tokenId, string memory newData) public FunctionAdminRequired(this.changeTokenData.selector) {
// @audit _tokenId, _images, _attributes
281: function updateImagesAndAttributes(uint256[] memory _tokenId, string[] memory _images, string[] memory _attributes) public FunctionAdminRequired(this.updateImagesAndAttributes.selector) {
[130, 178, 189, 227, 238, 257, 273, 281]
If the old value is equal to the new value, not re-storing the value will avoid a Gsreset (2900 gas), potentially at the expense of a Gcoldsload (2100 gas) or a Gwarmaccess (100 gas)
There are 19 instances of this issue.
Expand findings
File: smart-contracts/MinterContract.sol
// @audit setMintingCosts
157: function setCollectionCosts(uint256 _collectionID, uint256 _collectionMintCost, uint256 _collectionEndMintCost, uint256 _rate, uint256 _timePeriod, uint8 _salesOption, address _delAddress) public CollectionAdminRequired(_collectionID, this.setCollectionCosts.selector) {
// @audit gencore
448: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
// @audit adminsContract
454: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
File: smart-contracts/NextGenCore.sol
// @audit wereDataAdded
147: function setCollectionData(uint256 _collectionID, address _collectionArtistAddress, uint256 _maxCollectionPurchases, uint256 _collectionTotalSupply, uint _setFinalSupplyTimeAfterMint) public CollectionAdminRequired(_collectionID, this.setCollectionData.selector) {
// @audit onchainMetadata
266: function changeMetadataView(uint256 _collectionID, bool _status) public CollectionAdminRequired(_collectionID, this.changeMetadataView.selector) {
// @audit tokenData
273: function changeTokenData(uint256 _tokenId, string memory newData) public FunctionAdminRequired(this.changeTokenData.selector) {
// @audit tokenImageAndAttributes, tokenImageAndAttributes
281: function updateImagesAndAttributes(uint256[] memory _tokenId, string[] memory _images, string[] memory _attributes) public FunctionAdminRequired(this.updateImagesAndAttributes.selector) {
// @audit tokenToHash
299: function setTokenHash(uint256 _collectionID, uint256 _mintIndex, bytes32 _hash) external {
// @audit adminsContract
322: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
[147, 266, 273, 281, 299, 322]
File: smart-contracts/RandomizerNXT.sol
// @audit randoms
41: function updateRandomsContract(address _randoms) public FunctionAdminRequired(this.updateRandomsContract.selector) {
// @audit adminsContract
45: function updateAdminsContract(address _admin) public FunctionAdminRequired(this.updateAdminsContract.selector) {
// @audit gencore, gencoreContract
49: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
File: smart-contracts/RandomizerRNG.sol
// @audit adminsContract
61: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
// @audit gencore, gencoreContract
66: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
// @audit ethRequired
73: function updateRNGCost(uint256 _ethRequired) public FunctionAdminRequired(this.updateRNGCost.selector) {
File: smart-contracts/RandomizerVRF.sol
// @audit callbackGasLimit, keyHash
79: function updatecallbackGasLimitAndkeyHash(uint32 _callbackGasLimit, bytes32 _keyHash) public FunctionAdminRequired(this.updatecallbackGasLimitAndkeyHash.selector){
// @audit s_subscriptionId, numWords, requestConfirmations
86: function updateAdditionalData(uint64 _s_subscriptionId, uint32 _numWords, uint16 _requestConfirmations) public FunctionAdminRequired(this.updateAdditionalData.selector){
// @audit adminsContract
94: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
// @audit gencore, gencoreContract
99: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
Emitting an event inside a loop performs a LOG
op N times, where N is the loop length. Consider refactoring the code to emit the event only once at the end of loop. Gas savings should be multiplied by the average loop length.
There are 3 instances of this issue.
File: smart-contracts/AuctionDemo.sol
114: emit ClaimAuction(owner(), _tokenid, success, highestBid);
117: emit Refund(auctionInfoData[_tokenid][i].bidder, _tokenid, success, highestBid);
140: emit CancelBid(msg.sender, _tokenid, i, success, auctionInfoData[_tokenid][i].bid);
Some conditions may be reordered to save an SLOAD
(2100 gas), as we avoid reading state variables when the first part of the condition fails (with &&
), or succeeds (with ||
).
There are 2 instances of this issue.
File: smart-contracts/NextGenAdmins.sol
// @audit switch with this condition
// (_msgSender()== owner()) || (adminPermissions[msg.sender] == true)
32: require((adminPermissions[msg.sender] == true) || (_msgSender()== owner()), "Not allowed");
[32]
File: smart-contracts/NextGenCore.sol
// @audit switch with this condition
// (_collectionTotalSupply <= 10000000000) && (isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false)
148: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false) && (_collectionTotalSupply <= 10000000000), "err/freezed");
[148]
Consider using a local storage
or calldata
variable when accessing a mapping/array value multiple times.
This can be useful to avoid recalculating the mapping hash and/or the array offsets.
There are 46 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
// @audit auctionInfoData on lines 67, 69, 70, 70, 71
75: if (auctionInfoData[_tokenid][index].status == true) {
// @audit auctionInfoData on lines 90, 91, 91, 95
96: return auctionInfoData[_tokenid][index].bidder;
// @audit auctionInfoData on lines 110, 111, 111, 111, 115, 116, 116
117: emit Refund(auctionInfoData[_tokenid][i].bidder, _tokenid, success, highestBid);
// @audit auctionInfoData[_tokenid] on lines 126, 126, 127, 128, 128
129: emit CancelBid(msg.sender, _tokenid, index, success, auctionInfoData[_tokenid][index].bid);
// @audit auctionInfoData on lines 136, 137, 137, 138, 139, 139
140: emit CancelBid(msg.sender, _tokenid, i, success, auctionInfoData[_tokenid][i].bid);
File: smart-contracts/MinterContract.sol
// @audit collectionPhases on lines 159, 160, 161, 162, 163
164: collectionPhases[_collectionID].delAddress = _delAddress;
// @audit collectionPhases on lines 172, 173, 174, 175
176: collectionPhases[_collectionID].publicEndTime = _publicEndTime;
// @audit collectionPhases on lines 202, 202, 209, 209, 220, 221, 221, 240, 244, 244, 249, 252
252: lastMintDate[col] = collectionPhases[col].allowlistStartTime + (collectionPhases[col].timePeriod * (gencore.viewCirSupply(col) - 1));
// @audit collectionPhases on line 260
260: require(block.timestamp >= collectionPhases[_mintCollectionID].publicStartTime && block.timestamp<=collectionPhases[_mintCollectionID].publicEndTime,"No minting");
// @audit collectionPhases on lines 287, 287, 292, 295
295: lastMintDate[_collectionID] = collectionPhases[_collectionID].allowlistStartTime + (collectionPhases[_collectionID].timePeriod * (gencore.viewCirSupply(_collectionID) - 1));
// @audit burnOrSwapIds on line 320
321: burnOrSwapIds[externalCol][1] = _tokmax;
// @audit burnOrSwapIds[externalCol] on line 339
339: require(_tokenId >= burnOrSwapIds[externalCol][0] && _tokenId <= burnOrSwapIds[externalCol][1], "Token id does not match");
// @audit collectionPhases on lines 345, 345, 350, 351
351: } else if (block.timestamp >= collectionPhases[col].publicStartTime && block.timestamp <= collectionPhases[col].publicEndTime) {
// @audit collectionRoyaltiesPrimarySplits on line 372
373: collectionRoyaltiesPrimarySplits[_collectionID].teamPercentage = _teamPrSplit;
// @audit collectionRoyaltiesSecondarySplits on line 374
375: collectionRoyaltiesSecondarySplits[_collectionID].teamPercentage = _teamSecSplit;
// @audit collectionArtistPrimaryAddresses on lines 381, 383, 384, 385, 386, 387, 388
389: collectionArtistPrimaryAddresses[_collectionID].status = false;
// @audit collectionArtistSecondaryAddresses on lines 395, 397, 398, 399, 400, 401, 402
403: collectionArtistSecondaryAddresses[_collectionID].status = false;
// @audit collectionArtistPrimaryAddresses on lines 416, 429, 430, 431, 434, 435, 436, 439, 440
441: emit PayArtist(collectionArtistPrimaryAddresses[colId].primaryAdd3, success3, artistRoyalties3);
// @audit collectionRoyaltiesPrimarySplits on line 471
471: return (collectionRoyaltiesPrimarySplits[_collectionID].artistPercentage, collectionRoyaltiesPrimarySplits[_collectionID].teamPercentage);
// @audit collectionArtistPrimaryAddresses on lines 477, 477, 477, 477, 477, 477
477: return (collectionArtistPrimaryAddresses[_collectionID].primaryAdd1, collectionArtistPrimaryAddresses[_collectionID].primaryAdd2, collectionArtistPrimaryAddresses[_collectionID].primaryAdd3, collectionArtistPrimaryAddresses[_collectionID].add1Percentage, collectionArtistPrimaryAddresses[_collectionID].add2Percentage, collectionArtistPrimaryAddresses[_collectionID].add3Percentage, collectionArtistPrimaryAddresses[_collectionID].status);
// @audit collectionRoyaltiesSecondarySplits on line 483
483: return (collectionRoyaltiesSecondarySplits[_collectionID].artistPercentage, collectionRoyaltiesSecondarySplits[_collectionID].teamPercentage);
// @audit collectionArtistSecondaryAddresses on lines 489, 489, 489, 489, 489, 489
489: return (collectionArtistSecondaryAddresses[_collectionID].secondaryAdd1, collectionArtistSecondaryAddresses[_collectionID].secondaryAdd2, collectionArtistSecondaryAddresses[_collectionID].secondaryAdd3, collectionArtistSecondaryAddresses[_collectionID].add1Percentage, collectionArtistSecondaryAddresses[_collectionID].add2Percentage, collectionArtistSecondaryAddresses[_collectionID].add3Percentage, collectionArtistSecondaryAddresses[_collectionID].status);
// @audit collectionPhases on lines 495, 495, 495, 495
495: return (collectionPhases[_collectionID].allowlistStartTime, collectionPhases[_collectionID].allowlistEndTime, collectionPhases[_collectionID].merkleRoot, collectionPhases[_collectionID].publicStartTime, collectionPhases[_collectionID].publicEndTime);
// @audit collectionPhases on lines 501, 501, 501, 501, 501
501: return (collectionPhases[_collectionID].collectionMintCost, collectionPhases[_collectionID].collectionEndMintCost, collectionPhases[_collectionID].rate, collectionPhases[_collectionID].timePeriod, collectionPhases[_collectionID].salesOption, collectionPhases[_collectionID].delAddress);
// @audit collectionPhases on lines 532, 535, 536, 536, 536, 538, 540, 540, 540, 546, 546, 549, 550, 551, 551, 551, 551, 553, 553, 553, 554, 554, 556, 559, 562
566: return collectionPhases[_collectionId].collectionMintCost;
[164, 176, 252, 260, 295, 321, 339, 351, 373, 375, 389, 403, 441, 471, 477, 483, 489, 495, 501, 566]
File: smart-contracts/NextGenCore.sol
// @audit collectionInfo on lines 131, 132, 133, 134, 135, 136, 137
138: collectionInfo[newCollectionIndex].collectionScript = _collectionScript;
// @audit collectionAdditionalData on lines 149, 150, 151, 152, 153, 154, 155, 156, 159, 160, 161, 163
164: collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint = _setFinalSupplyTimeAfterMint;
// @audit collectionAdditionalData on line 172
173: collectionAdditionalData[_collectionID].randomizer = IRandomizer(_randomizerContract);
// @audit collectionAdditionalData on lines 180, 180, 181
181: if (collectionAdditionalData[_collectionID].collectionTotalSupply >= collectionAdditionalData[_collectionID].collectionCirculationSupply) {
// @audit tokensAirdropPerAddress on line 183
183: tokensAirdropPerAddress[_collectionID][_recipient] = tokensAirdropPerAddress[_collectionID][_recipient] + 1;
// @audit collectionAdditionalData on lines 191, 191, 192
192: if (collectionAdditionalData[_collectionID].collectionTotalSupply >= collectionAdditionalData[_collectionID].collectionCirculationSupply) {
// @audit tokensMintedAllowlistAddress on line 195
195: tokensMintedAllowlistAddress[_collectionID][_mintingAddress] = tokensMintedAllowlistAddress[_collectionID][_mintingAddress] + 1;
// @audit tokensMintedPerAddress on line 197
197: tokensMintedPerAddress[_collectionID][_mintingAddress] = tokensMintedPerAddress[_collectionID][_mintingAddress] + 1;
// @audit collectionAdditionalData on line 206
206: require ((_tokenId >= collectionAdditionalData[_collectionID].reservedMinTokensIndex) && (_tokenId <= collectionAdditionalData[_collectionID].reservedMaxTokensIndex), "id err");
// @audit collectionAdditionalData on lines 216, 216, 217
217: if (collectionAdditionalData[_mintCollectionID].collectionTotalSupply >= collectionAdditionalData[_mintCollectionID].collectionCirculationSupply) {
// @audit collectionInfo on lines 241, 242, 243, 244, 245, 246, 247, 249
251: collectionInfo[_collectionID].collectionScript[_index] = _newCollectionScript[0];
// @audit tokenImageAndAttributes on line 285
286: tokenImageAndAttributes[_tokenId[x]][1] = _attributes[x];
// @audit collectionAdditionalData on lines 308, 309, 309, 310
310: collectionAdditionalData[_collectionID].reservedMaxTokensIndex = (_collectionID * 10000000000) + collectionAdditionalData[_collectionID].collectionTotalSupply - 1;
// @audit tokenIdsToCollectionIds on lines 345, 346, 348, 349, 353
354: string memory _uri = string(abi.encodePacked("data:application/json;utf8,{\"name\":\"",getTokenName(tokenId),"\",\"description\":\"",collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionDescription,"\",\"image\":\"",tokenImageAndAttributes[tokenId][0],"\",\"attributes\":[",tokenImageAndAttributes[tokenId][1],"],\"animation_url\":\"data:text/html;base64,",b64,"\"}"));
// @audit collectionInfo on lines 427, 427, 427, 427, 427
427: return (collectionInfo[_collectionID].collectionName, collectionInfo[_collectionID].collectionArtist, collectionInfo[_collectionID].collectionDescription, collectionInfo[_collectionID].collectionWebsite, collectionInfo[_collectionID].collectionLicense, collectionInfo[_collectionID].collectionBaseURI);
// @audit collectionInfo on line 433
433: return (collectionInfo[_collectionID].collectionLibrary, collectionInfo[_collectionID].collectionScript);
// @audit collectionAdditionalData on lines 439, 439, 439, 439, 439
439: return (collectionAdditionalData[_collectionID].collectionArtistAddress, collectionAdditionalData[_collectionID].maxCollectionPurchases, collectionAdditionalData[_collectionID].collectionCirculationSupply, collectionAdditionalData[_collectionID].collectionTotalSupply, collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint, collectionAdditionalData[_collectionID].randomizerContract);
// @audit collectionInfo on line 453
454: scripttext = string(abi.encodePacked(scripttext, collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionScript[i]));
// @audit tokenImageAndAttributes[_tokenId] on line 468
468: return (tokenImageAndAttributes[_tokenId][0],tokenImageAndAttributes[_tokenId][1]);
[138, 164, 173, 181, 183, 192, 195, 197, 206, 217, 251, 286, 310, 354, 427, 433, 439, 454, 468]
File: smart-contracts/RandomizerRNG.sol
// @audit requestToToken on lines 49, 49
49: gencoreContract.setTokenHash(tokenIdToCollection[requestToToken[id]], requestToToken[id], bytes32(abi.encodePacked(numbers,requestToToken[id])));
[49]
File: smart-contracts/RandomizerVRF.sol
// @audit requestToToken on lines 66, 66
66: gencoreContract.setTokenHash(tokenIdToCollection[requestToToken[_requestId]], requestToToken[_requestId], bytes32(abi.encodePacked(_randomWords,requestToToken[_requestId])));
[66]
Getters for public state variables are automatically generated with public variables, so there is no need to code them manually, as it adds an unnecessary overhead.
There are 2 instances of this issue.
File: smart-contracts/AuctionDemo.sol
147: function returnBids(uint256 _tokenid) public view returns(auctionInfoStru[] memory) {
148: return auctionInfoData[_tokenid];
149: }
[147-149]
File: smart-contracts/NextGenAdmins.sol
65: function retrieveGlobalAdmin(address _address) public view returns(bool) {
66: return adminPermissions[_address];
67: }
[65-67]
Use uint256(1)
and uint256(2)
for true
/false
to avoid a Gwarmaccess (100 gas), and to avoid Gsset (20000 gas) when changing from false
to true
, after having been true
in the past. See source.
There are 13 instances of this issue.
File: smart-contracts/AuctionDemo.sol
53: mapping (uint256 => bool) public auctionClaim;
[53]
File: smart-contracts/MinterContract.sol
35: mapping (uint256 => mapping (uint256 => bool)) public burnToMintCollections;
38: mapping (bytes32 => mapping (uint256 => bool)) public burnExternalToMintCollections;
41: mapping (uint256 => bool) private setMintingCosts;
115: mapping (uint256 => bool) private mintToAuctionStatus;
File: smart-contracts/NextGenAdmins.sol
18: mapping(address => bool) public adminPermissions;
21: mapping (address => mapping (uint256 => bool)) private collectionAdmin;
24: mapping (address => mapping (bytes4 => bool)) private functionAdmin;
File: smart-contracts/NextGenCore.sol
62: mapping (uint256 => bool) private isCollectionCreated;
65: mapping (uint256 => bool) private wereDataAdded;
86: mapping (uint256 => bool) public onchainMetadata;
98: mapping (uint256 => bool) private collectionFreeze;
101: mapping (uint256 => bool) public artistSigned;
Consider the use of a custom error
, as it leads to a cheaper deploy cost and run time cost. The run time cost is only relevant when the revert condition is met.
There are 84 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
32: require(msg.sender == returnHighestBidder(_tokenId) || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
58: require(msg.value > returnHighestBid(_tokenid) && block.timestamp <= minter.getAuctionEndTime(_tokenid) && minter.getAuctionStatus(_tokenid) == true);
105: require(block.timestamp >= minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true);
125: require(block.timestamp <= minter.getAuctionEndTime(_tokenid), "Auction ended");
126: require(auctionInfoData[_tokenid][index].bidder == msg.sender && auctionInfoData[_tokenid][index].status == true);
135: require(block.timestamp <= minter.getAuctionEndTime(_tokenid), "Auction ended");
File: smart-contracts/MinterContract.sol
137: require(msg.sender == gencore.retrieveArtistAddress(_collectionID) || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
144: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
151: require(adminsContract.retrieveCollectionAdmin(msg.sender,_collectionID) == true || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
158: require(gencore.retrievewereDataAdded(_collectionID) == true, "Add data");
171: require(setMintingCosts[_collectionID] == true, "Set Minting Costs");
182: require(gencore.retrievewereDataAdded(_collectionID) == true, "Add data");
186: require(collectionTokenMintIndex <= gencore.viewTokensIndexMax(_collectionID), "No supply");
197: require(setMintingCosts[_collectionID] == true, "Set Minting Costs");
211: require(isAllowedToMint == true, "No delegation");
213: require(_maxAllowance >= gencore.retrieveTokensMintedALPerAddress(col, _delegator) + _numberOfTokens, "AL limit");
217: require(_maxAllowance >= gencore.retrieveTokensMintedALPerAddress(col, msg.sender) + _numberOfTokens, "AL limit");
220: require(MerkleProof.verifyCalldata(merkleProof, collectionPhases[col].merkleRoot, node), 'invalid proof');
223: require(_numberOfTokens <= gencore.viewMaxAllowance(col), "Change no of tokens");
224: require(gencore.retrieveTokensMintedPublicPerAddress(col, msg.sender) + _numberOfTokens <= gencore.viewMaxAllowance(col), "Max");
232: require(collectionTokenMintIndex <= gencore.viewTokensIndexMax(col), "No supply");
233: require(msg.value >= (getPrice(col) * _numberOfTokens), "Wrong ETH");
251: require(tDiff>=1 && _numberOfTokens == 1, "1 mint/period");
259: require(burnToMintCollections[_burnCollectionID][_mintCollectionID] == true, "Initialize burn");
260: require(block.timestamp >= collectionPhases[_mintCollectionID].publicStartTime && block.timestamp<=collectionPhases[_mintCollectionID].publicEndTime,"No minting");
261: require ((_tokenId >= gencore.viewTokensIndexMin(_burnCollectionID)) && (_tokenId <= gencore.viewTokensIndexMax(_burnCollectionID)), "col/token id error");
265: require(collectionTokenMintIndex <= gencore.viewTokensIndexMax(_mintCollectionID), "No supply");
266: require(msg.value >= getPrice(_mintCollectionID), "Wrong ETH");
277: require(gencore.retrievewereDataAdded(_collectionID) == true, "Add data");
280: require(collectionTokenMintIndex <= gencore.viewTokensIndexMax(_collectionID), "No supply");
294: require(tDiff>=1, "1 mint/period");
309: require((gencore.retrievewereDataAdded(_burnCollectionID) == true) && (gencore.retrievewereDataAdded(_mintCollectionID) == true), "No data");
317: require((gencore.retrievewereDataAdded(_mintCollectionID) == true), "No data");
328: require(burnExternalToMintCollections[externalCol][_mintCollectionID] == true, "Initialize external burn");
329: require(setMintingCosts[_mintCollectionID] == true, "Set Minting Costs");
337: require(isAllowedToMint == true, "No delegation");
339: require(_tokenId >= burnOrSwapIds[externalCol][0] && _tokenId <= burnOrSwapIds[externalCol][1], "Token id does not match");
350: require(MerkleProof.verifyCalldata(merkleProof, collectionPhases[col].merkleRoot, node), 'invalid proof');
360: require(collectionTokenMintIndex <= gencore.viewTokensIndexMax(col), "No supply");
361: require(msg.value >= (getPrice(col) * 1), "Wrong ETH");
370: require(_artistPrSplit + _teamPrSplit == 100, "splits need to be 100%");
371: require(_artistSecSplit + _teamSecSplit == 100, "splits need to be 100%");
381: require (collectionArtistPrimaryAddresses[_collectionID].status == false, "Already approved");
382: require (_add1Percentage + _add2Percentage + _add3Percentage == collectionRoyaltiesPrimarySplits[_collectionID].artistPercentage, "Check %");
395: require (collectionArtistSecondaryAddresses[_collectionID].status == false, "Already approved");
396: require (_add1Percentage + _add2Percentage + _add3Percentage == collectionRoyaltiesSecondarySplits[_collectionID].artistPercentage, "Check %");
416: require(collectionArtistPrimaryAddresses[_collectionID].status == true, "Accept Royalties");
417: require(collectionTotalAmount[_collectionID] > 0, "Collection Balance must be grater than 0");
418: require(collectionRoyaltiesPrimarySplits[_collectionID].artistPercentage + _teamperc1 + _teamperc2 == 100, "Change percentages");
455: require(INextGenAdmins(_newadminsContract).isAdminContract() == true, "Contract is not Admin");
[137, 144, 151, 158, 171, 182, 186, 197, 211, 213, 217, 220, 223, 224, 232, 233, 251, 259, 260, 261, 265, 266, 277, 280, 294, 309, 317, 328, 329, 337, 339, 350, 360, 361, 370, 371, 381, 382, 395, 396, 416, 417, 418, 455]
File: smart-contracts/NextGenAdmins.sol
32: require((adminPermissions[msg.sender] == true) || (_msgSender()== owner()), "Not allowed");
59: require(_collectionID > 0, "Collection Id must be larger than 0");
File: smart-contracts/NextGenCore.sol
117: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
124: require(adminsContract.retrieveCollectionAdmin(msg.sender,_collectionID) == true || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
148: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false) && (_collectionTotalSupply <= 10000000000), "err/freezed");
171: require(IRandomizer(_randomizerContract).isRandomizerContract() == true, "Contract is not Randomizer");
179: require(msg.sender == minterContract, "Caller is not the Minter Contract");
190: require(msg.sender == minterContract, "Caller is not the Minter Contract");
205: require(_isApprovedOrOwner(_msgSender(), _tokenId), "ERC721: caller is not token owner or approved");
206: require ((_tokenId >= collectionAdditionalData[_collectionID].reservedMinTokensIndex) && (_tokenId <= collectionAdditionalData[_collectionID].reservedMaxTokensIndex), "id err");
214: require(msg.sender == minterContract, "Caller is not the Minter Contract");
215: require(_isApprovedOrOwner(burner, _tokenId), "ERC721: caller is not token owner or approved");
239: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false), "Not allowed");
258: require(msg.sender == collectionAdditionalData[_collectionID].collectionArtistAddress, "Only artist");
259: require(artistSigned[_collectionID] == false, "Already Signed");
267: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false), "Not allowed");
274: require(collectionFreeze[tokenIdsToCollectionIds[_tokenId]] == false, "Data frozen");
283: require(collectionFreeze[tokenIdsToCollectionIds[_tokenId[x]]] == false, "Data frozen");
293: require(isCollectionCreated[_collectionID] == true, "No Col");
300: require(msg.sender == collectionAdditionalData[_collectionID].randomizerContract);
301: require(tokenToHash[_mintIndex] == 0x0000000000000000000000000000000000000000000000000000000000000000);
308: require (block.timestamp > IMinterContract(minterContract).getEndTime(_collectionID) + collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint, "Time has not passed");
316: require(IMinterContract(_minterContract).isMinterContract() == true, "Contract is not Minter");
323: require(INextGenAdmins(_newadminsContract).isAdminContract() == true, "Contract is not Admin");
[117, 124, 148, 171, 179, 190, 205, 206, 214, 215, 239, 258, 259, 267, 274, 283, 293, 300, 301, 308, 316, 323]
File: smart-contracts/RandomizerNXT.sol
35: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
56: require(msg.sender == gencore);
File: smart-contracts/RandomizerRNG.sol
36: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
41: require(msg.sender == gencore);
54: require(msg.sender == gencore);
62: require(INextGenAdmins(_newadminsContract).isAdminContract() == true, "Contract is not Admin");
File: smart-contracts/RandomizerVRF.sol
48: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
53: require(msg.sender == gencore);
72: require(msg.sender == gencore);
95: require(INextGenAdmins(_newadminsContract).isAdminContract() == true, "Contract is not Admin");
The IR-based code generator was developed to make code generation more performant by enabling optimization passes that can be applied across functions.
It is possible to activate the IR-based code generator through the command line by using the flag --via-ir
or by including the option {"viaIR": true}
.
Keep in mind that compiling with this option may take longer. However, you can simply test it before deploying your code. If you find that it provides better performance, you can add the --via-ir
flag to your deploy command.
Consider caching the result instead of re-calling the function when possible. Note: this also includes casts, which cost between 42-46 gas, depending on the type.
There are 11 instances of this issue.
File: smart-contracts/AuctionDemo.sol
// @audit owner() is duplicated on line 114
113: (bool success, ) = payable(owner()).call{value: highestBid}("");
[113]
File: smart-contracts/MinterContract.sol
// @audit gencore.viewTokensIndexMin(_collectionID) is duplicated on line 188
185: collectionTokenMintIndex = gencore.viewTokensIndexMin(_collectionID) + gencore.viewCirSupply(_collectionID) + _numberOfTokens[y] - 1;
// @audit gencore.viewCirSupply(_collectionID) is duplicated on line 188
185: collectionTokenMintIndex = gencore.viewTokensIndexMin(_collectionID) + gencore.viewCirSupply(_collectionID) + _numberOfTokens[y] - 1;
// @audit gencore.viewTokensIndexMin(col) is duplicated on line 235
231: collectionTokenMintIndex = gencore.viewTokensIndexMin(col) + gencore.viewCirSupply(col) + _numberOfTokens - 1;
// @audit gencore.viewCirSupply(col) is duplicated on line 235, 252
231: collectionTokenMintIndex = gencore.viewTokensIndexMin(col) + gencore.viewCirSupply(col) + _numberOfTokens - 1;
// @audit gencore.viewTokensIndexMin(_mintCollectionID) is duplicated on line 267
264: collectionTokenMintIndex = gencore.viewTokensIndexMin(_mintCollectionID) + gencore.viewCirSupply(_mintCollectionID);
// @audit gencore.viewCirSupply(_mintCollectionID) is duplicated on line 267
264: collectionTokenMintIndex = gencore.viewTokensIndexMin(_mintCollectionID) + gencore.viewCirSupply(_mintCollectionID);
// @audit gencore.viewTokensIndexMin(_collectionID) is duplicated on line 281
279: collectionTokenMintIndex = gencore.viewTokensIndexMin(_collectionID) + gencore.viewCirSupply(_collectionID);
// @audit gencore.viewCirSupply(_collectionID) is duplicated on line 281, 295
279: collectionTokenMintIndex = gencore.viewTokensIndexMin(_collectionID) + gencore.viewCirSupply(_collectionID);
// @audit gencore.viewTokensIndexMin(col) is duplicated on line 362
359: collectionTokenMintIndex = gencore.viewTokensIndexMin(col) + gencore.viewCirSupply(col);
// @audit gencore.viewCirSupply(col) is duplicated on line 362
359: collectionTokenMintIndex = gencore.viewTokensIndexMin(col) + gencore.viewCirSupply(col);
[185, 185, 231, 231, 264, 264, 279, 279, 359, 359]
If a function modifier such as onlyOwner
is used, the function will revert if a normal user tries to pay the function.
Marking the function as payable
will lower the gas for legitimate callers, as the compiler will not include checks for whether a payment was provided.
The extra opcodes avoided are:
CALLVALUE(2), DUP1(3), ISZERO(3), PUSH2(3), JUMPI(10), PUSH1(3), DUP1(3), REVERT(0), JUMPDEST(1), POP(2)
which cost an average of about 21 gas per call to the function, in addition to the extra deployment cost.
There are 43 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
104: function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){
[104]
File: smart-contracts/MinterContract.sol
157: function setCollectionCosts(uint256 _collectionID, uint256 _collectionMintCost, uint256 _collectionEndMintCost, uint256 _rate, uint256 _timePeriod, uint8 _salesOption, address _delAddress) public CollectionAdminRequired(_collectionID, this.setCollectionCosts.selector) {
170: function setCollectionPhases(uint256 _collectionID, uint _allowlistStartTime, uint _allowlistEndTime, uint _publicStartTime, uint _publicEndTime, bytes32 _merkleRoot) public CollectionAdminRequired(_collectionID, this.setCollectionPhases.selector) {
181: function airDropTokens(address[] memory _recipients, string[] memory _tokenData, uint256[] memory _saltfun_o, uint256 _collectionID, uint256[] memory _numberOfTokens) public FunctionAdminRequired(this.airDropTokens.selector) {
276: function mintAndAuction(address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint _auctionEndTime) public FunctionAdminRequired(this.mintAndAuction.selector) {
302: function updateDelegationCollection(uint256 _collectionID, address _collectionAddress) public FunctionAdminRequired(this.updateDelegationCollection.selector) {
308: function initializeBurn(uint256 _burnCollectionID, uint256 _mintCollectionID, bool _status) public FunctionAdminRequired(this.initializeBurn.selector) {
315: function initializeExternalBurnOrSwap(address _erc721Collection, uint256 _burnCollectionID, uint256 _mintCollectionID, uint256 _tokmin, uint256 _tokmax, address _burnOrSwapAddress, bool _status) public FunctionAdminRequired(this.initializeExternalBurnOrSwap.selector) {
369: function setPrimaryAndSecondarySplits(uint256 _collectionID, uint256 _artistPrSplit, uint256 _teamPrSplit, uint256 _artistSecSplit, uint256 _teamSecSplit) public FunctionAdminRequired(this.setPrimaryAndSecondarySplits.selector) {
380: function proposePrimaryAddressesAndPercentages(uint256 _collectionID, address _primaryAdd1, address _primaryAdd2, address _primaryAdd3, uint256 _add1Percentage, uint256 _add2Percentage, uint256 _add3Percentage) public ArtistOrAdminRequired(_collectionID, this.proposePrimaryAddressesAndPercentages.selector) {
394: function proposeSecondaryAddressesAndPercentages(uint256 _collectionID, address _secondaryAdd1, address _secondaryAdd2, address _secondaryAdd3, uint256 _add1Percentage, uint256 _add2Percentage, uint256 _add3Percentage) public ArtistOrAdminRequired(_collectionID, this.proposeSecondaryAddressesAndPercentages.selector) {
408: function acceptAddressesAndPercentages(uint256 _collectionID, bool _statusPrimary, bool _statusSecondary) public FunctionAdminRequired(this.acceptAddressesAndPercentages.selector) {
415: function payArtist(uint256 _collectionID, address _team1, address _team2, uint256 _teamperc1, uint256 _teamperc2) public FunctionAdminRequired(this.payArtist.selector) {
448: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
454: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
461: function emergencyWithdraw() public FunctionAdminRequired(this.emergencyWithdraw.selector) {
[157, 170, 181, 276, 302, 308, 315, 369, 380, 394, 408, 415, 448, 454, 461]
File: smart-contracts/NextGenAdmins.sol
38: function registerAdmin(address _admin, bool _status) public onlyOwner {
44: function registerFunctionAdmin(address _address, bytes4 _selector, bool _status) public AdminRequired {
50: function registerBatchFunctionAdmin(address _address, bytes4[] memory _selector, bool _status) public AdminRequired {
58: function registerCollectionAdmin(uint256 _collectionID, address _address, bool _status) public AdminRequired {
File: smart-contracts/NextGenCore.sol
130: function createCollection(string memory _collectionName, string memory _collectionArtist, string memory _collectionDescription, string memory _collectionWebsite, string memory _collectionLicense, string memory _collectionBaseURI, string memory _collectionLibrary, string[] memory _collectionScript) public FunctionAdminRequired(this.createCollection.selector) {
147: function setCollectionData(uint256 _collectionID, address _collectionArtistAddress, uint256 _maxCollectionPurchases, uint256 _collectionTotalSupply, uint _setFinalSupplyTimeAfterMint) public CollectionAdminRequired(_collectionID, this.setCollectionData.selector) {
170: function addRandomizer(uint256 _collectionID, address _randomizerContract) public FunctionAdminRequired(this.addRandomizer.selector) {
238: function updateCollectionInfo(uint256 _collectionID, string memory _newCollectionName, string memory _newCollectionArtist, string memory _newCollectionDescription, string memory _newCollectionWebsite, string memory _newCollectionLicense, string memory _newCollectionBaseURI, string memory _newCollectionLibrary, uint256 _index, string[] memory _newCollectionScript) public CollectionAdminRequired(_collectionID, this.updateCollectionInfo.selector) {
266: function changeMetadataView(uint256 _collectionID, bool _status) public CollectionAdminRequired(_collectionID, this.changeMetadataView.selector) {
273: function changeTokenData(uint256 _tokenId, string memory newData) public FunctionAdminRequired(this.changeTokenData.selector) {
281: function updateImagesAndAttributes(uint256[] memory _tokenId, string[] memory _images, string[] memory _attributes) public FunctionAdminRequired(this.updateImagesAndAttributes.selector) {
292: function freezeCollection(uint256 _collectionID) public FunctionAdminRequired(this.freezeCollection.selector) {
307: function setFinalSupply(uint256 _collectionID) public FunctionAdminRequired(this.setFinalSupply.selector) {
315: function addMinterContract(address _minterContract) public FunctionAdminRequired(this.addMinterContract.selector) {
322: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
329: function setDefaultRoyalties(address _royaltyAddress, uint96 _bps) public FunctionAdminRequired(this.setDefaultRoyalties.selector) {
[130, 147, 170, 238, 266, 273, 281, 292, 307, 315, 322, 329]
File: smart-contracts/RandomizerNXT.sol
41: function updateRandomsContract(address _randoms) public FunctionAdminRequired(this.updateRandomsContract.selector) {
45: function updateAdminsContract(address _admin) public FunctionAdminRequired(this.updateAdminsContract.selector) {
49: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
File: smart-contracts/RandomizerRNG.sol
61: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
66: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
73: function updateRNGCost(uint256 _ethRequired) public FunctionAdminRequired(this.updateRNGCost.selector) {
79: function emergencyWithdraw() public FunctionAdminRequired(this.emergencyWithdraw.selector) {
File: smart-contracts/RandomizerVRF.sol
79: function updatecallbackGasLimitAndkeyHash(uint32 _callbackGasLimit, bytes32 _keyHash) public FunctionAdminRequired(this.updatecallbackGasLimitAndkeyHash.selector){
86: function updateAdditionalData(uint64 _s_subscriptionId, uint32 _numWords, uint16 _requestConfirmations) public FunctionAdminRequired(this.updateAdditionalData.selector){
94: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
99: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
Solidity compiler reads array length every iteration if not cached. Storage array requires an extra sload operation (100 gas), memory array requires an extra mload operation (3 gas).
There are 8 instances of this issue.
File: smart-contracts/AuctionDemo.sol
69: for (uint256 i=0; i< auctionInfoData[_tokenid].length; i++) {
90: for (uint256 i=0; i< auctionInfoData[_tokenid].length; i++) {
110: for (uint256 i=0; i< auctionInfoData[_tokenid].length; i ++) {
136: for (uint256 i=0; i<auctionInfoData[_tokenid].length; i++) {
File: smart-contracts/MinterContract.sol
184: for (uint256 y=0; y< _recipients.length; y++) {
[184]
File: smart-contracts/NextGenAdmins.sol
51: for (uint256 i=0; i<_selector.length; i++) {
[51]
File: smart-contracts/NextGenCore.sol
282: for (uint256 x; x < _tokenId.length; x++) {
453: for (uint256 i=0; i < collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionScript.length; i++) {
It's better to not cache global variables, as their direct usage is cheaper (e.g. msg.sender
).
There is 1 instance of this issue.
File: smart-contracts/MinterContract.sol
269: address burner = msg.sender;
[269]
There are some checks to avoid an underflow, so it's safe to use unchecked
to have some gas savings.
There is 1 instance of this issue.
File: smart-contracts/MinterContract.sol
// @audit check on line 540
546: tDiff = (block.timestamp - collectionPhases[_collectionId].allowlistStartTime) / collectionPhases[_collectionId].timePeriod;
[546]
uint
divisions can't overflow, while int
divisions can overflow only in one specific case.
Consider adding an unchecked
block to have some gas savings.
There are 13 instances of this issue.
File: smart-contracts/MinterContract.sol
249: uint tDiff = (block.timestamp - timeOfLastMint) / collectionPhases[col].timePeriod;
292: uint tDiff = (block.timestamp - timeOfLastMint) / collectionPhases[_collectionID].timePeriod;
429: artistRoyalties1 = royalties * collectionArtistPrimaryAddresses[colId].add1Percentage / 100;
430: artistRoyalties2 = royalties * collectionArtistPrimaryAddresses[colId].add2Percentage / 100;
431: artistRoyalties3 = royalties * collectionArtistPrimaryAddresses[colId].add3Percentage / 100;
432: teamRoyalties1 = royalties * _teamperc1 / 100;
433: teamRoyalties2 = royalties * _teamperc2 / 100;
536: return collectionPhases[_collectionId].collectionMintCost + ((collectionPhases[_collectionId].collectionMintCost / collectionPhases[_collectionId].rate) * gencore.viewCirSupply(_collectionId));
546: tDiff = (block.timestamp - collectionPhases[_collectionId].allowlistStartTime) / collectionPhases[_collectionId].timePeriod;
550: price = collectionPhases[_collectionId].collectionMintCost / (tDiff + 1);
551: decreaserate = ((price - (collectionPhases[_collectionId].collectionMintCost / (tDiff + 2))) / collectionPhases[_collectionId].timePeriod) * ((block.timestamp - (tDiff * collectionPhases[_collectionId].timePeriod) - collectionPhases[_collectionId].allowlistStartTime));
551: decreaserate = ((price - (collectionPhases[_collectionId].collectionMintCost / (tDiff + 2))) / collectionPhases[_collectionId].timePeriod) * ((block.timestamp - (tDiff * collectionPhases[_collectionId].timePeriod) - collectionPhases[_collectionId].allowlistStartTime));
553: if (((collectionPhases[_collectionId].collectionMintCost - collectionPhases[_collectionId].collectionEndMintCost) / (collectionPhases[_collectionId].rate)) > tDiff) {
[249, 292, 429, 430, 431, 432, 433, 536, 546, 550, 551, 551, 553]
Some functions don't have a body: consider commenting why, or add some logic. Otherwise, refactor the code and remove these functions.
There is 1 instance of this issue.
File: smart-contracts/RandomizerRNG.sol
86: receive() external payable {}
[86]
Citing the documentation:
When using elements that are smaller than 32 bytes, your contract’s gas usage may be higher.This is because the EVM operates on 32 bytes at a time.Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size.
For example, each operation involving a uint8
costs an extra ** 22 - 28 gas ** (depending on whether the other operand is also a variable of type uint8
) as compared to ones involvinguint256
, due to the compiler having to clear the higher bits of the memory word before operating on theuint8
, as well as the associated stack operations of doing so.
Note that it might be beneficial to use reduced-size types when dealing with storage values because the compiler will pack multiple elements into one storage slot, but if not, it will have the opposite effect.
There are 13 instances of this issue.
File: smart-contracts/MinterContract.sol
54: uint8 salesOption;
157: function setCollectionCosts(uint256 _collectionID, uint256 _collectionMintCost, uint256 _collectionEndMintCost, uint256 _rate, uint256 _timePeriod, uint8 _salesOption, address _delAddress) public CollectionAdminRequired(_collectionID, this.setCollectionCosts.selector) {
500: function retrieveCollectionMintingDetails(uint256 _collectionID) public view returns(uint256, uint256, uint256, uint256, uint8, address){
File: smart-contracts/NextGenCore.sol
329: function setDefaultRoyalties(address _royaltyAddress, uint96 _bps) public FunctionAdminRequired(this.setDefaultRoyalties.selector) {
[329]
File: smart-contracts/RandomizerVRF.sol
25: uint64 s_subscriptionId;
27: uint32 public callbackGasLimit = 40000;
28: uint16 public requestConfirmations = 3;
29: uint32 public numWords = 1;
39: constructor(uint64 subscriptionId, address vrfCoordinator, address _gencore, address _adminsContract) VRFConsumerBaseV2(vrfCoordinator) {
79: function updatecallbackGasLimitAndkeyHash(uint32 _callbackGasLimit, bytes32 _keyHash) public FunctionAdminRequired(this.updatecallbackGasLimitAndkeyHash.selector){
86: function updateAdditionalData(uint64 _s_subscriptionId, uint32 _numWords, uint16 _requestConfirmations) public FunctionAdminRequired(this.updateAdditionalData.selector){
86: function updateAdditionalData(uint64 _s_subscriptionId, uint32 _numWords, uint16 _requestConfirmations) public FunctionAdminRequired(this.updateAdditionalData.selector){
86: function updateAdditionalData(uint64 _s_subscriptionId, uint32 _numWords, uint16 _requestConfirmations) public FunctionAdminRequired(this.updateAdditionalData.selector){
[25, 27, 28, 29, 39, 79, 86, 86, 86]
Using a stack variable instead of a state variable is cheaper when emitting an event.
There are 6 instances of this issue.
File: smart-contracts/AuctionDemo.sol
// @audit auctionInfoData[_tokenid][i].bidder
117: emit Refund(auctionInfoData[_tokenid][i].bidder, _tokenid, success, highestBid);
// @audit auctionInfoData[_tokenid][index].bid
129: emit CancelBid(msg.sender, _tokenid, index, success, auctionInfoData[_tokenid][index].bid);
// @audit auctionInfoData[_tokenid][i].bid
140: emit CancelBid(msg.sender, _tokenid, i, success, auctionInfoData[_tokenid][i].bid);
File: smart-contracts/MinterContract.sol
// @audit collectionArtistPrimaryAddresses[colId].primaryAdd1
439: emit PayArtist(collectionArtistPrimaryAddresses[colId].primaryAdd1, success1, artistRoyalties1);
// @audit collectionArtistPrimaryAddresses[colId].primaryAdd2
440: emit PayArtist(collectionArtistPrimaryAddresses[colId].primaryAdd2, success2, artistRoyalties2);
// @audit collectionArtistPrimaryAddresses[colId].primaryAdd3
441: emit PayArtist(collectionArtistPrimaryAddresses[colId].primaryAdd3, success3, artistRoyalties3);
Pre increments/decrements (++i/--i
) are cheaper than post increments/decrements (i++/i--
): it saves 6 gas per expression.
There are 10 instances of this issue.
File: smart-contracts/AuctionDemo.sol
69: for (uint256 i=0; i< auctionInfoData[_tokenid].length; i++) {
90: for (uint256 i=0; i< auctionInfoData[_tokenid].length; i++) {
110: for (uint256 i=0; i< auctionInfoData[_tokenid].length; i ++) {
136: for (uint256 i=0; i<auctionInfoData[_tokenid].length; i++) {
File: smart-contracts/MinterContract.sol
184: for (uint256 y=0; y< _recipients.length; y++) {
187: for(uint256 i = 0; i < _numberOfTokens[y]; i++) {
234: for(uint256 i = 0; i < _numberOfTokens; i++) {
File: smart-contracts/NextGenAdmins.sol
51: for (uint256 i=0; i<_selector.length; i++) {
[51]
File: smart-contracts/NextGenCore.sol
282: for (uint256 x; x < _tokenId.length; x++) {
453: for (uint256 i=0; i < collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionScript.length; i++) {
Consider using using msg.sender
directly when the contract does not implement EIP-2771
, as it's cheaper.
There are 2 instances of this issue.
File: smart-contracts/NextGenAdmins.sol
32: require((adminPermissions[msg.sender] == true) || (_msgSender()== owner()), "Not allowed");
[32]
File: smart-contracts/NextGenCore.sol
205: require(_isApprovedOrOwner(_msgSender(), _tokenId), "ERC721: caller is not token owner or approved");
[205]
The compiler uses opcodes GT
and ISZERO
for code that uses >
, but only requires LT
for >=
. A similar behaviour applies for >
, which uses opcodes LT
and ISZERO
, but only requires GT
for <=
.
There are 24 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
58: require(msg.value > returnHighestBid(_tokenid) && block.timestamp <= minter.getAuctionEndTime(_tokenid) && minter.getAuctionStatus(_tokenid) == true);
67: if (auctionInfoData[_tokenid].length > 0) {
69: for (uint256 i=0; i< auctionInfoData[_tokenid].length; i++) {
70: if (auctionInfoData[_tokenid][i].bid > highBid && auctionInfoData[_tokenid][i].status == true) {
90: for (uint256 i=0; i< auctionInfoData[_tokenid].length; i++) {
91: if (auctionInfoData[_tokenid][i].bid > highBid && auctionInfoData[_tokenid][i].status == true) {
110: for (uint256 i=0; i< auctionInfoData[_tokenid].length; i ++) {
136: for (uint256 i=0; i<auctionInfoData[_tokenid].length; i++) {
[58, 67, 69, 70, 90, 91, 110, 136]
File: smart-contracts/MinterContract.sol
184: for (uint256 y=0; y< _recipients.length; y++) {
187: for(uint256 i = 0; i < _numberOfTokens[y]; i++) {
234: for(uint256 i = 0; i < _numberOfTokens; i++) {
417: require(collectionTotalAmount[_collectionID] > 0, "Collection Balance must be grater than 0");
535: if (collectionPhases[_collectionId].rate > 0) {
540: } else if (collectionPhases[_collectionId].salesOption == 2 && block.timestamp > collectionPhases[_collectionId].allowlistStartTime && block.timestamp < collectionPhases[_collectionId].publicEndTime){
540: } else if (collectionPhases[_collectionId].salesOption == 2 && block.timestamp > collectionPhases[_collectionId].allowlistStartTime && block.timestamp < collectionPhases[_collectionId].publicEndTime){
553: if (((collectionPhases[_collectionId].collectionMintCost - collectionPhases[_collectionId].collectionEndMintCost) / (collectionPhases[_collectionId].rate)) > tDiff) {
559: if (price - decreaserate > collectionPhases[_collectionId].collectionEndMintCost) {
[184, 187, 234, 417, 535, 540, 540, 553, 559]
File: smart-contracts/NextGenAdmins.sol
51: for (uint256 i=0; i<_selector.length; i++) {
59: require(_collectionID > 0, "Collection Id must be larger than 0");
File: smart-contracts/NextGenCore.sol
282: for (uint256 x; x < _tokenId.length; x++) {
308: require (block.timestamp > IMinterContract(minterContract).getEndTime(_collectionID) + collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint, "Time has not passed");
347: return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
350: return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, "pending")) : "";
453: for (uint256 i=0; i < collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionScript.length; i++) {
Consider removing those internal functions and to put the logic directly where they are called, as they are called only once.
There is 1 instance of this issue.
File: smart-contracts/NextGenCore.sol
361: function getTokenName(uint256 tokenId) private view returns(string memory) {
[361]
These comparisons should be avoided, as they are implicit. Considering refactoring by using following approach instead:
if (x == true) -> if (x), if (x == false) => if (!x)
There are 69 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
32: require(msg.sender == returnHighestBidder(_tokenId) || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
32: require(msg.sender == returnHighestBidder(_tokenId) || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
58: require(msg.value > returnHighestBid(_tokenid) && block.timestamp <= minter.getAuctionEndTime(_tokenid) && minter.getAuctionStatus(_tokenid) == true);
70: if (auctionInfoData[_tokenid][i].bid > highBid && auctionInfoData[_tokenid][i].status == true) {
75: if (auctionInfoData[_tokenid][index].status == true) {
91: if (auctionInfoData[_tokenid][i].bid > highBid && auctionInfoData[_tokenid][i].status == true) {
95: if (auctionInfoData[_tokenid][index].status == true) {
105: require(block.timestamp >= minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true);
105: require(block.timestamp >= minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true);
111: if (auctionInfoData[_tokenid][i].bidder == highestBidder && auctionInfoData[_tokenid][i].bid == highestBid && auctionInfoData[_tokenid][i].status == true) {
115: } else if (auctionInfoData[_tokenid][i].status == true) {
126: require(auctionInfoData[_tokenid][index].bidder == msg.sender && auctionInfoData[_tokenid][index].status == true);
137: if (auctionInfoData[_tokenid][i].bidder == msg.sender && auctionInfoData[_tokenid][i].status == true) {
[32, 32, 58, 70, 75, 91, 95, 105, 105, 111, 115, 126, 137]
File: smart-contracts/MinterContract.sol
137: require(msg.sender == gencore.retrieveArtistAddress(_collectionID) || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
137: require(msg.sender == gencore.retrieveArtistAddress(_collectionID) || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
144: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
144: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
151: require(adminsContract.retrieveCollectionAdmin(msg.sender,_collectionID) == true || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
151: require(adminsContract.retrieveCollectionAdmin(msg.sender,_collectionID) == true || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
151: require(adminsContract.retrieveCollectionAdmin(msg.sender,_collectionID) == true || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
158: require(gencore.retrievewereDataAdded(_collectionID) == true, "Add data");
171: require(setMintingCosts[_collectionID] == true, "Set Minting Costs");
182: require(gencore.retrievewereDataAdded(_collectionID) == true, "Add data");
197: require(setMintingCosts[_collectionID] == true, "Set Minting Costs");
208: if (isAllowedToMint == false) {
211: require(isAllowedToMint == true, "No delegation");
259: require(burnToMintCollections[_burnCollectionID][_mintCollectionID] == true, "Initialize burn");
277: require(gencore.retrievewereDataAdded(_collectionID) == true, "Add data");
309: require((gencore.retrievewereDataAdded(_burnCollectionID) == true) && (gencore.retrievewereDataAdded(_mintCollectionID) == true), "No data");
309: require((gencore.retrievewereDataAdded(_burnCollectionID) == true) && (gencore.retrievewereDataAdded(_mintCollectionID) == true), "No data");
317: require((gencore.retrievewereDataAdded(_mintCollectionID) == true), "No data");
328: require(burnExternalToMintCollections[externalCol][_mintCollectionID] == true, "Initialize external burn");
329: require(setMintingCosts[_mintCollectionID] == true, "Set Minting Costs");
334: if (isAllowedToMint == false) {
337: require(isAllowedToMint == true, "No delegation");
381: require (collectionArtistPrimaryAddresses[_collectionID].status == false, "Already approved");
395: require (collectionArtistSecondaryAddresses[_collectionID].status == false, "Already approved");
416: require(collectionArtistPrimaryAddresses[_collectionID].status == true, "Accept Royalties");
455: require(INextGenAdmins(_newadminsContract).isAdminContract() == true, "Contract is not Admin");
[137, 137, 144, 144, 151, 151, 151, 158, 171, 182, 197, 208, 211, 259, 277, 309, 309, 317, 328, 329, 334, 337, 381, 395, 416, 455]
File: smart-contracts/NextGenAdmins.sol
32: require((adminPermissions[msg.sender] == true) || (_msgSender()== owner()), "Not allowed");
[32]
File: smart-contracts/NextGenCore.sol
117: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
117: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
124: require(adminsContract.retrieveCollectionAdmin(msg.sender,_collectionID) == true || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
124: require(adminsContract.retrieveCollectionAdmin(msg.sender,_collectionID) == true || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
124: require(adminsContract.retrieveCollectionAdmin(msg.sender,_collectionID) == true || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
148: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false) && (_collectionTotalSupply <= 10000000000), "err/freezed");
148: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false) && (_collectionTotalSupply <= 10000000000), "err/freezed");
158: } else if (artistSigned[_collectionID] == false) {
171: require(IRandomizer(_randomizerContract).isRandomizerContract() == true, "Contract is not Randomizer");
239: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false), "Not allowed");
239: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false), "Not allowed");
259: require(artistSigned[_collectionID] == false, "Already Signed");
267: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false), "Not allowed");
267: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false), "Not allowed");
274: require(collectionFreeze[tokenIdsToCollectionIds[_tokenId]] == false, "Data frozen");
283: require(collectionFreeze[tokenIdsToCollectionIds[_tokenId[x]]] == false, "Data frozen");
293: require(isCollectionCreated[_collectionID] == true, "No Col");
316: require(IMinterContract(_minterContract).isMinterContract() == true, "Contract is not Minter");
323: require(INextGenAdmins(_newadminsContract).isAdminContract() == true, "Contract is not Admin");
345: if (onchainMetadata[tokenIdsToCollectionIds[tokenId]] == false && tokenToHash[tokenId] != 0x0000000000000000000000000000000000000000000000000000000000000000) {
348: } else if (onchainMetadata[tokenIdsToCollectionIds[tokenId]] == false && tokenToHash[tokenId] == 0x0000000000000000000000000000000000000000000000000000000000000000) {
[117, 117, 124, 124, 124, 148, 148, 158, 171, 239, 239, 259, 267, 267, 274, 283, 293, 316, 323, 345, 348]
File: smart-contracts/RandomizerNXT.sol
35: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
35: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
File: smart-contracts/RandomizerRNG.sol
36: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
36: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
62: require(INextGenAdmins(_newadminsContract).isAdminContract() == true, "Contract is not Admin");
File: smart-contracts/RandomizerVRF.sol
48: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
48: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
95: require(INextGenAdmins(_newadminsContract).isAdminContract() == true, "Contract is not Admin");
Function that are public
/external
and public
state variable names can be optimized to save gas.
Method IDs that have two leading zero bytes can save 128 gas each during deployment, and renaming functions to have lower method IDs will save 22 gas per call, per sorted position shifted. Reference
There are 8 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
18: contract auctionDemo is Ownable {
[18]
File: smart-contracts/MinterContract.sol
20: contract NextGenMinterContract is Ownable {
[20]
File: smart-contracts/NextGenAdmins.sol
15: contract NextGenAdmins is Ownable{
[15]
File: smart-contracts/NextGenCore.sol
22: contract NextGenCore is ERC721Enumerable, Ownable, ERC2981 {
[22]
File: smart-contracts/RandomizerNXT.sol
18: contract NextGenRandomizerNXT {
[18]
File: smart-contracts/RandomizerRNG.sol
18: contract NextGenRandomizerRNG is ArrngConsumer, Ownable {
[18]
File: smart-contracts/RandomizerVRF.sol
19: contract NextGenRandomizerVRF is VRFConsumerBaseV2, Ownable {
[19]
File: smart-contracts/XRandoms.sol
13: contract randomPool {
[13]
Avoid an assignment by deleting the value instead of setting it to zero, as it's cheaper.
There are 2 instances of this issue.
File: smart-contracts/MinterContract.sol
420: collectionTotalAmount[_collectionID] = 0;
[420]
File: smart-contracts/NextGenCore.sol
152: collectionAdditionalData[_collectionID].collectionCirculationSupply = 0;
[152]
Using +=
for mappings saves 40 gas due to not having to recalculate the mapping's value's hash.
There are 8 instances of this issue.
File: smart-contracts/MinterContract.sol
238: collectionTotalAmount[col] = collectionTotalAmount[col] + msg.value;
271: collectionTotalAmount[_mintCollectionID] = collectionTotalAmount[_mintCollectionID] + msg.value;
364: collectionTotalAmount[col] = collectionTotalAmount[col] + msg.value;
File: smart-contracts/NextGenCore.sol
183: tokensAirdropPerAddress[_collectionID][_recipient] = tokensAirdropPerAddress[_collectionID][_recipient] + 1;
195: tokensMintedAllowlistAddress[_collectionID][_mintingAddress] = tokensMintedAllowlistAddress[_collectionID][_mintingAddress] + 1;
197: tokensMintedPerAddress[_collectionID][_mintingAddress] = tokensMintedPerAddress[_collectionID][_mintingAddress] + 1;
208: burnAmount[_collectionID] = burnAmount[_collectionID] + 1;
221: burnAmount[_burnCollectionID] = burnAmount[_burnCollectionID] + 1;
payable
functions cost less gas to execute, since the compiler does not have to add extra checks to ensure that a payment wasn't provided.
A constructor
can safely be marked as payable
, since only the deployer would be able to pass funds, and the project itself would not pass any funds.
There are 7 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
36: constructor (address _minter, address _gencore, address _adminsContract) public {
[36]
File: smart-contracts/MinterContract.sol
129: constructor (address _gencore, address _del, address _adminsContract) {
[129]
File: smart-contracts/NextGenAdmins.sol
26: constructor() {
[26]
File: smart-contracts/NextGenCore.sol
108: constructor(string memory name, string memory symbol, address _adminsContract) ERC721(name, symbol) {
[108]
File: smart-contracts/RandomizerNXT.sol
25: constructor(address _randoms, address _admin, address _gencore) {
[25]
File: smart-contracts/RandomizerRNG.sol
29: constructor(address _gencore, address _adminsContract, address _arRNG) ArrngConsumer(_arRNG) {
[29]
File: smart-contracts/RandomizerVRF.sol
39: constructor(uint64 subscriptionId, address vrfCoordinator, address _gencore, address _adminsContract) VRFConsumerBaseV2(vrfCoordinator) {
[39]
Considering refactoring the revert message to fit in 32 bytes to avoid using more than one memory slot.
There are 7 instances of this issue.
File: smart-contracts/MinterContract.sol
417: require(collectionTotalAmount[_collectionID] > 0, "Collection Balance must be grater than 0");
[417]
File: smart-contracts/NextGenAdmins.sol
59: require(_collectionID > 0, "Collection Id must be larger than 0");
[59]
File: smart-contracts/NextGenCore.sol
179: require(msg.sender == minterContract, "Caller is not the Minter Contract");
190: require(msg.sender == minterContract, "Caller is not the Minter Contract");
205: require(_isApprovedOrOwner(_msgSender(), _tokenId), "ERC721: caller is not token owner or approved");
214: require(msg.sender == minterContract, "Caller is not the Minter Contract");
215: require(_isApprovedOrOwner(burner, _tokenId), "ERC721: caller is not token owner or approved");
Using operator && on a single require costs more gas than using two require.
//expensive
require(version == 1 && index == 2);
//cheaper
require(version == 1);
require(index == 2 == bytes1(0));
There are 12 instances of this issue.
File: smart-contracts/AuctionDemo.sol
58: require(msg.value > returnHighestBid(_tokenid) && block.timestamp <= minter.getAuctionEndTime(_tokenid) && minter.getAuctionStatus(_tokenid) == true);
105: require(block.timestamp >= minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true);
126: require(auctionInfoData[_tokenid][index].bidder == msg.sender && auctionInfoData[_tokenid][index].status == true);
File: smart-contracts/MinterContract.sol
251: require(tDiff>=1 && _numberOfTokens == 1, "1 mint/period");
260: require(block.timestamp >= collectionPhases[_mintCollectionID].publicStartTime && block.timestamp<=collectionPhases[_mintCollectionID].publicEndTime,"No minting");
261: require ((_tokenId >= gencore.viewTokensIndexMin(_burnCollectionID)) && (_tokenId <= gencore.viewTokensIndexMax(_burnCollectionID)), "col/token id error");
309: require((gencore.retrievewereDataAdded(_burnCollectionID) == true) && (gencore.retrievewereDataAdded(_mintCollectionID) == true), "No data");
339: require(_tokenId >= burnOrSwapIds[externalCol][0] && _tokenId <= burnOrSwapIds[externalCol][1], "Token id does not match");
File: smart-contracts/NextGenCore.sol
148: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false) && (_collectionTotalSupply <= 10000000000), "err/freezed");
206: require ((_tokenId >= collectionAdditionalData[_collectionID].reservedMinTokensIndex) && (_tokenId <= collectionAdditionalData[_collectionID].reservedMaxTokensIndex), "id err");
239: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false), "Not allowed");
267: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false), "Not allowed");
Using the &&
operator on a single if
costs more gas than using two nested if
.
There are 11 instances of this issue.
File: smart-contracts/AuctionDemo.sol
70: if (auctionInfoData[_tokenid][i].bid > highBid && auctionInfoData[_tokenid][i].status == true) {
91: if (auctionInfoData[_tokenid][i].bid > highBid && auctionInfoData[_tokenid][i].status == true) {
111: if (auctionInfoData[_tokenid][i].bidder == highestBidder && auctionInfoData[_tokenid][i].bid == highestBid && auctionInfoData[_tokenid][i].status == true) {
137: if (auctionInfoData[_tokenid][i].bidder == msg.sender && auctionInfoData[_tokenid][i].status == true) {
File: smart-contracts/MinterContract.sol
202: if (block.timestamp >= collectionPhases[col].allowlistStartTime && block.timestamp <= collectionPhases[col].allowlistEndTime) {
221: } else if (block.timestamp >= collectionPhases[col].publicStartTime && block.timestamp <= collectionPhases[col].publicEndTime) {
345: if (block.timestamp >= collectionPhases[col].allowlistStartTime && block.timestamp <= collectionPhases[col].allowlistEndTime) {
351: } else if (block.timestamp >= collectionPhases[col].publicStartTime && block.timestamp <= collectionPhases[col].publicEndTime) {
540: } else if (collectionPhases[_collectionId].salesOption == 2 && block.timestamp > collectionPhases[_collectionId].allowlistStartTime && block.timestamp < collectionPhases[_collectionId].publicEndTime){
File: smart-contracts/NextGenCore.sol
345: if (onchainMetadata[tokenIdsToCollectionIds[tokenId]] == false && tokenToHash[tokenId] != 0x0000000000000000000000000000000000000000000000000000000000000000) {
348: } else if (onchainMetadata[tokenIdsToCollectionIds[tokenId]] == false && tokenToHash[tokenId] == 0x0000000000000000000000000000000000000000000000000000000000000000) {
Use unchecked
to increment the loop variable as it can save gas:
for(uint256 i; i < length;) {
unchecked{
++i;
}
}
There are 10 instances of this issue.
File: smart-contracts/AuctionDemo.sol
69: for (uint256 i=0; i< auctionInfoData[_tokenid].length; i++) {
90: for (uint256 i=0; i< auctionInfoData[_tokenid].length; i++) {
110: for (uint256 i=0; i< auctionInfoData[_tokenid].length; i ++) {
136: for (uint256 i=0; i<auctionInfoData[_tokenid].length; i++) {
File: smart-contracts/MinterContract.sol
184: for (uint256 y=0; y< _recipients.length; y++) {
187: for(uint256 i = 0; i < _numberOfTokens[y]; i++) {
234: for(uint256 i = 0; i < _numberOfTokens; i++) {
File: smart-contracts/NextGenAdmins.sol
51: for (uint256 i=0; i<_selector.length; i++) {
[51]
File: smart-contracts/NextGenCore.sol
282: for (uint256 x; x < _tokenId.length; x++) {
453: for (uint256 i=0; i < collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionScript.length; i++) {
Checking for != 0
is cheaper than > 0
for unsigned integers.
There are 6 instances of this issue.
File: smart-contracts/AuctionDemo.sol
67: if (auctionInfoData[_tokenid].length > 0) {
[67]
File: smart-contracts/MinterContract.sol
417: require(collectionTotalAmount[_collectionID] > 0, "Collection Balance must be grater than 0");
535: if (collectionPhases[_collectionId].rate > 0) {
File: smart-contracts/NextGenAdmins.sol
59: require(_collectionID > 0, "Collection Id must be larger than 0");
[59]
File: smart-contracts/NextGenCore.sol
347: return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
350: return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, "pending")) : "";
Considering using assembly to write hashes, as it's possible to save a considerable amount of gas.
There are 8 instances of this issue.
File: smart-contracts/MinterContract.sol
212: node = keccak256(abi.encodePacked(_delegator, _maxAllowance, tokData));
216: node = keccak256(abi.encodePacked(msg.sender, _maxAllowance, tokData));
316: bytes32 externalCol = keccak256(abi.encodePacked(_erc721Collection,_burnCollectionID));
327: bytes32 externalCol = keccak256(abi.encodePacked(_erc721Collection,_burnCollectionID));
348: node = keccak256(abi.encodePacked(_tokenId, tokData));
File: smart-contracts/RandomizerNXT.sol
57: bytes32 hash = keccak256(abi.encodePacked(_mintIndex, blockhash(block.number - 1), randoms.randomNumber(), randoms.randomWord()));
[57]
File: smart-contracts/XRandoms.sol
36: uint256 randomNum = uint(keccak256(abi.encodePacked(block.prevrandao, blockhash(block.number - 1), block.timestamp))) % 1000;
41: uint256 randomNum = uint(keccak256(abi.encodePacked(block.prevrandao, blockhash(block.number - 1), block.timestamp))) % 100;
It is possible to use assembly to efficiently validate msg.sender
with the least amount of opcodes. For more details check the following report.
There are 25 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
137: if (auctionInfoData[_tokenid][i].bidder == msg.sender && auctionInfoData[_tokenid][i].status == true) {
32: require(msg.sender == returnHighestBidder(_tokenId) || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
126: require(auctionInfoData[_tokenid][index].bidder == msg.sender && auctionInfoData[_tokenid][index].status == true);
File: smart-contracts/MinterContract.sol
331: if (msg.sender != ownerOfToken) {
137: require(msg.sender == gencore.retrieveArtistAddress(_collectionID) || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
144: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
151: require(adminsContract.retrieveCollectionAdmin(msg.sender,_collectionID) == true || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
217: require(_maxAllowance >= gencore.retrieveTokensMintedALPerAddress(col, msg.sender) + _numberOfTokens, "AL limit");
224: require(gencore.retrieveTokensMintedPublicPerAddress(col, msg.sender) + _numberOfTokens <= gencore.viewMaxAllowance(col), "Max");
[331, 137, 144, 151, 217, 224]
File: smart-contracts/NextGenAdmins.sol
32: require((adminPermissions[msg.sender] == true) || (_msgSender()== owner()), "Not allowed");
[32]
File: smart-contracts/NextGenCore.sol
117: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
124: require(adminsContract.retrieveCollectionAdmin(msg.sender,_collectionID) == true || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
179: require(msg.sender == minterContract, "Caller is not the Minter Contract");
190: require(msg.sender == minterContract, "Caller is not the Minter Contract");
214: require(msg.sender == minterContract, "Caller is not the Minter Contract");
258: require(msg.sender == collectionAdditionalData[_collectionID].collectionArtistAddress, "Only artist");
300: require(msg.sender == collectionAdditionalData[_collectionID].randomizerContract);
[117, 124, 179, 190, 214, 258, 300]
File: smart-contracts/RandomizerNXT.sol
35: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
56: require(msg.sender == gencore);
File: smart-contracts/RandomizerRNG.sol
36: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
41: require(msg.sender == gencore);
54: require(msg.sender == gencore);
File: smart-contracts/RandomizerVRF.sol
48: require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
53: require(msg.sender == gencore);
72: require(msg.sender == gencore);
Using assembly { sstore(state.slot, addr)
instead of state = addr
can save gas.
There are 32 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
37: minter = IMinterContract(_minter);
38: gencore = _gencore;
39: adminsContract = INextGenAdmins(_adminsContract);
File: smart-contracts/MinterContract.sol
130: gencore = INextGenCore(_gencore);
131: dmc = IDelegationManagementContract(_del);
132: adminsContract = INextGenAdmins(_adminsContract);
449: gencore = INextGenCore(_gencore);
456: adminsContract = INextGenAdmins(_newadminsContract);
File: smart-contracts/NextGenCore.sol
109: adminsContract = INextGenAdmins(_adminsContract);
317: minterContract = _minterContract;
324: adminsContract = INextGenAdmins(_newadminsContract);
File: smart-contracts/RandomizerNXT.sol
26: randoms = IXRandoms(_randoms);
27: adminsContract = INextGenAdmins(_admin);
28: gencore = _gencore;
29: gencoreContract = INextGenCore(_gencore);
42: randoms = IXRandoms(_randoms);
46: adminsContract = INextGenAdmins(_admin);
50: gencore = _gencore;
51: gencoreContract = INextGenCore(_gencore);
[26, 27, 28, 29, 42, 46, 50, 51]
File: smart-contracts/RandomizerRNG.sol
30: gencore = _gencore;
31: gencoreContract = INextGenCore(_gencore);
32: adminsContract = INextGenAdmins(_adminsContract);
63: adminsContract = INextGenAdmins(_newadminsContract);
67: gencore = _gencore;
68: gencoreContract = INextGenCore(_gencore);
File: smart-contracts/RandomizerVRF.sol
40: COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator);
42: gencore = _gencore;
43: gencoreContract = INextGenCore(_gencore);
44: adminsContract = INextGenAdmins(_adminsContract);
96: adminsContract = INextGenAdmins(_newadminsContract);
100: gencore = _gencore;
101: gencoreContract = INextGenCore(_gencore);
To efficiently emit events, it's possible to utilize assembly by making use of scratch space and the free memory pointer. This approach has the advantage of potentially avoiding the costs associated with memory expansion.
However, it's important to note that in order to safely optimize this process, it is preferable to cache and restore the free memory pointer.
A good example of such practice can be seen in Solady's codebase.
There are 12 instances of this issue.
File: smart-contracts/AuctionDemo.sol
114: emit ClaimAuction(owner(), _tokenid, success, highestBid);
117: emit Refund(auctionInfoData[_tokenid][i].bidder, _tokenid, success, highestBid);
129: emit CancelBid(msg.sender, _tokenid, index, success, auctionInfoData[_tokenid][index].bid);
140: emit CancelBid(msg.sender, _tokenid, i, success, auctionInfoData[_tokenid][i].bid);
File: smart-contracts/MinterContract.sol
439: emit PayArtist(collectionArtistPrimaryAddresses[colId].primaryAdd1, success1, artistRoyalties1);
440: emit PayArtist(collectionArtistPrimaryAddresses[colId].primaryAdd2, success2, artistRoyalties2);
441: emit PayArtist(collectionArtistPrimaryAddresses[colId].primaryAdd3, success3, artistRoyalties3);
442: emit PayTeam(tm1, success4, teamRoyalties1);
443: emit PayTeam(tm2, success5, teamRoyalties2);
465: emit Withdraw(msg.sender, success, balance);
[439, 440, 441, 442, 443, 465]
File: smart-contracts/RandomizerRNG.sol
83: emit Withdraw(msg.sender, success, balance);
[83]
File: smart-contracts/RandomizerVRF.sol
67: emit RequestFulfilled(_requestId, _randomWords);
[67]
The general issue is valid, but there is a zero check when safeMint
is called.
There is 1 instance of this issue.
File: smart-contracts/NextGenCore.sol
189: function mint(uint256 mintIndex, address _mintingAddress , address _mintTo, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint256 phase) external {
190: require(msg.sender == minterContract, "Caller is not the Minter Contract");
191: collectionAdditionalData[_collectionID].collectionCirculationSupply = collectionAdditionalData[_collectionID].collectionCirculationSupply + 1;
192: if (collectionAdditionalData[_collectionID].collectionTotalSupply >= collectionAdditionalData[_collectionID].collectionCirculationSupply) {
193: _mintProcessing(mintIndex, _mintTo, _tokenData, _collectionID, _saltfun_o);
194: if (phase == 1) {
195: tokensMintedAllowlistAddress[_collectionID][_mintingAddress] = tokensMintedAllowlistAddress[_collectionID][_mintingAddress] + 1;
196: } else {
197: tokensMintedPerAddress[_collectionID][_mintingAddress] = tokensMintedPerAddress[_collectionID][_mintingAddress] + 1;
198: }
199: }
200: }
[189-200]
The general issue is valid, but this is the OZ implementation.
There are 7 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
15: import "./Ownable.sol";
[15]
File: smart-contracts/MinterContract.sol
14: import "./Ownable.sol";
[14]
File: smart-contracts/NextGenAdmins.sol
13: import "./Ownable.sol";
[13]
File: smart-contracts/NextGenCore.sol
14: import "./Ownable.sol";
[14]
File: smart-contracts/RandomizerNXT.sol
15: import "./Ownable.sol";
[15]
File: smart-contracts/RandomizerRNG.sol
14: import "./Ownable.sol";
[14]
File: smart-contracts/RandomizerVRF.sol
15: import "./Ownable.sol";
[15]
The general issue is valid, but the following are actually selectors and not function calls.
There are 39 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
104: function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){
[104]
File: smart-contracts/MinterContract.sol
157: function setCollectionCosts(uint256 _collectionID, uint256 _collectionMintCost, uint256 _collectionEndMintCost, uint256 _rate, uint256 _timePeriod, uint8 _salesOption, address _delAddress) public CollectionAdminRequired(_collectionID, this.setCollectionCosts.selector) {
170: function setCollectionPhases(uint256 _collectionID, uint _allowlistStartTime, uint _allowlistEndTime, uint _publicStartTime, uint _publicEndTime, bytes32 _merkleRoot) public CollectionAdminRequired(_collectionID, this.setCollectionPhases.selector) {
181: function airDropTokens(address[] memory _recipients, string[] memory _tokenData, uint256[] memory _saltfun_o, uint256 _collectionID, uint256[] memory _numberOfTokens) public FunctionAdminRequired(this.airDropTokens.selector) {
276: function mintAndAuction(address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint _auctionEndTime) public FunctionAdminRequired(this.mintAndAuction.selector) {
302: function updateDelegationCollection(uint256 _collectionID, address _collectionAddress) public FunctionAdminRequired(this.updateDelegationCollection.selector) {
308: function initializeBurn(uint256 _burnCollectionID, uint256 _mintCollectionID, bool _status) public FunctionAdminRequired(this.initializeBurn.selector) {
315: function initializeExternalBurnOrSwap(address _erc721Collection, uint256 _burnCollectionID, uint256 _mintCollectionID, uint256 _tokmin, uint256 _tokmax, address _burnOrSwapAddress, bool _status) public FunctionAdminRequired(this.initializeExternalBurnOrSwap.selector) {
369: function setPrimaryAndSecondarySplits(uint256 _collectionID, uint256 _artistPrSplit, uint256 _teamPrSplit, uint256 _artistSecSplit, uint256 _teamSecSplit) public FunctionAdminRequired(this.setPrimaryAndSecondarySplits.selector) {
380: function proposePrimaryAddressesAndPercentages(uint256 _collectionID, address _primaryAdd1, address _primaryAdd2, address _primaryAdd3, uint256 _add1Percentage, uint256 _add2Percentage, uint256 _add3Percentage) public ArtistOrAdminRequired(_collectionID, this.proposePrimaryAddressesAndPercentages.selector) {
394: function proposeSecondaryAddressesAndPercentages(uint256 _collectionID, address _secondaryAdd1, address _secondaryAdd2, address _secondaryAdd3, uint256 _add1Percentage, uint256 _add2Percentage, uint256 _add3Percentage) public ArtistOrAdminRequired(_collectionID, this.proposeSecondaryAddressesAndPercentages.selector) {
408: function acceptAddressesAndPercentages(uint256 _collectionID, bool _statusPrimary, bool _statusSecondary) public FunctionAdminRequired(this.acceptAddressesAndPercentages.selector) {
415: function payArtist(uint256 _collectionID, address _team1, address _team2, uint256 _teamperc1, uint256 _teamperc2) public FunctionAdminRequired(this.payArtist.selector) {
448: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
454: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
461: function emergencyWithdraw() public FunctionAdminRequired(this.emergencyWithdraw.selector) {
[157, 170, 181, 276, 302, 308, 315, 369, 380, 394, 408, 415, 448, 454, 461]
File: smart-contracts/NextGenCore.sol
130: function createCollection(string memory _collectionName, string memory _collectionArtist, string memory _collectionDescription, string memory _collectionWebsite, string memory _collectionLicense, string memory _collectionBaseURI, string memory _collectionLibrary, string[] memory _collectionScript) public FunctionAdminRequired(this.createCollection.selector) {
147: function setCollectionData(uint256 _collectionID, address _collectionArtistAddress, uint256 _maxCollectionPurchases, uint256 _collectionTotalSupply, uint _setFinalSupplyTimeAfterMint) public CollectionAdminRequired(_collectionID, this.setCollectionData.selector) {
170: function addRandomizer(uint256 _collectionID, address _randomizerContract) public FunctionAdminRequired(this.addRandomizer.selector) {
238: function updateCollectionInfo(uint256 _collectionID, string memory _newCollectionName, string memory _newCollectionArtist, string memory _newCollectionDescription, string memory _newCollectionWebsite, string memory _newCollectionLicense, string memory _newCollectionBaseURI, string memory _newCollectionLibrary, uint256 _index, string[] memory _newCollectionScript) public CollectionAdminRequired(_collectionID, this.updateCollectionInfo.selector) {
266: function changeMetadataView(uint256 _collectionID, bool _status) public CollectionAdminRequired(_collectionID, this.changeMetadataView.selector) {
273: function changeTokenData(uint256 _tokenId, string memory newData) public FunctionAdminRequired(this.changeTokenData.selector) {
281: function updateImagesAndAttributes(uint256[] memory _tokenId, string[] memory _images, string[] memory _attributes) public FunctionAdminRequired(this.updateImagesAndAttributes.selector) {
292: function freezeCollection(uint256 _collectionID) public FunctionAdminRequired(this.freezeCollection.selector) {
307: function setFinalSupply(uint256 _collectionID) public FunctionAdminRequired(this.setFinalSupply.selector) {
315: function addMinterContract(address _minterContract) public FunctionAdminRequired(this.addMinterContract.selector) {
322: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
329: function setDefaultRoyalties(address _royaltyAddress, uint96 _bps) public FunctionAdminRequired(this.setDefaultRoyalties.selector) {
[130, 147, 170, 238, 266, 273, 281, 292, 307, 315, 322, 329]
File: smart-contracts/RandomizerNXT.sol
41: function updateRandomsContract(address _randoms) public FunctionAdminRequired(this.updateRandomsContract.selector) {
45: function updateAdminsContract(address _admin) public FunctionAdminRequired(this.updateAdminsContract.selector) {
49: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
File: smart-contracts/RandomizerRNG.sol
61: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
66: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
73: function updateRNGCost(uint256 _ethRequired) public FunctionAdminRequired(this.updateRNGCost.selector) {
79: function emergencyWithdraw() public FunctionAdminRequired(this.emergencyWithdraw.selector) {
File: smart-contracts/RandomizerVRF.sol
79: function updatecallbackGasLimitAndkeyHash(uint32 _callbackGasLimit, bytes32 _keyHash) public FunctionAdminRequired(this.updatecallbackGasLimitAndkeyHash.selector){
86: function updateAdditionalData(uint64 _s_subscriptionId, uint32 _numWords, uint16 _requestConfirmations) public FunctionAdminRequired(this.updateAdditionalData.selector){
94: function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
99: function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) {
The rule is valid for some ERC20, but these instances contain either non-ERC20 or ERC20 that do not have this issue.
There are 2 instances of this issue.
File: smart-contracts/AuctionDemo.sol
// @audit not an ERC-20
112: IERC721(gencore).safeTransferFrom(ownerOfToken, highestBidder, _tokenid);
[112]
File: smart-contracts/MinterContract.sol
// @audit not an ERC-20
340: IERC721(_erc721Collection).safeTransferFrom(ownerOfToken, burnOrSwapAddress[externalCol], _tokenId);
[340]
The general rule is true, but this project is not deployed on multiple chains.
There are 3 instances of this issue.
File: smart-contracts/RandomizerNXT.sol
57: bytes32 hash = keccak256(abi.encodePacked(_mintIndex, blockhash(block.number - 1), randoms.randomNumber(), randoms.randomWord()));
[57]
File: smart-contracts/XRandoms.sol
36: uint256 randomNum = uint(keccak256(abi.encodePacked(block.prevrandao, blockhash(block.number - 1), block.timestamp))) % 1000;
41: uint256 randomNum = uint(keccak256(abi.encodePacked(block.prevrandao, blockhash(block.number - 1), block.timestamp))) % 100;
The general rule is true, but this project is not deployed on multiple chains.
There are 6 instances of this issue.
File: smart-contracts/MinterContract.sol
// @audit 0x0000000000000000000000000000000000000000
205: if (_delegator != 0x0000000000000000000000000000000000000000) {
// @audit 0x8888888888888888888888888888888888888888
207: isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(_delegator, 0x8888888888888888888888888888888888888888, msg.sender, 1) || dmc.retrieveGlobalStatusOfDelegation(_delegator, 0x8888888888888888888888888888888888888888, msg.sender, 2);
// @audit 0x8888888888888888888888888888888888888888
207: isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(_delegator, 0x8888888888888888888888888888888888888888, msg.sender, 1) || dmc.retrieveGlobalStatusOfDelegation(_delegator, 0x8888888888888888888888888888888888888888, msg.sender, 2);
// @audit 0x8888888888888888888888888888888888888888
333: isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(ownerOfToken, 0x8888888888888888888888888888888888888888, msg.sender, 1) || dmc.retrieveGlobalStatusOfDelegation(ownerOfToken, 0x8888888888888888888888888888888888888888, msg.sender, 2);
// @audit 0x8888888888888888888888888888888888888888
333: isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(ownerOfToken, 0x8888888888888888888888888888888888888888, msg.sender, 1) || dmc.retrieveGlobalStatusOfDelegation(ownerOfToken, 0x8888888888888888888888888888888888888888, msg.sender, 2);
File: smart-contracts/NextGenCore.sol
// @audit 0x1B1289E34Fe05019511d7b436a5138F361904df0
111: _setDefaultRoyalty(0x1B1289E34Fe05019511d7b436a5138F361904df0, 690);
[111]
The following instances are not addresses and thus they are invalid.
There are 9 instances of this issue.
File: smart-contracts/NextGenCore.sol
// @audit 10000000000
148: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false) && (_collectionTotalSupply <= 10000000000), "err/freezed");
// @audit 10000000000
155: collectionAdditionalData[_collectionID].reservedMinTokensIndex = (_collectionID * 10000000000);
// @audit 10000000000
156: collectionAdditionalData[_collectionID].reservedMaxTokensIndex = (_collectionID * 10000000000) + _collectionTotalSupply - 1;
// @audit 0x0000000000000000000000000000000000000000000000000000000000000000
301: require(tokenToHash[_mintIndex] == 0x0000000000000000000000000000000000000000000000000000000000000000);
// @audit 10000000000
310: collectionAdditionalData[_collectionID].reservedMaxTokensIndex = (_collectionID * 10000000000) + collectionAdditionalData[_collectionID].collectionTotalSupply - 1;
// @audit 0x0000000000000000000000000000000000000000000000000000000000000000
345: if (onchainMetadata[tokenIdsToCollectionIds[tokenId]] == false && tokenToHash[tokenId] != 0x0000000000000000000000000000000000000000000000000000000000000000) {
// @audit 0x0000000000000000000000000000000000000000000000000000000000000000
348: } else if (onchainMetadata[tokenIdsToCollectionIds[tokenId]] == false && tokenToHash[tokenId] == 0x0000000000000000000000000000000000000000000000000000000000000000) {
[148, 155, 156, 301, 310, 345, 348]
File: smart-contracts/RandomizerVRF.sol
// @audit 0x79d3d8832d904592c0bf9818b621522c988bb8b0c05cdc3b15aea1b6e8db0c15
26: bytes32 public keyHash = 0x79d3d8832d904592c0bf9818b621522c988bb8b0c05cdc3b15aea1b6e8db0c15;
// @audit 0x79d3d8832d904592c0bf9818b621522c988bb8b0c05cdc3b15aea1b6e8db0c15
26: bytes32 public keyHash = 0x79d3d8832d904592c0bf9818b621522c988bb8b0c05cdc3b15aea1b6e8db0c15;
The following instances are not numbers and thus they are invalid.
There are 427 instances of this issue.
Expand findings
File: smart-contracts/AuctionDemo.sol
60: auctionInfoData[_tokenid].push(newBid);
67: if (auctionInfoData[_tokenid].length > 0) {
69: for (uint256 i=0; i< auctionInfoData[_tokenid].length; i++) {
70: if (auctionInfoData[_tokenid][i].bid > highBid && auctionInfoData[_tokenid][i].status == true) {
70: if (auctionInfoData[_tokenid][i].bid > highBid && auctionInfoData[_tokenid][i].status == true) {
70: if (auctionInfoData[_tokenid][i].bid > highBid && auctionInfoData[_tokenid][i].status == true) {
70: if (auctionInfoData[_tokenid][i].bid > highBid && auctionInfoData[_tokenid][i].status == true) {
71: highBid = auctionInfoData[_tokenid][i].bid;
71: highBid = auctionInfoData[_tokenid][i].bid;
75: if (auctionInfoData[_tokenid][index].status == true) {
75: if (auctionInfoData[_tokenid][index].status == true) {
90: for (uint256 i=0; i< auctionInfoData[_tokenid].length; i++) {
91: if (auctionInfoData[_tokenid][i].bid > highBid && auctionInfoData[_tokenid][i].status == true) {
91: if (auctionInfoData[_tokenid][i].bid > highBid && auctionInfoData[_tokenid][i].status == true) {
91: if (auctionInfoData[_tokenid][i].bid > highBid && auctionInfoData[_tokenid][i].status == true) {
91: if (auctionInfoData[_tokenid][i].bid > highBid && auctionInfoData[_tokenid][i].status == true) {
95: if (auctionInfoData[_tokenid][index].status == true) {
95: if (auctionInfoData[_tokenid][index].status == true) {
96: return auctionInfoData[_tokenid][index].bidder;
96: return auctionInfoData[_tokenid][index].bidder;
105: require(block.timestamp >= minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true);
106: auctionClaim[_tokenid] = true;
110: for (uint256 i=0; i< auctionInfoData[_tokenid].length; i ++) {
111: if (auctionInfoData[_tokenid][i].bidder == highestBidder && auctionInfoData[_tokenid][i].bid == highestBid && auctionInfoData[_tokenid][i].status == true) {
111: if (auctionInfoData[_tokenid][i].bidder == highestBidder && auctionInfoData[_tokenid][i].bid == highestBid && auctionInfoData[_tokenid][i].status == true) {
111: if (auctionInfoData[_tokenid][i].bidder == highestBidder && auctionInfoData[_tokenid][i].bid == highestBid && auctionInfoData[_tokenid][i].status == true) {
111: if (auctionInfoData[_tokenid][i].bidder == highestBidder && auctionInfoData[_tokenid][i].bid == highestBid && auctionInfoData[_tokenid][i].status == true) {
111: if (auctionInfoData[_tokenid][i].bidder == highestBidder && auctionInfoData[_tokenid][i].bid == highestBid && auctionInfoData[_tokenid][i].status == true) {
111: if (auctionInfoData[_tokenid][i].bidder == highestBidder && auctionInfoData[_tokenid][i].bid == highestBid && auctionInfoData[_tokenid][i].status == true) {
115: } else if (auctionInfoData[_tokenid][i].status == true) {
115: } else if (auctionInfoData[_tokenid][i].status == true) {
116: (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}("");
116: (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}("");
116: (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}("");
116: (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}("");
117: emit Refund(auctionInfoData[_tokenid][i].bidder, _tokenid, success, highestBid);
117: emit Refund(auctionInfoData[_tokenid][i].bidder, _tokenid, success, highestBid);
126: require(auctionInfoData[_tokenid][index].bidder == msg.sender && auctionInfoData[_tokenid][index].status == true);
126: require(auctionInfoData[_tokenid][index].bidder == msg.sender && auctionInfoData[_tokenid][index].status == true);
126: require(auctionInfoData[_tokenid][index].bidder == msg.sender && auctionInfoData[_tokenid][index].status == true);
126: require(auctionInfoData[_tokenid][index].bidder == msg.sender && auctionInfoData[_tokenid][index].status == true);
127: auctionInfoData[_tokenid][index].status = false;
127: auctionInfoData[_tokenid][index].status = false;
128: (bool success, ) = payable(auctionInfoData[_tokenid][index].bidder).call{value: auctionInfoData[_tokenid][index].bid}("");
128: (bool success, ) = payable(auctionInfoData[_tokenid][index].bidder).call{value: auctionInfoData[_tokenid][index].bid}("");
128: (bool success, ) = payable(auctionInfoData[_tokenid][index].bidder).call{value: auctionInfoData[_tokenid][index].bid}("");
128: (bool success, ) = payable(auctionInfoData[_tokenid][index].bidder).call{value: auctionInfoData[_tokenid][index].bid}("");
129: emit CancelBid(msg.sender, _tokenid, index, success, auctionInfoData[_tokenid][index].bid);
129: emit CancelBid(msg.sender, _tokenid, index, success, auctionInfoData[_tokenid][index].bid);
136: for (uint256 i=0; i<auctionInfoData[_tokenid].length; i++) {
137: if (auctionInfoData[_tokenid][i].bidder == msg.sender && auctionInfoData[_tokenid][i].status == true) {
137: if (auctionInfoData[_tokenid][i].bidder == msg.sender && auctionInfoData[_tokenid][i].status == true) {
137: if (auctionInfoData[_tokenid][i].bidder == msg.sender && auctionInfoData[_tokenid][i].status == true) {
137: if (auctionInfoData[_tokenid][i].bidder == msg.sender && auctionInfoData[_tokenid][i].status == true) {
138: auctionInfoData[_tokenid][i].status = false;
138: auctionInfoData[_tokenid][i].status = false;
139: (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}("");
139: (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}("");
139: (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}("");
139: (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}("");
140: emit CancelBid(msg.sender, _tokenid, i, success, auctionInfoData[_tokenid][i].bid);
140: emit CancelBid(msg.sender, _tokenid, i, success, auctionInfoData[_tokenid][i].bid);
148: return auctionInfoData[_tokenid];
[60, 67, 69, 70, 70, 70, 70, 71, 71, 75, 75, 90, 91, 91, 91, 91, 95, 95, 96, 96, 105, 106, 110, 111, 111, 111, 111, 111, 111, 115, 115, 116, 116, 116, 116, 117, 117, 126, 126, 126, 126, 127, 127, 128, 128, 128, 128, 129, 129, 136, 137, 137, 137, 137, 138, 138, 139, 139, 139, 139, 140, 140, 148]
File: smart-contracts/MinterContract.sol
159: collectionPhases[_collectionID].collectionMintCost = _collectionMintCost;
160: collectionPhases[_collectionID].collectionEndMintCost = _collectionEndMintCost;
161: collectionPhases[_collectionID].rate = _rate;
162: collectionPhases[_collectionID].timePeriod = _timePeriod;
163: collectionPhases[_collectionID].salesOption = _salesOption;
164: collectionPhases[_collectionID].delAddress = _delAddress;
165: setMintingCosts[_collectionID] = true;
171: require(setMintingCosts[_collectionID] == true, "Set Minting Costs");
172: collectionPhases[_collectionID].allowlistStartTime = _allowlistStartTime;
173: collectionPhases[_collectionID].allowlistEndTime = _allowlistEndTime;
174: collectionPhases[_collectionID].merkleRoot = _merkleRoot;
175: collectionPhases[_collectionID].publicStartTime = _publicStartTime;
176: collectionPhases[_collectionID].publicEndTime = _publicEndTime;
185: collectionTokenMintIndex = gencore.viewTokensIndexMin(_collectionID) + gencore.viewCirSupply(_collectionID) + _numberOfTokens[y] - 1;
187: for(uint256 i = 0; i < _numberOfTokens[y]; i++) {
189: gencore.airDropTokens(mintIndex, _recipients[y], _tokenData[y], _saltfun_o[y], _collectionID);
189: gencore.airDropTokens(mintIndex, _recipients[y], _tokenData[y], _saltfun_o[y], _collectionID);
189: gencore.airDropTokens(mintIndex, _recipients[y], _tokenData[y], _saltfun_o[y], _collectionID);
197: require(setMintingCosts[_collectionID] == true, "Set Minting Costs");
202: if (block.timestamp >= collectionPhases[col].allowlistStartTime && block.timestamp <= collectionPhases[col].allowlistEndTime) {
202: if (block.timestamp >= collectionPhases[col].allowlistStartTime && block.timestamp <= collectionPhases[col].allowlistEndTime) {
209: isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(_delegator, collectionPhases[col].delAddress, msg.sender, 1) || dmc.retrieveGlobalStatusOfDelegation(_delegator, collectionPhases[col].delAddress, msg.sender, 2);
209: isAllowedToMint = dmc.retrieveGlobalStatusOfDelegation(_delegator, collectionPhases[col].delAddress, msg.sender, 1) || dmc.retrieveGlobalStatusOfDelegation(_delegator, collectionPhases[col].delAddress, msg.sender, 2);
220: require(MerkleProof.verifyCalldata(merkleProof, collectionPhases[col].merkleRoot, node), 'invalid proof');
221: } else if (block.timestamp >= collectionPhases[col].publicStartTime && block.timestamp <= collectionPhases[col].publicEndTime) {
221: } else if (block.timestamp >= collectionPhases[col].publicStartTime && block.timestamp <= collectionPhases[col].publicEndTime) {
238: collectionTotalAmount[col] = collectionTotalAmount[col] + msg.value;
238: collectionTotalAmount[col] = collectionTotalAmount[col] + msg.value;
240: if (collectionPhases[col].salesOption == 3) {
242: if (lastMintDate[col] == 0) {
244: timeOfLastMint = collectionPhases[col].allowlistStartTime - collectionPhases[col].timePeriod;
244: timeOfLastMint = collectionPhases[col].allowlistStartTime - collectionPhases[col].timePeriod;
246: timeOfLastMint = lastMintDate[col];
249: uint tDiff = (block.timestamp - timeOfLastMint) / collectionPhases[col].timePeriod;
252: lastMintDate[col] = collectionPhases[col].allowlistStartTime + (collectionPhases[col].timePeriod * (gencore.viewCirSupply(col) - 1));
252: lastMintDate[col] = collectionPhases[col].allowlistStartTime + (collectionPhases[col].timePeriod * (gencore.viewCirSupply(col) - 1));
252: lastMintDate[col] = collectionPhases[col].allowlistStartTime + (collectionPhases[col].timePeriod * (gencore.viewCirSupply(col) - 1));
259: require(burnToMintCollections[_burnCollectionID][_mintCollectionID] == true, "Initialize burn");
259: require(burnToMintCollections[_burnCollectionID][_mintCollectionID] == true, "Initialize burn");
260: require(block.timestamp >= collectionPhases[_mintCollectionID].publicStartTime && block.timestamp<=collectionPhases[_mintCollectionID].publicEndTime,"No minting");
260: require(block.timestamp >= collectionPhases[_mintCollectionID].publicStartTime && block.timestamp<=collectionPhases[_mintCollectionID].publicEndTime,"No minting");
271: collectionTotalAmount[_mintCollectionID] = collectionTotalAmount[_mintCollectionID] + msg.value;
271: collectionTotalAmount[_mintCollectionID] = collectionTotalAmount[_mintCollectionID] + msg.value;
285: if (lastMintDate[_collectionID] == 0) {
287: timeOfLastMint = collectionPhases[_collectionID].allowlistStartTime - collectionPhases[_collectionID].timePeriod;
287: timeOfLastMint = collectionPhases[_collectionID].allowlistStartTime - collectionPhases[_collectionID].timePeriod;
289: timeOfLastMint = lastMintDate[_collectionID];
292: uint tDiff = (block.timestamp - timeOfLastMint) / collectionPhases[_collectionID].timePeriod;
295: lastMintDate[_collectionID] = collectionPhases[_collectionID].allowlistStartTime + (collectionPhases[_collectionID].timePeriod * (gencore.viewCirSupply(_collectionID) - 1));
295: lastMintDate[_collectionID] = collectionPhases[_collectionID].allowlistStartTime + (collectionPhases[_collectionID].timePeriod * (gencore.viewCirSupply(_collectionID) - 1));
295: lastMintDate[_collectionID] = collectionPhases[_collectionID].allowlistStartTime + (collectionPhases[_collectionID].timePeriod * (gencore.viewCirSupply(_collectionID) - 1));
296: mintToAuctionData[mintIndex] = _auctionEndTime;
297: mintToAuctionStatus[mintIndex] = true;
303: collectionPhases[_collectionID].delAddress = _collectionAddress;
310: burnToMintCollections[_burnCollectionID][_mintCollectionID] = _status;
310: burnToMintCollections[_burnCollectionID][_mintCollectionID] = _status;
318: burnExternalToMintCollections[externalCol][_mintCollectionID] = _status;
318: burnExternalToMintCollections[externalCol][_mintCollectionID] = _status;
319: burnOrSwapAddress[externalCol] = _burnOrSwapAddress;
320: burnOrSwapIds[externalCol][0] = _tokmin;
321: burnOrSwapIds[externalCol][1] = _tokmax;
328: require(burnExternalToMintCollections[externalCol][_mintCollectionID] == true, "Initialize external burn");
328: require(burnExternalToMintCollections[externalCol][_mintCollectionID] == true, "Initialize external burn");
329: require(setMintingCosts[_mintCollectionID] == true, "Set Minting Costs");
339: require(_tokenId >= burnOrSwapIds[externalCol][0] && _tokenId <= burnOrSwapIds[externalCol][1], "Token id does not match");
339: require(_tokenId >= burnOrSwapIds[externalCol][0] && _tokenId <= burnOrSwapIds[externalCol][1], "Token id does not match");
340: IERC721(_erc721Collection).safeTransferFrom(ownerOfToken, burnOrSwapAddress[externalCol], _tokenId);
345: if (block.timestamp >= collectionPhases[col].allowlistStartTime && block.timestamp <= collectionPhases[col].allowlistEndTime) {
345: if (block.timestamp >= collectionPhases[col].allowlistStartTime && block.timestamp <= collectionPhases[col].allowlistEndTime) {
350: require(MerkleProof.verifyCalldata(merkleProof, collectionPhases[col].merkleRoot, node), 'invalid proof');
351: } else if (block.timestamp >= collectionPhases[col].publicStartTime && block.timestamp <= collectionPhases[col].publicEndTime) {
351: } else if (block.timestamp >= collectionPhases[col].publicStartTime && block.timestamp <= collectionPhases[col].publicEndTime) {
364: collectionTotalAmount[col] = collectionTotalAmount[col] + msg.value;
364: collectionTotalAmount[col] = collectionTotalAmount[col] + msg.value;
372: collectionRoyaltiesPrimarySplits[_collectionID].artistPercentage = _artistPrSplit;
373: collectionRoyaltiesPrimarySplits[_collectionID].teamPercentage = _teamPrSplit;
374: collectionRoyaltiesSecondarySplits[_collectionID].artistPercentage = _artistSecSplit;
375: collectionRoyaltiesSecondarySplits[_collectionID].teamPercentage = _teamSecSplit;
381: require (collectionArtistPrimaryAddresses[_collectionID].status == false, "Already approved");
382: require (_add1Percentage + _add2Percentage + _add3Percentage == collectionRoyaltiesPrimarySplits[_collectionID].artistPercentage, "Check %");
383: collectionArtistPrimaryAddresses[_collectionID].primaryAdd1 = _primaryAdd1;
384: collectionArtistPrimaryAddresses[_collectionID].primaryAdd2 = _primaryAdd2;
385: collectionArtistPrimaryAddresses[_collectionID].primaryAdd3 = _primaryAdd3;
386: collectionArtistPrimaryAddresses[_collectionID].add1Percentage = _add1Percentage;
387: collectionArtistPrimaryAddresses[_collectionID].add2Percentage = _add2Percentage;
388: collectionArtistPrimaryAddresses[_collectionID].add3Percentage = _add3Percentage;
389: collectionArtistPrimaryAddresses[_collectionID].status = false;
395: require (collectionArtistSecondaryAddresses[_collectionID].status == false, "Already approved");
396: require (_add1Percentage + _add2Percentage + _add3Percentage == collectionRoyaltiesSecondarySplits[_collectionID].artistPercentage, "Check %");
397: collectionArtistSecondaryAddresses[_collectionID].secondaryAdd1 = _secondaryAdd1;
398: collectionArtistSecondaryAddresses[_collectionID].secondaryAdd2 = _secondaryAdd2;
399: collectionArtistSecondaryAddresses[_collectionID].secondaryAdd3 = _secondaryAdd3;
400: collectionArtistSecondaryAddresses[_collectionID].add1Percentage = _add1Percentage;
401: collectionArtistSecondaryAddresses[_collectionID].add2Percentage = _add2Percentage;
402: collectionArtistSecondaryAddresses[_collectionID].add3Percentage = _add3Percentage;
403: collectionArtistSecondaryAddresses[_collectionID].status = false;
409: collectionArtistPrimaryAddresses[_collectionID].status = _statusPrimary;
410: collectionArtistSecondaryAddresses[_collectionID].status = _statusSecondary;
416: require(collectionArtistPrimaryAddresses[_collectionID].status == true, "Accept Royalties");
417: require(collectionTotalAmount[_collectionID] > 0, "Collection Balance must be grater than 0");
418: require(collectionRoyaltiesPrimarySplits[_collectionID].artistPercentage + _teamperc1 + _teamperc2 == 100, "Change percentages");
419: uint256 royalties = collectionTotalAmount[_collectionID];
420: collectionTotalAmount[_collectionID] = 0;
429: artistRoyalties1 = royalties * collectionArtistPrimaryAddresses[colId].add1Percentage / 100;
430: artistRoyalties2 = royalties * collectionArtistPrimaryAddresses[colId].add2Percentage / 100;
431: artistRoyalties3 = royalties * collectionArtistPrimaryAddresses[colId].add3Percentage / 100;
434: (bool success1, ) = payable(collectionArtistPrimaryAddresses[colId].primaryAdd1).call{value: artistRoyalties1}("");
435: (bool success2, ) = payable(collectionArtistPrimaryAddresses[colId].primaryAdd2).call{value: artistRoyalties2}("");
436: (bool success3, ) = payable(collectionArtistPrimaryAddresses[colId].primaryAdd3).call{value: artistRoyalties3}("");
439: emit PayArtist(collectionArtistPrimaryAddresses[colId].primaryAdd1, success1, artistRoyalties1);
440: emit PayArtist(collectionArtistPrimaryAddresses[colId].primaryAdd2, success2, artistRoyalties2);
441: emit PayArtist(collectionArtistPrimaryAddresses[colId].primaryAdd3, success3, artistRoyalties3);
471: return (collectionRoyaltiesPrimarySplits[_collectionID].artistPercentage, collectionRoyaltiesPrimarySplits[_collectionID].teamPercentage);
471: return (collectionRoyaltiesPrimarySplits[_collectionID].artistPercentage, collectionRoyaltiesPrimarySplits[_collectionID].teamPercentage);
477: return (collectionArtistPrimaryAddresses[_collectionID].primaryAdd1, collectionArtistPrimaryAddresses[_collectionID].primaryAdd2, collectionArtistPrimaryAddresses[_collectionID].primaryAdd3, collectionArtistPrimaryAddresses[_collectionID].add1Percentage, collectionArtistPrimaryAddresses[_collectionID].add2Percentage, collectionArtistPrimaryAddresses[_collectionID].add3Percentage, collectionArtistPrimaryAddresses[_collectionID].status);
477: return (collectionArtistPrimaryAddresses[_collectionID].primaryAdd1, collectionArtistPrimaryAddresses[_collectionID].primaryAdd2, collectionArtistPrimaryAddresses[_collectionID].primaryAdd3, collectionArtistPrimaryAddresses[_collectionID].add1Percentage, collectionArtistPrimaryAddresses[_collectionID].add2Percentage, collectionArtistPrimaryAddresses[_collectionID].add3Percentage, collectionArtistPrimaryAddresses[_collectionID].status);
477: return (collectionArtistPrimaryAddresses[_collectionID].primaryAdd1, collectionArtistPrimaryAddresses[_collectionID].primaryAdd2, collectionArtistPrimaryAddresses[_collectionID].primaryAdd3, collectionArtistPrimaryAddresses[_collectionID].add1Percentage, collectionArtistPrimaryAddresses[_collectionID].add2Percentage, collectionArtistPrimaryAddresses[_collectionID].add3Percentage, collectionArtistPrimaryAddresses[_collectionID].status);
477: return (collectionArtistPrimaryAddresses[_collectionID].primaryAdd1, collectionArtistPrimaryAddresses[_collectionID].primaryAdd2, collectionArtistPrimaryAddresses[_collectionID].primaryAdd3, collectionArtistPrimaryAddresses[_collectionID].add1Percentage, collectionArtistPrimaryAddresses[_collectionID].add2Percentage, collectionArtistPrimaryAddresses[_collectionID].add3Percentage, collectionArtistPrimaryAddresses[_collectionID].status);
477: return (collectionArtistPrimaryAddresses[_collectionID].primaryAdd1, collectionArtistPrimaryAddresses[_collectionID].primaryAdd2, collectionArtistPrimaryAddresses[_collectionID].primaryAdd3, collectionArtistPrimaryAddresses[_collectionID].add1Percentage, collectionArtistPrimaryAddresses[_collectionID].add2Percentage, collectionArtistPrimaryAddresses[_collectionID].add3Percentage, collectionArtistPrimaryAddresses[_collectionID].status);
477: return (collectionArtistPrimaryAddresses[_collectionID].primaryAdd1, collectionArtistPrimaryAddresses[_collectionID].primaryAdd2, collectionArtistPrimaryAddresses[_collectionID].primaryAdd3, collectionArtistPrimaryAddresses[_collectionID].add1Percentage, collectionArtistPrimaryAddresses[_collectionID].add2Percentage, collectionArtistPrimaryAddresses[_collectionID].add3Percentage, collectionArtistPrimaryAddresses[_collectionID].status);
477: return (collectionArtistPrimaryAddresses[_collectionID].primaryAdd1, collectionArtistPrimaryAddresses[_collectionID].primaryAdd2, collectionArtistPrimaryAddresses[_collectionID].primaryAdd3, collectionArtistPrimaryAddresses[_collectionID].add1Percentage, collectionArtistPrimaryAddresses[_collectionID].add2Percentage, collectionArtistPrimaryAddresses[_collectionID].add3Percentage, collectionArtistPrimaryAddresses[_collectionID].status);
483: return (collectionRoyaltiesSecondarySplits[_collectionID].artistPercentage, collectionRoyaltiesSecondarySplits[_collectionID].teamPercentage);
483: return (collectionRoyaltiesSecondarySplits[_collectionID].artistPercentage, collectionRoyaltiesSecondarySplits[_collectionID].teamPercentage);
489: return (collectionArtistSecondaryAddresses[_collectionID].secondaryAdd1, collectionArtistSecondaryAddresses[_collectionID].secondaryAdd2, collectionArtistSecondaryAddresses[_collectionID].secondaryAdd3, collectionArtistSecondaryAddresses[_collectionID].add1Percentage, collectionArtistSecondaryAddresses[_collectionID].add2Percentage, collectionArtistSecondaryAddresses[_collectionID].add3Percentage, collectionArtistSecondaryAddresses[_collectionID].status);
489: return (collectionArtistSecondaryAddresses[_collectionID].secondaryAdd1, collectionArtistSecondaryAddresses[_collectionID].secondaryAdd2, collectionArtistSecondaryAddresses[_collectionID].secondaryAdd3, collectionArtistSecondaryAddresses[_collectionID].add1Percentage, collectionArtistSecondaryAddresses[_collectionID].add2Percentage, collectionArtistSecondaryAddresses[_collectionID].add3Percentage, collectionArtistSecondaryAddresses[_collectionID].status);
489: return (collectionArtistSecondaryAddresses[_collectionID].secondaryAdd1, collectionArtistSecondaryAddresses[_collectionID].secondaryAdd2, collectionArtistSecondaryAddresses[_collectionID].secondaryAdd3, collectionArtistSecondaryAddresses[_collectionID].add1Percentage, collectionArtistSecondaryAddresses[_collectionID].add2Percentage, collectionArtistSecondaryAddresses[_collectionID].add3Percentage, collectionArtistSecondaryAddresses[_collectionID].status);
489: return (collectionArtistSecondaryAddresses[_collectionID].secondaryAdd1, collectionArtistSecondaryAddresses[_collectionID].secondaryAdd2, collectionArtistSecondaryAddresses[_collectionID].secondaryAdd3, collectionArtistSecondaryAddresses[_collectionID].add1Percentage, collectionArtistSecondaryAddresses[_collectionID].add2Percentage, collectionArtistSecondaryAddresses[_collectionID].add3Percentage, collectionArtistSecondaryAddresses[_collectionID].status);
489: return (collectionArtistSecondaryAddresses[_collectionID].secondaryAdd1, collectionArtistSecondaryAddresses[_collectionID].secondaryAdd2, collectionArtistSecondaryAddresses[_collectionID].secondaryAdd3, collectionArtistSecondaryAddresses[_collectionID].add1Percentage, collectionArtistSecondaryAddresses[_collectionID].add2Percentage, collectionArtistSecondaryAddresses[_collectionID].add3Percentage, collectionArtistSecondaryAddresses[_collectionID].status);
489: return (collectionArtistSecondaryAddresses[_collectionID].secondaryAdd1, collectionArtistSecondaryAddresses[_collectionID].secondaryAdd2, collectionArtistSecondaryAddresses[_collectionID].secondaryAdd3, collectionArtistSecondaryAddresses[_collectionID].add1Percentage, collectionArtistSecondaryAddresses[_collectionID].add2Percentage, collectionArtistSecondaryAddresses[_collectionID].add3Percentage, collectionArtistSecondaryAddresses[_collectionID].status);
489: return (collectionArtistSecondaryAddresses[_collectionID].secondaryAdd1, collectionArtistSecondaryAddresses[_collectionID].secondaryAdd2, collectionArtistSecondaryAddresses[_collectionID].secondaryAdd3, collectionArtistSecondaryAddresses[_collectionID].add1Percentage, collectionArtistSecondaryAddresses[_collectionID].add2Percentage, collectionArtistSecondaryAddresses[_collectionID].add3Percentage, collectionArtistSecondaryAddresses[_collectionID].status);
495: return (collectionPhases[_collectionID].allowlistStartTime, collectionPhases[_collectionID].allowlistEndTime, collectionPhases[_collectionID].merkleRoot, collectionPhases[_collectionID].publicStartTime, collectionPhases[_collectionID].publicEndTime);
495: return (collectionPhases[_collectionID].allowlistStartTime, collectionPhases[_collectionID].allowlistEndTime, collectionPhases[_collectionID].merkleRoot, collectionPhases[_collectionID].publicStartTime, collectionPhases[_collectionID].publicEndTime);
495: return (collectionPhases[_collectionID].allowlistStartTime, collectionPhases[_collectionID].allowlistEndTime, collectionPhases[_collectionID].merkleRoot, collectionPhases[_collectionID].publicStartTime, collectionPhases[_collectionID].publicEndTime);
495: return (collectionPhases[_collectionID].allowlistStartTime, collectionPhases[_collectionID].allowlistEndTime, collectionPhases[_collectionID].merkleRoot, collectionPhases[_collectionID].publicStartTime, collectionPhases[_collectionID].publicEndTime);
495: return (collectionPhases[_collectionID].allowlistStartTime, collectionPhases[_collectionID].allowlistEndTime, collectionPhases[_collectionID].merkleRoot, collectionPhases[_collectionID].publicStartTime, collectionPhases[_collectionID].publicEndTime);
501: return (collectionPhases[_collectionID].collectionMintCost, collectionPhases[_collectionID].collectionEndMintCost, collectionPhases[_collectionID].rate, collectionPhases[_collectionID].timePeriod, collectionPhases[_collectionID].salesOption, collectionPhases[_collectionID].delAddress);
501: return (collectionPhases[_collectionID].collectionMintCost, collectionPhases[_collectionID].collectionEndMintCost, collectionPhases[_collectionID].rate, collectionPhases[_collectionID].timePeriod, collectionPhases[_collectionID].salesOption, collectionPhases[_collectionID].delAddress);
501: return (collectionPhases[_collectionID].collectionMintCost, collectionPhases[_collectionID].collectionEndMintCost, collectionPhases[_collectionID].rate, collectionPhases[_collectionID].timePeriod, collectionPhases[_collectionID].salesOption, collectionPhases[_collectionID].delAddress);
501: return (collectionPhases[_collectionID].collectionMintCost, collectionPhases[_collectionID].collectionEndMintCost, collectionPhases[_collectionID].rate, collectionPhases[_collectionID].timePeriod, collectionPhases[_collectionID].salesOption, collectionPhases[_collectionID].delAddress);
501: return (collectionPhases[_collectionID].collectionMintCost, collectionPhases[_collectionID].collectionEndMintCost, collectionPhases[_collectionID].rate, collectionPhases[_collectionID].timePeriod, collectionPhases[_collectionID].salesOption, collectionPhases[_collectionID].delAddress);
501: return (collectionPhases[_collectionID].collectionMintCost, collectionPhases[_collectionID].collectionEndMintCost, collectionPhases[_collectionID].rate, collectionPhases[_collectionID].timePeriod, collectionPhases[_collectionID].salesOption, collectionPhases[_collectionID].delAddress);
513: return collectionPhases[_collectionID].publicEndTime;
519: return mintToAuctionData[_tokenId];
525: return mintToAuctionStatus[_tokenId];
532: if (collectionPhases[_collectionId].salesOption == 3) {
535: if (collectionPhases[_collectionId].rate > 0) {
536: return collectionPhases[_collectionId].collectionMintCost + ((collectionPhases[_collectionId].collectionMintCost / collectionPhases[_collectionId].rate) * gencore.viewCirSupply(_collectionId));
536: return collectionPhases[_collectionId].collectionMintCost + ((collectionPhases[_collectionId].collectionMintCost / collectionPhases[_collectionId].rate) * gencore.viewCirSupply(_collectionId));
536: return collectionPhases[_collectionId].collectionMintCost + ((collectionPhases[_collectionId].collectionMintCost / collectionPhases[_collectionId].rate) * gencore.viewCirSupply(_collectionId));
538: return collectionPhases[_collectionId].collectionMintCost;
540: } else if (collectionPhases[_collectionId].salesOption == 2 && block.timestamp > collectionPhases[_collectionId].allowlistStartTime && block.timestamp < collectionPhases[_collectionId].publicEndTime){
540: } else if (collectionPhases[_collectionId].salesOption == 2 && block.timestamp > collectionPhases[_collectionId].allowlistStartTime && block.timestamp < collectionPhases[_collectionId].publicEndTime){
540: } else if (collectionPhases[_collectionId].salesOption == 2 && block.timestamp > collectionPhases[_collectionId].allowlistStartTime && block.timestamp < collectionPhases[_collectionId].publicEndTime){
546: tDiff = (block.timestamp - collectionPhases[_collectionId].allowlistStartTime) / collectionPhases[_collectionId].timePeriod;
546: tDiff = (block.timestamp - collectionPhases[_collectionId].allowlistStartTime) / collectionPhases[_collectionId].timePeriod;
549: if (collectionPhases[_collectionId].rate == 0) {
550: price = collectionPhases[_collectionId].collectionMintCost / (tDiff + 1);
551: decreaserate = ((price - (collectionPhases[_collectionId].collectionMintCost / (tDiff + 2))) / collectionPhases[_collectionId].timePeriod) * ((block.timestamp - (tDiff * collectionPhases[_collectionId].timePeriod) - collectionPhases[_collectionId].allowlistStartTime));
551: decreaserate = ((price - (collectionPhases[_collectionId].collectionMintCost / (tDiff + 2))) / collectionPhases[_collectionId].timePeriod) * ((block.timestamp - (tDiff * collectionPhases[_collectionId].timePeriod) - collectionPhases[_collectionId].allowlistStartTime));
551: decreaserate = ((price - (collectionPhases[_collectionId].collectionMintCost / (tDiff + 2))) / collectionPhases[_collectionId].timePeriod) * ((block.timestamp - (tDiff * collectionPhases[_collectionId].timePeriod) - collectionPhases[_collectionId].allowlistStartTime));
551: decreaserate = ((price - (collectionPhases[_collectionId].collectionMintCost / (tDiff + 2))) / collectionPhases[_collectionId].timePeriod) * ((block.timestamp - (tDiff * collectionPhases[_collectionId].timePeriod) - collectionPhases[_collectionId].allowlistStartTime));
553: if (((collectionPhases[_collectionId].collectionMintCost - collectionPhases[_collectionId].collectionEndMintCost) / (collectionPhases[_collectionId].rate)) > tDiff) {
553: if (((collectionPhases[_collectionId].collectionMintCost - collectionPhases[_collectionId].collectionEndMintCost) / (collectionPhases[_collectionId].rate)) > tDiff) {
553: if (((collectionPhases[_collectionId].collectionMintCost - collectionPhases[_collectionId].collectionEndMintCost) / (collectionPhases[_collectionId].rate)) > tDiff) {
554: price = collectionPhases[_collectionId].collectionMintCost - (tDiff * collectionPhases[_collectionId].rate);
554: price = collectionPhases[_collectionId].collectionMintCost - (tDiff * collectionPhases[_collectionId].rate);
556: price = collectionPhases[_collectionId].collectionEndMintCost;
559: if (price - decreaserate > collectionPhases[_collectionId].collectionEndMintCost) {
562: return collectionPhases[_collectionId].collectionEndMintCost;
566: return collectionPhases[_collectionId].collectionMintCost;
[159, 160, 161, 162, 163, 164, 165, 171, 172, 173, 174, 175, 176, 185, 187, 189, 189, 189, 197, 202, 202, 209, 209, 220, 221, 221, 238, 238, 240, 242, 244, 244, 246, 249, 252, 252, 252, 259, 259, 260, 260, 271, 271, 285, 287, 287, 289, 292, 295, 295, 295, 296, 297, 303, 310, 310, 318, 318, 319, 320, 321, 328, 328, 329, 339, 339, 340, 345, 345, 350, 351, 351, 364, 364, 372, 373, 374, 375, 381, 382, 383, 384, 385, 386, 387, 388, 389, 395, 396, 397, 398, 399, 400, 401, 402, 403, 409, 410, 416, 417, 418, 419, 420, 429, 430, 431, 434, 435, 436, 439, 440, 441, 471, 471, 477, 477, 477, 477, 477, 477, 477, 483, 483, 489, 489, 489, 489, 489, 489, 489, 495, 495, 495, 495, 495, 501, 501, 501, 501, 501, 501, 513, 519, 525, 532, 535, 536, 536, 536, 538, 540, 540, 540, 546, 546, 549, 550, 551, 551, 551, 551, 553, 553, 553, 554, 554, 556, 559, 562, 566]
File: smart-contracts/NextGenAdmins.sol
27: adminPermissions[msg.sender] = true;
32: require((adminPermissions[msg.sender] == true) || (_msgSender()== owner()), "Not allowed");
39: adminPermissions[_admin] = _status;
45: functionAdmin[_address][_selector] = _status;
45: functionAdmin[_address][_selector] = _status;
52: functionAdmin[_address][_selector[i]] = _status;
52: functionAdmin[_address][_selector[i]] = _status;
52: functionAdmin[_address][_selector[i]] = _status;
60: collectionAdmin[_address][_collectionID] = _status;
60: collectionAdmin[_address][_collectionID] = _status;
66: return adminPermissions[_address];
72: return functionAdmin[_address][_selector];
72: return functionAdmin[_address][_selector];
78: return collectionAdmin[_address][_collectionID];
78: return collectionAdmin[_address][_collectionID];
[27, 32, 39, 45, 45, 52, 52, 52, 60, 60, 66, 72, 72, 78, 78]
File: smart-contracts/NextGenCore.sol
131: collectionInfo[newCollectionIndex].collectionName = _collectionName;
132: collectionInfo[newCollectionIndex].collectionArtist = _collectionArtist;
133: collectionInfo[newCollectionIndex].collectionDescription = _collectionDescription;
134: collectionInfo[newCollectionIndex].collectionWebsite = _collectionWebsite;
135: collectionInfo[newCollectionIndex].collectionLicense = _collectionLicense;
136: collectionInfo[newCollectionIndex].collectionBaseURI = _collectionBaseURI;
137: collectionInfo[newCollectionIndex].collectionLibrary = _collectionLibrary;
138: collectionInfo[newCollectionIndex].collectionScript = _collectionScript;
139: isCollectionCreated[newCollectionIndex] = true;
148: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false) && (_collectionTotalSupply <= 10000000000), "err/freezed");
148: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false) && (_collectionTotalSupply <= 10000000000), "err/freezed");
149: if (collectionAdditionalData[_collectionID].collectionTotalSupply == 0) {
150: collectionAdditionalData[_collectionID].collectionArtistAddress = _collectionArtistAddress;
151: collectionAdditionalData[_collectionID].maxCollectionPurchases = _maxCollectionPurchases;
152: collectionAdditionalData[_collectionID].collectionCirculationSupply = 0;
153: collectionAdditionalData[_collectionID].collectionTotalSupply = _collectionTotalSupply;
154: collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint = _setFinalSupplyTimeAfterMint;
155: collectionAdditionalData[_collectionID].reservedMinTokensIndex = (_collectionID * 10000000000);
156: collectionAdditionalData[_collectionID].reservedMaxTokensIndex = (_collectionID * 10000000000) + _collectionTotalSupply - 1;
157: wereDataAdded[_collectionID] = true;
158: } else if (artistSigned[_collectionID] == false) {
159: collectionAdditionalData[_collectionID].collectionArtistAddress = _collectionArtistAddress;
160: collectionAdditionalData[_collectionID].maxCollectionPurchases = _maxCollectionPurchases;
161: collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint = _setFinalSupplyTimeAfterMint;
163: collectionAdditionalData[_collectionID].maxCollectionPurchases = _maxCollectionPurchases;
164: collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint = _setFinalSupplyTimeAfterMint;
172: collectionAdditionalData[_collectionID].randomizerContract = _randomizerContract;
173: collectionAdditionalData[_collectionID].randomizer = IRandomizer(_randomizerContract);
180: collectionAdditionalData[_collectionID].collectionCirculationSupply = collectionAdditionalData[_collectionID].collectionCirculationSupply + 1;
180: collectionAdditionalData[_collectionID].collectionCirculationSupply = collectionAdditionalData[_collectionID].collectionCirculationSupply + 1;
181: if (collectionAdditionalData[_collectionID].collectionTotalSupply >= collectionAdditionalData[_collectionID].collectionCirculationSupply) {
181: if (collectionAdditionalData[_collectionID].collectionTotalSupply >= collectionAdditionalData[_collectionID].collectionCirculationSupply) {
183: tokensAirdropPerAddress[_collectionID][_recipient] = tokensAirdropPerAddress[_collectionID][_recipient] + 1;
183: tokensAirdropPerAddress[_collectionID][_recipient] = tokensAirdropPerAddress[_collectionID][_recipient] + 1;
183: tokensAirdropPerAddress[_collectionID][_recipient] = tokensAirdropPerAddress[_collectionID][_recipient] + 1;
183: tokensAirdropPerAddress[_collectionID][_recipient] = tokensAirdropPerAddress[_collectionID][_recipient] + 1;
191: collectionAdditionalData[_collectionID].collectionCirculationSupply = collectionAdditionalData[_collectionID].collectionCirculationSupply + 1;
191: collectionAdditionalData[_collectionID].collectionCirculationSupply = collectionAdditionalData[_collectionID].collectionCirculationSupply + 1;
192: if (collectionAdditionalData[_collectionID].collectionTotalSupply >= collectionAdditionalData[_collectionID].collectionCirculationSupply) {
192: if (collectionAdditionalData[_collectionID].collectionTotalSupply >= collectionAdditionalData[_collectionID].collectionCirculationSupply) {
195: tokensMintedAllowlistAddress[_collectionID][_mintingAddress] = tokensMintedAllowlistAddress[_collectionID][_mintingAddress] + 1;
195: tokensMintedAllowlistAddress[_collectionID][_mintingAddress] = tokensMintedAllowlistAddress[_collectionID][_mintingAddress] + 1;
195: tokensMintedAllowlistAddress[_collectionID][_mintingAddress] = tokensMintedAllowlistAddress[_collectionID][_mintingAddress] + 1;
195: tokensMintedAllowlistAddress[_collectionID][_mintingAddress] = tokensMintedAllowlistAddress[_collectionID][_mintingAddress] + 1;
197: tokensMintedPerAddress[_collectionID][_mintingAddress] = tokensMintedPerAddress[_collectionID][_mintingAddress] + 1;
197: tokensMintedPerAddress[_collectionID][_mintingAddress] = tokensMintedPerAddress[_collectionID][_mintingAddress] + 1;
197: tokensMintedPerAddress[_collectionID][_mintingAddress] = tokensMintedPerAddress[_collectionID][_mintingAddress] + 1;
197: tokensMintedPerAddress[_collectionID][_mintingAddress] = tokensMintedPerAddress[_collectionID][_mintingAddress] + 1;
206: require ((_tokenId >= collectionAdditionalData[_collectionID].reservedMinTokensIndex) && (_tokenId <= collectionAdditionalData[_collectionID].reservedMaxTokensIndex), "id err");
206: require ((_tokenId >= collectionAdditionalData[_collectionID].reservedMinTokensIndex) && (_tokenId <= collectionAdditionalData[_collectionID].reservedMaxTokensIndex), "id err");
208: burnAmount[_collectionID] = burnAmount[_collectionID] + 1;
208: burnAmount[_collectionID] = burnAmount[_collectionID] + 1;
216: collectionAdditionalData[_mintCollectionID].collectionCirculationSupply = collectionAdditionalData[_mintCollectionID].collectionCirculationSupply + 1;
216: collectionAdditionalData[_mintCollectionID].collectionCirculationSupply = collectionAdditionalData[_mintCollectionID].collectionCirculationSupply + 1;
217: if (collectionAdditionalData[_mintCollectionID].collectionTotalSupply >= collectionAdditionalData[_mintCollectionID].collectionCirculationSupply) {
217: if (collectionAdditionalData[_mintCollectionID].collectionTotalSupply >= collectionAdditionalData[_mintCollectionID].collectionCirculationSupply) {
218: _mintProcessing(mintIndex, ownerOf(_tokenId), tokenData[_tokenId], _mintCollectionID, _saltfun_o);
221: burnAmount[_burnCollectionID] = burnAmount[_burnCollectionID] + 1;
221: burnAmount[_burnCollectionID] = burnAmount[_burnCollectionID] + 1;
228: tokenData[_mintIndex] = _tokenData;
229: collectionAdditionalData[_collectionID].randomizer.calculateTokenHash(_collectionID, _mintIndex, _saltfun_o);
230: tokenIdsToCollectionIds[_mintIndex] = _collectionID;
239: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false), "Not allowed");
239: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false), "Not allowed");
241: collectionInfo[_collectionID].collectionName = _newCollectionName;
242: collectionInfo[_collectionID].collectionArtist = _newCollectionArtist;
243: collectionInfo[_collectionID].collectionDescription = _newCollectionDescription;
244: collectionInfo[_collectionID].collectionWebsite = _newCollectionWebsite;
245: collectionInfo[_collectionID].collectionLicense = _newCollectionLicense;
246: collectionInfo[_collectionID].collectionLibrary = _newCollectionLibrary;
247: collectionInfo[_collectionID].collectionScript = _newCollectionScript;
249: collectionInfo[_collectionID].collectionBaseURI = _newCollectionBaseURI;
251: collectionInfo[_collectionID].collectionScript[_index] = _newCollectionScript[0];
251: collectionInfo[_collectionID].collectionScript[_index] = _newCollectionScript[0];
258: require(msg.sender == collectionAdditionalData[_collectionID].collectionArtistAddress, "Only artist");
259: require(artistSigned[_collectionID] == false, "Already Signed");
260: artistsSignatures[_collectionID] = _signature;
261: artistSigned[_collectionID] = true;
267: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false), "Not allowed");
267: require((isCollectionCreated[_collectionID] == true) && (collectionFreeze[_collectionID] == false), "Not allowed");
268: onchainMetadata[_collectionID] = _status;
274: require(collectionFreeze[tokenIdsToCollectionIds[_tokenId]] == false, "Data frozen");
274: require(collectionFreeze[tokenIdsToCollectionIds[_tokenId]] == false, "Data frozen");
276: tokenData[_tokenId] = newData;
283: require(collectionFreeze[tokenIdsToCollectionIds[_tokenId[x]]] == false, "Data frozen");
283: require(collectionFreeze[tokenIdsToCollectionIds[_tokenId[x]]] == false, "Data frozen");
283: require(collectionFreeze[tokenIdsToCollectionIds[_tokenId[x]]] == false, "Data frozen");
284: _requireMinted(_tokenId[x]);
285: tokenImageAndAttributes[_tokenId[x]][0] = _images[x];
285: tokenImageAndAttributes[_tokenId[x]][0] = _images[x];
285: tokenImageAndAttributes[_tokenId[x]][0] = _images[x];
286: tokenImageAndAttributes[_tokenId[x]][1] = _attributes[x];
286: tokenImageAndAttributes[_tokenId[x]][1] = _attributes[x];
286: tokenImageAndAttributes[_tokenId[x]][1] = _attributes[x];
293: require(isCollectionCreated[_collectionID] == true, "No Col");
294: collectionFreeze[_collectionID] = true;
300: require(msg.sender == collectionAdditionalData[_collectionID].randomizerContract);
301: require(tokenToHash[_mintIndex] == 0x0000000000000000000000000000000000000000000000000000000000000000);
302: tokenToHash[_mintIndex] = _hash;
308: require (block.timestamp > IMinterContract(minterContract).getEndTime(_collectionID) + collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint, "Time has not passed");
309: collectionAdditionalData[_collectionID].collectionTotalSupply = collectionAdditionalData[_collectionID].collectionCirculationSupply;
309: collectionAdditionalData[_collectionID].collectionTotalSupply = collectionAdditionalData[_collectionID].collectionCirculationSupply;
310: collectionAdditionalData[_collectionID].reservedMaxTokensIndex = (_collectionID * 10000000000) + collectionAdditionalData[_collectionID].collectionTotalSupply - 1;
310: collectionAdditionalData[_collectionID].reservedMaxTokensIndex = (_collectionID * 10000000000) + collectionAdditionalData[_collectionID].collectionTotalSupply - 1;
345: if (onchainMetadata[tokenIdsToCollectionIds[tokenId]] == false && tokenToHash[tokenId] != 0x0000000000000000000000000000000000000000000000000000000000000000) {
345: if (onchainMetadata[tokenIdsToCollectionIds[tokenId]] == false && tokenToHash[tokenId] != 0x0000000000000000000000000000000000000000000000000000000000000000) {
345: if (onchainMetadata[tokenIdsToCollectionIds[tokenId]] == false && tokenToHash[tokenId] != 0x0000000000000000000000000000000000000000000000000000000000000000) {
346: string memory baseURI = collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionBaseURI;
346: string memory baseURI = collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionBaseURI;
348: } else if (onchainMetadata[tokenIdsToCollectionIds[tokenId]] == false && tokenToHash[tokenId] == 0x0000000000000000000000000000000000000000000000000000000000000000) {
348: } else if (onchainMetadata[tokenIdsToCollectionIds[tokenId]] == false && tokenToHash[tokenId] == 0x0000000000000000000000000000000000000000000000000000000000000000) {
348: } else if (onchainMetadata[tokenIdsToCollectionIds[tokenId]] == false && tokenToHash[tokenId] == 0x0000000000000000000000000000000000000000000000000000000000000000) {
349: string memory baseURI = collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionBaseURI;
349: string memory baseURI = collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionBaseURI;
353: string memory b64 = Base64.encode(abi.encodePacked("<html><head></head><body><script src=\"",collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionLibrary,"\"></script><script>",retrieveGenerativeScript(tokenId),"</script></body></html>"));
353: string memory b64 = Base64.encode(abi.encodePacked("<html><head></head><body><script src=\"",collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionLibrary,"\"></script><script>",retrieveGenerativeScript(tokenId),"</script></body></html>"));
354: string memory _uri = string(abi.encodePacked("data:application/json;utf8,{\"name\":\"",getTokenName(tokenId),"\",\"description\":\"",collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionDescription,"\",\"image\":\"",tokenImageAndAttributes[tokenId][0],"\",\"attributes\":[",tokenImageAndAttributes[tokenId][1],"],\"animation_url\":\"data:text/html;base64,",b64,"\"}"));
354: string memory _uri = string(abi.encodePacked("data:application/json;utf8,{\"name\":\"",getTokenName(tokenId),"\",\"description\":\"",collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionDescription,"\",\"image\":\"",tokenImageAndAttributes[tokenId][0],"\",\"attributes\":[",tokenImageAndAttributes[tokenId][1],"],\"animation_url\":\"data:text/html;base64,",b64,"\"}"));
354: string memory _uri = string(abi.encodePacked("data:application/json;utf8,{\"name\":\"",getTokenName(tokenId),"\",\"description\":\"",collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionDescription,"\",\"image\":\"",tokenImageAndAttributes[tokenId][0],"\",\"attributes\":[",tokenImageAndAttributes[tokenId][1],"],\"animation_url\":\"data:text/html;base64,",b64,"\"}"));
354: string memory _uri = string(abi.encodePacked("data:application/json;utf8,{\"name\":\"",getTokenName(tokenId),"\",\"description\":\"",collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionDescription,"\",\"image\":\"",tokenImageAndAttributes[tokenId][0],"\",\"attributes\":[",tokenImageAndAttributes[tokenId][1],"],\"animation_url\":\"data:text/html;base64,",b64,"\"}"));
362: uint256 tok = tokenId - collectionAdditionalData[tokenIdsToCollectionIds[tokenId]].reservedMinTokensIndex;
362: uint256 tok = tokenId - collectionAdditionalData[tokenIdsToCollectionIds[tokenId]].reservedMinTokensIndex;
363: return string(abi.encodePacked(collectionInfo[viewColIDforTokenID(tokenId)].collectionName, " #" ,tok.toString()));
368: return collectionFreeze[_collectionID];
373: return(tokenIdsToCollectionIds[_tokenid]);
378: return wereDataAdded[_collectionID];
384: return(collectionAdditionalData[_collectionID].reservedMinTokensIndex);
390: return(collectionAdditionalData[_collectionID].reservedMaxTokensIndex);
395: return(collectionAdditionalData[_collectionID].collectionCirculationSupply);
400: return(collectionAdditionalData[_collectionID].maxCollectionPurchases);
405: return (tokensMintedAllowlistAddress[_collectionID][_address]);
405: return (tokensMintedAllowlistAddress[_collectionID][_address]);
410: return (tokensMintedPerAddress[_collectionID][_address]);
410: return (tokensMintedPerAddress[_collectionID][_address]);
416: return (tokensAirdropPerAddress[_collectionID][_address]);
416: return (tokensAirdropPerAddress[_collectionID][_address]);
421: return (collectionAdditionalData[_collectionID].collectionArtistAddress);
427: return (collectionInfo[_collectionID].collectionName, collectionInfo[_collectionID].collectionArtist, collectionInfo[_collectionID].collectionDescription, collectionInfo[_collectionID].collectionWebsite, collectionInfo[_collectionID].collectionLicense, collectionInfo[_collectionID].collectionBaseURI);
427: return (collectionInfo[_collectionID].collectionName, collectionInfo[_collectionID].collectionArtist, collectionInfo[_collectionID].collectionDescription, collectionInfo[_collectionID].collectionWebsite, collectionInfo[_collectionID].collectionLicense, collectionInfo[_collectionID].collectionBaseURI);
427: return (collectionInfo[_collectionID].collectionName, collectionInfo[_collectionID].collectionArtist, collectionInfo[_collectionID].collectionDescription, collectionInfo[_collectionID].collectionWebsite, collectionInfo[_collectionID].collectionLicense, collectionInfo[_collectionID].collectionBaseURI);
427: return (collectionInfo[_collectionID].collectionName, collectionInfo[_collectionID].collectionArtist, collectionInfo[_collectionID].collectionDescription, collectionInfo[_collectionID].collectionWebsite, collectionInfo[_collectionID].collectionLicense, collectionInfo[_collectionID].collectionBaseURI);
427: return (collectionInfo[_collectionID].collectionName, collectionInfo[_collectionID].collectionArtist, collectionInfo[_collectionID].collectionDescription, collectionInfo[_collectionID].collectionWebsite, collectionInfo[_collectionID].collectionLicense, collectionInfo[_collectionID].collectionBaseURI);
427: return (collectionInfo[_collectionID].collectionName, collectionInfo[_collectionID].collectionArtist, collectionInfo[_collectionID].collectionDescription, collectionInfo[_collectionID].collectionWebsite, collectionInfo[_collectionID].collectionLicense, collectionInfo[_collectionID].collectionBaseURI);
433: return (collectionInfo[_collectionID].collectionLibrary, collectionInfo[_collectionID].collectionScript);
433: return (collectionInfo[_collectionID].collectionLibrary, collectionInfo[_collectionID].collectionScript);
439: return (collectionAdditionalData[_collectionID].collectionArtistAddress, collectionAdditionalData[_collectionID].maxCollectionPurchases, collectionAdditionalData[_collectionID].collectionCirculationSupply, collectionAdditionalData[_collectionID].collectionTotalSupply, collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint, collectionAdditionalData[_collectionID].randomizerContract);
439: return (collectionAdditionalData[_collectionID].collectionArtistAddress, collectionAdditionalData[_collectionID].maxCollectionPurchases, collectionAdditionalData[_collectionID].collectionCirculationSupply, collectionAdditionalData[_collectionID].collectionTotalSupply, collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint, collectionAdditionalData[_collectionID].randomizerContract);
439: return (collectionAdditionalData[_collectionID].collectionArtistAddress, collectionAdditionalData[_collectionID].maxCollectionPurchases, collectionAdditionalData[_collectionID].collectionCirculationSupply, collectionAdditionalData[_collectionID].collectionTotalSupply, collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint, collectionAdditionalData[_collectionID].randomizerContract);
439: return (collectionAdditionalData[_collectionID].collectionArtistAddress, collectionAdditionalData[_collectionID].maxCollectionPurchases, collectionAdditionalData[_collectionID].collectionCirculationSupply, collectionAdditionalData[_collectionID].collectionTotalSupply, collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint, collectionAdditionalData[_collectionID].randomizerContract);
439: return (collectionAdditionalData[_collectionID].collectionArtistAddress, collectionAdditionalData[_collectionID].maxCollectionPurchases, collectionAdditionalData[_collectionID].collectionCirculationSupply, collectionAdditionalData[_collectionID].collectionTotalSupply, collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint, collectionAdditionalData[_collectionID].randomizerContract);
439: return (collectionAdditionalData[_collectionID].collectionArtistAddress, collectionAdditionalData[_collectionID].maxCollectionPurchases, collectionAdditionalData[_collectionID].collectionCirculationSupply, collectionAdditionalData[_collectionID].collectionTotalSupply, collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint, collectionAdditionalData[_collectionID].randomizerContract);
445: return (tokenToHash[_tokenid]);
453: for (uint256 i=0; i < collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionScript.length; i++) {
453: for (uint256 i=0; i < collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionScript.length; i++) {
454: scripttext = string(abi.encodePacked(scripttext, collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionScript[i]));
454: scripttext = string(abi.encodePacked(scripttext, collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionScript[i]));
454: scripttext = string(abi.encodePacked(scripttext, collectionInfo[tokenIdsToCollectionIds[tokenId]].collectionScript[i]));
456: return string(abi.encodePacked("let hash='",Strings.toHexString(uint256(tokenToHash[tokenId]), 32),"';let tokenId=",tokenId.toString(),";let tokenData=[",tokenData[tokenId],"];", scripttext));
456: return string(abi.encodePacked("let hash='",Strings.toHexString(uint256(tokenToHash[tokenId]), 32),"';let tokenId=",tokenId.toString(),";let tokenData=[",tokenData[tokenId],"];", scripttext));
462: return (collectionAdditionalData[_collectionID].collectionCirculationSupply - burnAmount[_collectionID]);
462: return (collectionAdditionalData[_collectionID].collectionCirculationSupply - burnAmount[_collectionID]);
468: return (tokenImageAndAttributes[_tokenId][0],tokenImageAndAttributes[_tokenId][1]);
468: return (tokenImageAndAttributes[_tokenId][0],tokenImageAndAttributes[_tokenId][1]);
[131, 132, 133, 134, 135, 136, 137, 138, 139, 148, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 163, 164, 172, 173, 180, 180, 181, 181, 183, 183, 183, 183, 191, 191, 192, 192, 195, 195, 195, 195, 197, 197, 197, 197, 206, 206, 208, 208, 216, 216, 217, 217, 218, 221, 221, 228, 229, 230, 239, 239, 241, 242, 243, 244, 245, 246, 247, 249, 251, 251, 258, 259, 260, 261, 267, 267, 268, 274, 274, 276, 283, 283, 283, 284, 285, 285, 285, 286, 286, 286, 293, 294, 300, 301, [302](ht
Note: Due to truncation, D-08 is being re-added below, in addition to the remaining contents of the winning bot report:
[D-08] Enum values should be used in place of constant array indexes
The following instances are not numbers and thus they are invalid.
There are 427 instances of this issue.
Expand findings
[60, 67, 69, 70, 70, 70, 70, 71, 71, 75, 75, 90, 91, 91, 91, 91, 95, 95, 96, 96, 105, 106, 110, 111, 111, 111, 111, 111, 111, 115, 115, 116, 116, 116, 116, 117, 117, 126, 126, 126, 126, 127, 127, 128, 128, 128, 128, 129, 129, 136, 137, 137, 137, 137, 138, 138, 139, 139, 139, 139, 140, 140, 148]
[159, 160, 161, 162, 163, 164, 165, 171, 172, 173, 174, 175, 176, 185, 187, 189, 189, 189, 197, 202, 202, 209, 209, 220, 221, 221, 238, 238, 240, 242, 244, 244, 246, 249, 252, 252, 252, 259, 259, 260, 260, 271, 271, 285, 287, 287, 289, 292, 295, 295, 295, 296, 297, 303, 310, 310, 318, 318, 319, 320, 321, 328, 328, 329, 339, 339, 340, 345, 345, 350, 351, 351, 364, 364, 372, 373, 374, 375, 381, 382, 383, 384, 385, 386, 387, 388, 389, 395, 396, 397, 398, 399, 400, 401, 402, 403, 409, 410, 416, 417, 418, 419, 420, 429, 430, 431, 434, 435, 436, 439, 440, 441, 471, 471, 477, 477, 477, 477, 477, 477, 477, 483, 483, 489, 489, 489, 489, 489, 489, 489, 495, 495, 495, 495, 495, 501, 501, 501, 501, 501, 501, 513, 519, 525, 532, 535, 536, 536, 536, 538, 540, 540, 540, 546, 546, 549, 550, 551, 551, 551, 551, 553, 553, 553, 554, 554, 556, 559, 562, 566]
[27, 32, 39, 45, 45, 52, 52, 52, 60, 60, 66, 72, 72, 78, 78]
[131, 132, 133, 134, 135, 136, 137, 138, 139, 148, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 163, 164, 172, 173, 180, 180, 181, 181, 183, 183, 183, 183, 191, 191, 192, 192, 195, 195, 195, 195, 197, 197, 197, 197, 206, 206, 208, 208, 216, 216, 217, 217, 218, 221, 221, 228, 229, 230, 239, 239, 241, 242, 243, 244, 245, 246, 247, 249, 251, 251, 258, 259, 260, 261, 267, 267, 268, 274, 274, 276, 283, 283, 283, 284, 285, 285, 285, 286, 286, 286, 293, 294, 300, 301, 302, 308, 309, 309, 310, 310, 345, 345, 345, 346, 346, 348, 348, 348, 349, 349, 353, 353, 354, 354, 354, 354, 362, 362, 363, 368, 373, 378, 384, 390, 395, 400, 405, 405, 410, 410, 416, 416, 421, 427, 427, 427, 427, 427, 427, 433, 433, 439, 439, 439, 439, 439, 439, 445, 453, 453, 454, 454, 454, 456, 456, 462, 462, 468, 468]
[43, 44, 49, 49, 49, 49, 55]
[61, 62, 66, 66, 66, 66, 73]
[29, 31]
[D-09] Time related variables should use time units instead of numbers
The following instances do not indicate time, or they already use time units, and thus they are invalid.
There are 4 instances of this issue.
[26, 27, 28, 29]
[D-10] Upgradeable contract is missing a constructor that disables initialization
The general rule is true, but the following instances are invalid.
There are 8 instances of this issue.
Expand findings
[18]
[20]
[15]
[22]
[18]
[18]
[19]
[13]
[D-11] Upgradeable contract is missing a gap storage variable
The general rule is true, but the following instances are invalid.
There are 8 instances of this issue.
Expand findings
[18]
[20]
[15]
[22]
[18]
[18]
[19]
[13]
[D-12]
selfbalance()
is cheaper thanaddress(this).balance
This issue is not valid, it's actually worse in gas usage. Proof
There are 2 instances of this issue.
[462]
[80]
[D-13] Initializers could be front-run
The general rule is true, but the following instances are invalid.
There are 2 instances of this issue.
[308, 315]
[D-14] Modifier order does not comply with best practices
The general rule is true, but every in-scope function follows the recommended order: