Aotaverse - Smart Contract Audit Report
Audit Summary
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.Recommendation: We recommend declaring these functions external for additional gas savings on each call.mint, mintForAddress, walletOfOwner, totalSupply, getMode, getCost, setMaxSupply, setSoftCap, togglemode, setRevealed, setCost, setUriPrefix, setPaused, withdraw
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 Category | Notes | Result |
---|---|---|
Arbitrary Storage Write | N/A | PASS |
Arbitrary Jump | N/A | PASS |
Centralization of Control | WARNING | |
Delegate Call to Untrusted Contract | N/A | PASS |
Dependence on Predictable Variables | N/A | PASS |
Deprecated Opcodes | N/A | PASS |
Ether Thief | N/A | PASS |
Exceptions | N/A | PASS |
External Calls | N/A | PASS |
Flash Loans | N/A | PASS |
Integer Over/Underflow | N/A | PASS |
Logical Issues | N/A | PASS |
Multiple Sends | N/A | PASS |
Oracles | N/A | PASS |
Suicide | N/A | PASS |
State Change External Calls | N/A | PASS |
Unchecked Retval | N/A | PASS |
User Supplied Assertion | N/A | PASS |
Critical Solidity Compiler | N/A | PASS |
Overall Contract Safety | PASS |
Function Graph
Inheritance Chart
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