Tozzy NFT - Smart Contract Audit Report

Audit Summary

Tozzy NFT ($TFT) is a new protocol that allows users to purchase NFTs.

We reviewed the TestNft contract using code that was provided to us by the team.

Audit Findings

Please ensure trust in the team prior to investing as they have substantial control in the ecosystem.
Date: February 5th, 2022.

Finding #1 - TestNft - Low

Description: In the mintTokens() function, the transaction will revert if all of the NFTs reserved for Presale mode (5,555) have been minted, despite the maximum supply of 10,000 NFTs.
			
require(totalPreSaleReserved - _amount > 0, "Pre sale sold out");

Risk/Impact: Users will not be able to purchase NFTs if all of the NFTs reserved for Presale mode have been purchased.
Recommendation: The require statement above can be removed to properly enforce the maximum supply of 10,000 NFTs.

Finding #2 - TestNft - Low

Description: In the mintTokens() function, any excess ETH that is entered by the user will be accepted and sent to the project team.
			
require(msg.value >= _amount * itemPrice, "Try to send more ETH");

Risk/Impact: A user can mistakenly pay more in ETH than the actual cost per NFT.
Recommendation: The project team should require that the amount of ETH supplied is equal to the amount of ETH required to purchase each NFT.

Finding #3 - TestNft - Informational

Description: Although the SafeMath library is utilized, the contract is implemented with Solidity v0.8.x which has built-in overflow checks.
Recommendation: SafeMath could be safely removed to reduce contract size and deployment costs.

Contract Overview

  • The maximum supply is set to 10,000 NFTs.
  • There is a maximum number of 5,555 NFTs that can be purchased during Presale mode.
  • Any user can purchase up to 3 NFTs using ETH. The index of the NFT that is minted to the user is generated pseudo-randomly.
  • The randomness algorithm relies on some predictable variables that can be manipulated by miners to some extent.
  • The price per NFT is 0.3 ether. Users should exercise caution when supplying ETH to purchase NFTs and ensure that the exact amount is supplied as any excess ETH will not be returned to the user.
  • Whitelisted users can purchase up to 3 NFTs during Presale mode.
  • The owner can add accounts to the Presale whitelist at any time.
  • The owner can burn any user's purchased NFTs at any time.
  • The owner can pause all Standard NFT purchases and Presale NFT purchases at any time.
  • The owner can withdraw all of the ETH from the contract address at any time.
  • The owner can update the BaseURI of the contract at any time.
  • The logic is properly structured to prevent reentrancy attacks in applicable functions.
  • As the contract is implemented with Solidity v0.8.x it is protected from overflows/underflows.
  • The contract complies with the ERC-721 token standard.

External Threat Results

Vulnerability CategoryNotesResult
Arbitrary Storage WriteN/APASS
Arbitrary JumpN/APASS
Centralization of ControlThe owner can burn any user's purchased NFTs at any time.WARNING
Delegate Call to Untrusted ContractN/APASS
Dependence on Predictable VariablesDecisions are made based on the block.timestamp and block.difficulty environment variables that can be manipulated by a malicious miner. This is extremely unlikely to occur.WARNING
Deprecated OpcodesN/APASS
Ether ThiefN/APASS
ExceptionsN/APASS
External CallsN/APASS
Flash LoansN/APASS
Integer Over/UnderflowN/APASS
Logical IssuesIn the mintTokens() function, the transaction will revert if all of the NFTs reserved for Presale mode (5,555) have been minted, despite the maximum supply of 10,000 NFTs.WARNING
Multiple SendsN/APASS
OraclesN/APASS
SuicideN/APASS
State Change External CallsN/APASS
Unchecked RetvalN/APASS
User Supplied AssertionN/APASS
Critical Solidity CompilerN/APASS
Overall Contract Safety WARNING

Function Graph

BEP20 Token Graph

Inheritance Chart

Multi-file Token

Functions Overview

												
($) = payable function
 # = non-constant function

 + [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

 + [Int] IERC165 
    - [Ext] supportsInterface

 + [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

 + [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

 + [Lib] Strings 
    - [Int] toString
    - [Int] toHexString
    - [Int] toHexString

 +  ERC165 (IERC165)
    - [Pub] supportsInterface

 +  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 #
    - [Int] _afterTokenTransfer #

 +  TestNft (ERC721)
    - [Ext] mintTokens ($)
       - modifiers: tokensAvailable
    - [Ext] preSaleMint ($)
       - modifiers: tokensAvailable,preSaleStarted
    - [Int] _baseURI
    - [Pub] tokenURI
    - [Pub] tokensRemaining
    - [Ext] addToPreSaleList #
       - modifiers: onlyOwner
    - [Ext] setBaseURI #
       - modifiers: onlyOwner
    - [Ext] toggleSale #
       - modifiers: onlyOwner
    - [Ext] togglePreSale #
       - modifiers: onlyOwner
    - [Ext] toggleReveal #
       - modifiers: onlyOwner
    - [Ext] withdraw #
       - modifiers: onlyOwner
    - [Ext] burn #
       - modifiers: onlyOwner,validNFToken
    - [Int] randomIndex #