CouncilOfKingz NFT - Smart Contract Audit Report
CouncilOfKingz is a new NFT collection with a presale and public sale format.
For this audit, we reviewed the CouncilOfKingz contract provided to us by the project team.
Please ensure trust in the team prior to investing as they have notable control in the ecosystem.
Date: January 23th, 2022.
Updated: January 24th, 2022 to address resolved issues and changes by the team.
- The CouncilOfKingz contract is used to facilitate a presale and a public sale for the CouncilOfKingz NFTs.
- The maximum total supply of CouncilOfKingz NFTs is 7,777, of which 100 are minted to the owner on deployment.
- While the presale is active, eligible users can each purchase up to 5 NFTs until the maximum total supply has been reached.
- The contract uses an off-chain generated Merkle tree provided by the owner to store and verify addresses that are eligible to mint during the presale.
- While the public sale is active, users can each purchase up to 5 NFTs per transaction until the maximum total supply or the maximum wallet limit has been reached.
- CouncilOfKingz NFT presale and public sale prices are set separately; the presale price is 0.13 ETH while the public sale price is 0.15 ETH.
- In the event that the address receiving an NFT is a contract, the contract must have implemented the onERC721Received() function in order to successfully receive the NFT.
- The base URI value is set on deployment, but is not meant to be the final base URI. This is intended so that users will not know which CouncilOfKingz NFT they have received until the true base URI is "revealed".
- The contract will only accept the correct amount of ETH that is required for the specified amount of NFTs to be purchased.
- The owner can withdraw all funds from the contract at any time.
- The owner can mint NFTs while the contract is not paused and the maximum supply limit has not been reached.
- The owner can toggle the presale and public sale at any time.
- The owner can pause the contract at any time which disables all minting functionality.
- The owner can enable burn functionality at any time; once it is enabled it cannot be disabled.
- The owner can set the maximum burn limit to any value at any time.
- The owner can reveal the token URIs at any time.
- The owner can set the root of the Merkle tree at any time, effectively controlling the presale whitelist.
- The owner can set the hidden URI, base URI, and base extension at any time.
- This contract complies with the ERC-721 standard.
- As the contract is developed with Solidity 0.8.x, it is protected from overflow/underflow attacks.
Finding #1 - CouncilOfKingz - InformationalDescription: Several functions are declared public, but are never called internally. Several state variables can never be modified, but are not declared constant.Recommendation: We recommend declaring these functions external and declaring these state variables constant for additional gas savings on each call.
Functions: totalSupply, publicMint, presaleMint, ownerMint, walletOfOwner, contractURI, burn, publicSaleStart, reveal, enableBurn, setmaxMintAmount, setMaxTokensPerWalletPresale, setMaxTokensPerWallet, setCostPublicSale, setCostPresale, setTotalBurnTokens, setBaseExtension State Variables: marketingWallet, totalTokens
Resolution: The team has declared these functions as external, removed the marketingWallet variable and declared the totalTokens variable as constant.
External Threat Results
|Arbitrary Storage Write||N/A||PASS|
|Centralization of Control||N/A||PASS|
|Delegate Call to Untrusted Contract||N/A||PASS|
|Dependence on Predictable Variables||N/A||PASS|
|State Change External Calls||N/A||PASS|
|User Supplied Assertion||N/A||PASS|
|Critical Solidity Compiler||N/A||PASS|
|Overall Contract Safety||PASS|
($) = payable function # = non-constant function + [Lib] Address - [Int] isContract - [Int] sendValue # - [Int] functionCall # - [Int] functionCall # - [Int] functionCallWithValue # - [Int] functionCallWithValue # - [Int] functionStaticCall - [Int] functionStaticCall - [Int] functionDelegateCall # - [Int] functionDelegateCall # - [Int] verifyCallResult + Context - [Int] _msgSender - [Int] _msgData + [Int] IERC165 - [Ext] supportsInterface + ERC165 (IERC165) - [Pub] supportsInterface + [Lib] MerkleProof - [Int] verify - [Int] processProof + [Lib] Strings - [Int] toString - [Int] toHexString - [Int] toHexString + [Lib] SafeMath - [Int] tryAdd - [Int] trySub - [Int] tryMul - [Int] tryDiv - [Int] tryMod - [Int] add - [Int] sub - [Int] mul - [Int] div - [Int] mod - [Int] sub - [Int] div - [Int] mod + Ownable (Context) - [Pub]
# - [Pub] owner - [Pub] renounceOwnership # - modifiers: onlyOwner - [Pub] transferOwnership # - modifiers: onlyOwner - [Int] _transferOwnership # + [Int] IERC721 (IERC165) - [Ext] balanceOf - [Ext] ownerOf - [Ext] safeTransferFrom # - [Ext] transferFrom # - [Ext] approve # - [Ext] getApproved - [Ext] setApprovalForAll # - [Ext] isApprovedForAll - [Ext] safeTransferFrom # + [Int] IERC721Receiver - [Ext] onERC721Received # + [Int] IERC721Metadata (IERC721) - [Ext] name - [Ext] symbol - [Ext] tokenURI + ERC721 (Context, ERC165, IERC721, IERC721Metadata) - [Pub] # - [Pub] supportsInterface - [Pub] balanceOf - [Pub] ownerOf - [Pub] name - [Pub] symbol - [Pub] tokenURI - [Int] _baseURI - [Pub] approve # - [Pub] getApproved - [Pub] setApprovalForAll # - [Pub] isApprovedForAll - [Pub] transferFrom # - [Pub] safeTransferFrom # - [Pub] safeTransferFrom # - [Int] _safeTransfer # - [Int] _exists - [Int] _isApprovedOrOwner - [Int] _safeMint # - [Int] _safeMint # - [Int] _mint # - [Int] _burn # - [Int] _transfer # - [Int] _approve # - [Int] _setApprovalForAll # - [Prv] _checkOnERC721Received # - [Int] _beforeTokenTransfer # + CouncilOfKingz (ERC721, Ownable) - [Pub] # - modifiers: ERC721 - [Ext] totalSupply - [Pub] totalBurned - [Pub] totalMinted - [Ext] publicMint ($) - modifiers: onlyAllowValidCountAndActiveSale - [Ext] presaleMint ($) - modifiers: onlyAllowValidCountAndActiveSale - [Ext] ownerMint # - modifiers: onlyOwner,onlyAllowValidCountAndActiveSale - [Prv] _mintNFT # - [Prv] _getTokenToBeMinted # - [Prv] _getRandomNumber - [Ext] walletOfOwner - [Ext] contractURI - [Int] _baseURI - [Pub] tokenURI - [Ext] burn # - [Ext] flipSaleState # - modifiers: onlyOwner - [Ext] publicSaleStart # - modifiers: onlyOwner - [Ext] reveal # - modifiers: onlyOwner - [Ext] enableBurn # - modifiers: onlyOwner - [Ext] setCostPublicSale # - modifiers: onlyOwner - [Ext] setCostPresale # - modifiers: onlyOwner - [Ext] setTotalBurnTokens # - modifiers: onlyOwner - [Pub] setContractURI # - modifiers: onlyOwner - [Pub] setNotRevealedURI # - modifiers: onlyOwner - [Pub] setCurrentBaseURI # - modifiers: onlyOwner - [Ext] setBaseExtension # - modifiers: onlyOwner - [Ext] setPresaleListEnabled # - modifiers: onlyOwner - [Ext] setMerkleRoot # - modifiers: onlyOwner - [Pub] withdraw ($) - modifiers: onlyOwner - [Ext] Fallback ($) - [Ext] Receive Ether ($)