VanityNFT - Smart Contract Audit Report

Summary

crypto_audit Vanity is releasing a new NFT based on user's wallet addresses and a new storage solution for tracking NFT transactions.

For this audit, we reviewed the VNYWrappedNFT, VNYStorage, and VNYPaymentHandler contracts provided to us by the team.

Notes on the Contracts:
VNYWrappedNFT Contract:
  • This contract is ERC721 compliant, all standard functionality is present.
  • Authorized users are able to mint VNYWrappedNFT NFTs up to the total mint limit. The total number of NFTs is initially capped at 500 NFTs.
  • Authorized users are able to unwrap any NFT they own resulting in the NFT being burned.
  • Users accumulate rewards in Vanity tokens. Users may manually claim rewards. Alternatively, gas can be provided to loop though all users and distribute rewards until the contract has used all of the provided gas.
  • Vanity tokens must be provided to fund rewards. If there are not enough tokens, reward claims will fail.
  • The owner is able to set the mint limit to any value at any time.
  • The owner is able to withdraw any ERC20 token in the contract at any time.
  • The owner is able to grant or revoke authorization for any address at any time.
  • Use of SafeMath to prevent overflow/underflow.
VNYStorage Contract:
  • This contract is used to record information about NFT transactions and ownership.
  • Authorized addresses can create and update records.
  • The owner may toggle authorization for any address at any time.
  • As the contract is implemented with Solidity v0.8.x, it is protected from overflows/underflows.
VNYPaymentHandler Contract:
  • This contract is used to manage payment for NFTs and route payment and dividends accordingly.
  • NFTs are purchased using a combination of the fee token, which is set upon deployment, and BNB.
  • The team should exercise caution when choosing the fee token as to not use fee-on-transfer tokens.
  • There is a burn fee, royalty fee, and LP fee when buying NFTs.
  • The fee token used in the purchase is sent to the 0x...dead address lowering the circulating supply of the fee tokens.
  • The LP fee is taken from the BNB used to purchase the NFT, and subsequently used to add liquidity in the BNB-fee token pair.
  • A liquidity-add is funded by selling half of the BNB collected as liquidity fees, pairing the received fee token with the remaining BNB, and adding it as liquidity to the BNB pair.
  • The dev fee is also taken from the BNB, and sent to the dev address controlled by the team.
  • The royalty fee is taken from the remaining BNB and distributed as rewards to NFT holders through a DividendTracker.
  • All of the remaining BNB is retained in the contract for the owner to buyback fee tokens.
  • Users can buy either a wrapped or unwrapped NFT.
  • Both wrapped and unwrapped NFTs have a price per character in BNB and fee token. Users must supply the correct amount of BNB and fee token in order to purchase an NFT.
  • The price for wrapped and unwrapped NFTs is seperate and may vary between the two.
  • Buying an unwrapped NFT will create a record, through the Storage contract, that the user has purchased the NFT.
  • Buying a wrapped NFT will mint a new NFT to the user.
  • Users may unwrap any of their wrapped NFTs. This will burn the corresponding NFT and create a record, through the Storage contract, that the NFT is now unwrapped.
  • The owner may buyback fee tokens from the liquidity pool at any time. We recommend that the team pass the allowed slippage as a parameter to prevent price manipulation.
  • The owner may update the cost per character at any time.
  • The owner may update the implementation of the Storage and NFT contracts at anytime.
  • The owner may update the amount of fees and the dev wallet address at anytime.
  • As the contract is implemented with Solidity v0.8.x, it is protected from overflows/underflows.
Audit Findings Summary
  • No external threats were identified.
  • Ensure trust in the team as they have significant control within the ecosystem.
  • Date: November 24th, 2021.

Audit Results

Vulnerability CategoryNotesResult
Arbitrary Storage WriteN/APASS
Arbitrary JumpN/APASS
Centralization of ControlThe team retains control of ownership functions described above.PASS
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
Multiple SendsN/APASS
OraclesN/APASS
SuicideN/APASS
State Change External CallsN/APASS
Unbounded LoopsN/APASS
Unchecked RetvalN/APASS
User Supplied AssertionN/APASS
Critical Solidity CompilerN/APASS
Overall Contract Safety PASS

VNYWrappedNFT Contract

smart_contract_audit_company

token_audit


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

 +  Context 
    - [Int] _msgSender
    - [Int] _msgData

 + [Int] IERC20 
    - [Ext] totalSupply
    - [Ext] balanceOf
    - [Ext] transfer #
    - [Ext] allowance
    - [Ext] approve #
    - [Ext] transferFrom #

 + [Lib] SafeERC20 
    - [Int] safeTransfer #
    - [Int] safeTransferFrom #
    - [Int] safeApprove #
    - [Int] safeIncreaseAllowance #
    - [Int] safeDecreaseAllowance #
    - [Prv] callOptionalReturn #

 + [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] IERC721Metadata (IERC721)
    - [Ext] name
    - [Ext] symbol
    - [Ext] tokenURI

 + [Int] IERC721Enumerable (IERC721)
    - [Ext] totalSupply
    - [Ext] tokenOfOwnerByIndex
    - [Ext] tokenByIndex

 + [Int] IERC721Receiver 
    - [Ext] onERC721Received #

 +  ERC165 (IERC165)
    - [Int] Constructor #
    - [Pub] supportsInterface
    - [Int] _registerInterface #

 + [Lib] SafeMath 
    - [Int] add
    - [Int] sub
    - [Int] sub
    - [Int] mul
    - [Int] div
    - [Int] div
    - [Int] mod
    - [Int] mod

 + [Lib] Address 
    - [Int] isContract
    - [Int] sendValue #
    - [Int] functionCall #
    - [Int] functionCall #
    - [Int] functionCallWithValue #
    - [Int] functionCallWithValue #
    - [Prv] _functionCallWithValue #

 + [Lib] EnumerableSet 
    - [Prv] _add #
    - [Prv] _remove #
    - [Prv] _contains
    - [Prv] _length
    - [Prv] _at
    - [Int] add #
    - [Int] remove #
    - [Int] contains
    - [Int] length
    - [Int] at
    - [Int] add #
    - [Int] remove #
    - [Int] contains
    - [Int] length
    - [Int] at

 + [Lib] EnumerableMap 
    - [Prv] _set #
    - [Prv] _remove #
    - [Prv] _contains
    - [Prv] _length
    - [Prv] _at
    - [Prv] _get
    - [Prv] _get
    - [Int] set #
    - [Int] remove #
    - [Int] contains
    - [Int] length
    - [Int] at
    - [Int] get
    - [Int] get

 + [Lib] Strings 
    - [Int] toString

 +  ERC721 (Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable)
    - [Pub] Constructor #
    - [Pub] balanceOf
    - [Pub] ownerOf
    - [Pub] name
    - [Pub] symbol
    - [Pub] tokenURI
    - [Pub] baseURI
    - [Pub] tokenOfOwnerByIndex
    - [Pub] totalSupply
    - [Pub] tokenByIndex
    - [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] _setTokenURI #
    - [Pub] _setBaseURI #
    - [Prv] _checkOnERC721Received #
    - [Prv] _approve #
    - [Int] _beforeTokenTransfer #

 + [Lib] Counters 
    - [Int] current
    - [Int] increment #
    - [Int] decrement #

 +  Ownable (Context)
    - [Int] Constructor #
    - [Pub] owner
    - [Pub] renounceOwnership #
       - modifiers: onlyOwner
    - [Pub] transferOwnership #
       - modifiers: onlyOwner

 +  VNYWrappedNFT (ERC721, Ownable)
    - [Pub] Constructor #
       - modifiers: ERC721
    - [Ext] Fallback ($)
    - [Ext] setAuthorized #
       - modifiers: onlyOwner
    - [Ext] mintNFT #
    - [Ext] unwrapNFT #
    - [Int] _transfer #
    - [Ext] withdrawErrantTokens #
       - modifiers: onlyOwner
    - [Ext] claim #

 + [Int] DividendPayingTokenOptionalInterface 
    - [Ext] withdrawableDividendOf
    - [Ext] withdrawnDividendOf
    - [Ext] accumulativeDividendOf

 + [Int] DividendPayingTokenInterface 
    - [Ext] dividendOf
    - [Ext] distributeDividends #
    - [Ext] withdrawDividend #

 + [Lib] SafeMathInt 
    - [Int] mul
    - [Int] div
    - [Int] sub
    - [Int] add
    - [Int] abs
    - [Int] toUint256Safe

 + [Lib] SafeMathUint 
    - [Int] toInt256Safe

 +  DividendPayingToken (DividendPayingTokenInterface, DividendPayingTokenOptionalInterface, Ownable)
    - [Pub] Constructor #
    - [Ext] Fallback ($)
    - [Ext] distributeDividends #
       - modifiers: onlyOwner
    - [Ext] withdrawDividend #
    - [Int] _withdrawDividendOfUser #
    - [Ext] dividendOf
    - [Pub] withdrawableDividendOf
    - [Ext] withdrawnDividendOf
    - [Pub] accumulativeDividendOf
    - [Int] _increase #
    - [Int] _reduce #
    - [Int] _setBalance #

 + [Lib] IterableMapping 
    - [Pub] get
    - [Pub] getIndexOfKey
    - [Pub] getKeyAtIndex
    - [Pub] size
    - [Pub] set #
    - [Pub] remove #

 +  DividendTracker (DividendPayingToken)
    - [Pub] Constructor #
    - [Ext] getLastProcessedIndex
    - [Ext] getNumberOfTokenHolders
    - [Pub] getAccount
    - [Ext] getAccountAtIndex
    - [Prv] canAutoClaim
    - [Ext] setBalance #
       - modifiers: onlyOwner
    - [Ext] process #
    - [Pub] processAccount #
       - modifiers: onlyOwner

							

VNYStorage Contract

smart_contract_audit_company

token_audit


 ($) = 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

 +  Ownable (Context)
    - [Pub] Constructor #
    - [Pub] owner
    - [Pub] renounceOwnership #
       - modifiers: onlyOwner
    - [Pub] transferOwnership #
       - modifiers: onlyOwner
    - [Prv] _setOwner #

 +  VNYStorage (Ownable)
    - [Pub] Constructor #
    - [Ext] createNewRecord #
    - [Ext] updateRecord #
    - [Ext] updateAuthorized #
       - modifiers: onlyOwner

							

VNYPaymentHandler Contract

smart_contract_audit_company

token_audit


 ($) = 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] IERC20 
    - [Ext] totalSupply
    - [Ext] balanceOf
    - [Ext] transfer #
    - [Ext] allowance
    - [Ext] approve #
    - [Ext] transferFrom #

 + [Int] IERC20Metadata (IERC20)
    - [Ext] name
    - [Ext] symbol
    - [Ext] decimals

 +  ERC20 (Context, IERC20, IERC20Metadata)
    - [Pub] Constructor #
    - [Pub] name
    - [Pub] symbol
    - [Pub] decimals
    - [Pub] totalSupply
    - [Pub] balanceOf
    - [Pub] transfer #
    - [Pub] allowance
    - [Pub] approve #
    - [Pub] transferFrom #
    - [Pub] increaseAllowance #
    - [Pub] decreaseAllowance #
    - [Int] _transfer #
    - [Int] _mint #
    - [Int] _burn #
    - [Int] _approve #
    - [Int] _beforeTokenTransfer #
    - [Int] _afterTokenTransfer #

 + [Lib] SafeERC20 
    - [Int] safeTransfer #
    - [Int] safeTransferFrom #
    - [Int] safeApprove #
    - [Int] safeIncreaseAllowance #
    - [Int] safeDecreaseAllowance #
    - [Prv] _callOptionalReturn #

 +  ERC20Burnable (Context, ERC20)
    - [Pub] burn #
    - [Pub] burnFrom #

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

 +  ReentrancyGuard 
    - [Pub] Constructor #

 +  Ownable (Context)
    - [Pub] Constructor #
    - [Pub] owner
    - [Pub] renounceOwnership #
       - modifiers: onlyOwner
    - [Pub] transferOwnership #
       - modifiers: onlyOwner
    - [Prv] _setOwner #

 + [Int] IPancakeSwapV2Router02 
    - [Ext] swapExactTokensForETHSupportingFeeOnTransferTokens #
    - [Ext] swapExactETHForTokensSupportingFeeOnTransferTokens ($)
    - [Ext] factory
    - [Ext] WETH
    - [Ext] addLiquidityETH ($)

 + [Int] VNYStorage 
    - [Ext] createNewRecord #
    - [Ext] updateRecord #

 + [Int] VNYNFT 
    - [Ext] mintNFT #
    - [Ext] unwrapNFT #
    - [Ext] ownerOf
    - [Ext] distributeDivs #

 +  VNYPaymentHandler (Ownable, ReentrancyGuard)
    - [Pub] Constructor #
    - [Ext] setCostPerCharacter #
       - modifiers: onlyOwner
    - [Pub] quote
    - [Ext] payUnwrapped #
    - [Ext] payWrapped #
    - [Ext] unwrapNFT #
    - [Ext] setVnyStorageAddress #
       - modifiers: onlyOwner
    - [Ext] setVnyNFTAddress #
       - modifiers: onlyOwner
    - [Prv] swapETHForTokens #
    - [Ext] buyback #
       - modifiers: onlyOwner
    - [Ext] setContractWallet #
       - modifiers: onlyOwner
    - [Ext] setBurnPercent #
       - modifiers: onlyOwner
    - [Ext] setDivider #
       - modifiers: onlyOwner
    - [Ext] Fallback ($)