Aotaverse - Smart Contract Audit Report

Audit Summary

Aotaverse Audit Report Aotaverse ($AOTA) is a new protocol that allows users to purchase NFTs.

We reviewed the Aotaverse contract at commit 085cdce68aa4a962032668f88fe92a6bcf411d36 on the team's Github repository.

Audit Findings

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

Finding #1 - Aotaverse - Low

Description: Any excess ETH supplied to the contract during minting is not returned to the user.
Risk/Impact: Users will lose any excess funds sent as payment.
Recommendation: The contract should require the user supplies the exact amount of ETH needed to mint the desired amount of NFTs.

Finding #2 - Aotaverse - Informational

Description: Several functions are declared public, but are never called internally.
			
mint, mintForAddress, walletOfOwner, totalSupply, getMode, getCost, setMaxSupply, setSoftCap, togglemode, setRevealed, setCost, setUriPrefix, setPaused, withdraw
Recommendation: We recommend declaring these functions external for additional gas savings on each call.

Contract Overview

  • Upon deployment, the maximum supply is set to 25 NFTs and the soft cap is set to 18 NFTs.
  • The owner can update the maximum supply and soft cap to any values as long as their updated values are greater than their previous values.
  • The contract utilizes four modes that dictate the cost per NFT, how many NFTs a user can purchase, and who can purchase them.
  • Upon deployment, the mode of the contract will be set to 1. The owner can call the togglemode() function to advance to the next mode. The breakdown for each mode is as follows:
    • In mode 1, the cost per NFT is 0.01 ether, and only users that belong to the team's first whitelist can mint a maximum of 2 NFTs in total as long as the soft cap is not reached.
    • In mode 2, the cost per NFT is 0.02 ether, and only users that belong to the team's second whitelist can mint a maximum of 2 NFTs in total as long as the soft cap is not reached.
    • In mode 3, the cost per NFT is 0.03 ether, and any user can mint a maximum of 2 NFTs per transaction until the soft cap is reached.
    • In mode 4, the owner can mint NFTs to any user's wallet at no cost until the maximum supply has been reached.
  • The owner can update the current cost per NFT to any value at any time regardless of the current mode of the contract.
  • If all of the modes have been cycled through at least once, any user can mint NFTs in mode 1.
  • The contract uses an off-chain generated Merkle tree provided by the owner to store and verify addresses that are whitelisted for minting when in modes 1 and 2.
  • The user must provide a proof that can be used to verify against the Merkle tree to ensure that the user is indeed whitelisted.
  • 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.
  • The owner can pause the contract at any time which disables all minting functionality.
  • The owner can withdraw all of the ETH from the contract address at any time.
  • The owner can update the hidden URI and URI prefix of the contract at any time.
  • The proxy registry address is whitelisted to enable gas-free listings of all AOTA NFTs on OpenSea.
  • 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.
  • The contract utilizes ReentrancyGuard to prevent reentrancy attacks in applicable functions.

External Threat Results

Vulnerability CategoryNotesResult
Arbitrary Storage WriteN/APASS
Arbitrary JumpN/APASS
Centralization of Control
  • The owner can update the current cost per NFT to any value at any time regardless of the current mode of the contract.
  • The owner can pause the contract at any time which disables all minting functionality.
  • WARNING
    Delegate Call to Untrusted ContractN/APASS
    Dependence on Predictable VariablesN/APASS
    Deprecated OpcodesN/APASS
    Ether ThiefN/APASS
    ExceptionsN/APASS
    External CallsN/APASS
    Flash LoansN/APASS
    Integer Over/UnderflowN/APASS
    Logical IssuesN/APASS
    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 PASS

    Function Graph

    BEP20 Token Graph

    Inheritance Chart

    Multi-file Token

    Functions Overview

    												
    ($) = payable function
     # = non-constant function
    
     + [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 #
    
     + [Lib] Counters 
        - [Int] current
        - [Int] increment #
        - [Int] decrement #
        - [Int] reset #
    
     +  Ownable (Context)
        - [Pub]  #
        - [Pub] owner
        - [Pub] renounceOwnership #
           - modifiers: onlyOwner
        - [Pub] transferOwnership #
           - modifiers: onlyOwner
        - [Int] _transferOwnership #
    
     +  ReentrancyGuard 
        - [Pub]  #
    
     + [Lib] MerkleProof 
        - [Int] verify
        - [Int] processProof
        - [Prv] _efficientHash
    
     +  Aotaverse (ERC721, Ownable, ReentrancyGuard)
        - [Pub]  #
           - modifiers: ERC721,ReentrancyGuard
        - [Pub] mint ($)
           - modifiers: mintCompliance,nonReentrant
        - [Pub] mintForAddress #
           - modifiers: onlyOwner,nonReentrant
        - [Pub] walletOfOwner
        - [Pub] tokenURI
        - [Pub] totalSupply
        - [Pub] getMode
        - [Pub] getCost
        - [Pub] setMaxSupply #
           - modifiers: onlyOwner
        - [Pub] setSoftCap #
           - modifiers: onlyOwner
        - [Pub] togglemode #
           - modifiers: onlyOwner
        - [Pub] setRevealed #
           - modifiers: onlyOwner
        - [Pub] setCost #
           - modifiers: onlyOwner
        - [Pub] setHiddenMetadataUri #
           - modifiers: onlyOwner
        - [Pub] setUriPrefix #
           - modifiers: onlyOwner
        - [Pub] setPaused #
           - modifiers: onlyOwner
        - [Int] _mintLoop #
        - [Pub] withdraw ($)
           - modifiers: onlyOwner
        - [Pub] isApprovedForAll
    
     +  OwnableDelegateProxy 
    
     +  OpenSeaProxyRegistry