Eden Gallery V2 - Smart Contract Audit Report

Audit Summary

Eden Gallery is creating new NFT collections with purchases verified using a Merkle tree.

For this audit, we reviewed Eden Gallery's MintableERC721, MintableSale, Eagles, and FounderKeys contracts using code provided by the project team.

Audit Findings

Please ensure trust in the team prior to investing as they have substantial control in the ecosystem. Off-chain logic is used to authorize users to participate in the sale via a Merkle tree.
Date: Febuary 3rd, 2022.

Finding #1 - MintableSale & FounderKeys - Informational

Description: The following functions are declared public, but are never called internally:
			
MintableSale.buy(), MintableSale.buyTo(), FounderKeys.withdrawTo().

Recommendation: These functions can be declared external for additional gas savings on each call.

Contracts Overview

MintableERC721 & Eagles Contracts:
  • This MintableERC721 contract implements the below functionality; the Eagles contract inherits the MintableERC721 contract but does not provide any additional functionality.
  • The owner of the MintableERC721 contract is given the Default Admin Role, Minter Role, and URI Manager Role upon deployment.
  • Any role can grant or revoke their role from another address at any time.
  • Any URI Manager can update the base URI at any time.
  • Any Minter can mint tokens to any address at any time.
  • No burning functionality is present; however, users can transfer their tokens to the 0x..dead address to reduce circulating supply, if desired.
  • Users cannot purchase tokens through this contract.
MintableSale Contract:
  • This contract allows authorized users to use ETH to purchase a specified supported ERC-721 token.
  • The owner can initialize a new sale at any time, updating the Merkle root, mint limit, batch limit, next token ID to be minted, and the last ID that can be minted.
  • The owner will also specify if the sale is public.
  • Contracts are not permitted to purchase tokens if the sale is public.
  • When purchasing, the user must specify a price, start time, end time, number of tokens to purchase, and a Merkle proof.
  • The user address, price, start time, and end time are hashed and verified with the passed Merkle proof against the contract's Merkle root.
  • The time of purchase must be between within the verified start and end times.
  • Users can purchase one or more tokens in a single call.
  • When buying in batches, the user's amount to purchase cannot exceed the contract's "batch limit".
  • In addition, a user's total number of purchases per sale cannot exceed the contract's mint limit.
  • Any excess ETH sent will be returned to the purchaser.
  • This contract inherits the PaymentSplitter contract, allowing certain users to withdraw portions of tokens or ETH from the contract based on their shares.
FounderKeys Contract:
  • This ERC-1155 token contract allows users to purchase tokens by registering for a waitlist.
  • The owner is given the Admin role and Waitlister role upon deployment.
  • Any role can grant or revoke their role from another address at any time.
  • The maximum supply of the token is 1,111.
  • In order to purchase a token, the user must register to the waitlist by paying a mint price of 1.12 ETH.
  • Any excess ETH sent will be returned to the user.
  • After registering, any Waitlister has the ability to approve or reject the user.
  • If rejected, the user's payment is returned to them.
  • If approved, the user is minted a token.
  • The owner can update the token URI at any time.
  • The owner can withdraw any ETH from the contract at any time.

External Threat Results

Vulnerability CategoryNotesResult
Arbitrary Storage WriteN/APASS
Arbitrary JumpN/APASS
Centralization of Control
  • The owner and defined roles have the permissions mentioned above.
  • A Minter can mint MintableERC721 tokens to any address at any time.
  • Off-chain logic is used to keep track of users authorized to participate in sales by use of a Merkle tree.
  • 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
    Unbounded LoopN/APASS
    Unchecked RetvalN/APASS
    User Supplied AssertionN/APASS
    Critical Solidity CompilerN/APASS
    Overall Contract Safety PASS


    Details: MintableSale Contract

    ERC20 Token Graph

    Multi-file Token

    												
    ($) = payable function
     # = non-constant function
    
      +  Context 
        - [Int] _msgSender
        - [Int] _msgData
    
     +  Ownable (Context)
        - [Pub]  #
        - [Pub] owner
        - [Pub] renounceOwnership #
           - modifiers: onlyOwner
        - [Pub] transferOwnership #
           - modifiers: onlyOwner
        - [Int] _transferOwnership #
    
     + [Lib] MerkleProof 
        - [Int] verify
        - [Int] processProof
    
     + [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] IERC20 
        - [Ext] totalSupply
        - [Ext] balanceOf
        - [Ext] transfer #
        - [Ext] allowance
        - [Ext] approve #
        - [Ext] transferFrom #
    
     + [Lib] Address 
        - [Int] isContract
        - [Int] sendValue #
        - [Int] functionCall #
        - [Int] functionCall #
        - [Int] functionCallWithValue #
        - [Int] functionCallWithValue #
        - [Int] functionStaticCall
        - [Int] functionStaticCall
        - [Int] functionDelegateCall #
        - [Int] functionDelegateCall #
        - [Int] verifyCallResult
    
     + [Lib] SafeERC20 
        - [Int] safeTransfer #
        - [Int] safeTransferFrom #
        - [Int] safeApprove #
        - [Int] safeIncreaseAllowance #
        - [Int] safeDecreaseAllowance #
        - [Prv] _callOptionalReturn #
    
     +  PaymentSplitter (Context)
        - [Pub]  ($)
        - [Ext]  ($)
        - [Pub] totalShares
        - [Pub] totalReleased
        - [Pub] totalReleased
        - [Pub] shares
        - [Pub] released
        - [Pub] released
        - [Pub] payee
        - [Pub] release #
        - [Pub] release #
        - [Prv] _pendingPayment
        - [Prv] _addPayee #
    
     +  ReentrancyGuard 
        - [Pub]  #
    
     + [Int] IMintableERC721 
        - [Ext] exists
        - [Ext] mint #
        - [Ext] mintBatch #
        - [Ext] safeMint #
        - [Ext] safeMint #
        - [Ext] safeMintBatch #
        - [Ext] safeMintBatch #
    
     +  MintableSale (Ownable, PaymentSplitter, ReentrancyGuard)
        - [Pub]  #
           - modifiers: PaymentSplitter
        - [Pub] itemsOnSale
        - [Pub] itemsAvailable
        - [Pub] isActive
        - [Pub] initialize #
           - modifiers: onlyOwner
        - [Pub] buy ($)
        - [Pub] buyTo ($)
           - modifiers: nonReentrant
        - [Pub] buySingle ($)
        - [Pub] buySingleTo ($)
           - modifiers: nonReentrant
        - [Int] buildLeaf
    
    
     

    Details: Eagles Contract

    ERC20 Token Graph

    Multi-file Token

    												
    ($) = payable function
     # = non-constant function
    
    
        - [Int] toString
        - [Int] toHexString
        - [Int] toHexString
    
     + [Int] IERC165 
        - [Ext] supportsInterface
    
     +  ERC165 (IERC165)
        - [Pub] supportsInterface
    
     +  AccessControl (Context, IAccessControl, ERC165)
        - [Pub] supportsInterface
        - [Pub] hasRole
        - [Int] _checkRole
        - [Pub] getRoleAdmin
        - [Pub] grantRole #
           - modifiers: onlyRole
        - [Pub] revokeRole #
           - modifiers: onlyRole
        - [Pub] renounceRole #
        - [Int] _setupRole #
        - [Int] _setRoleAdmin #
        - [Int] _grantRole #
        - [Int] _revokeRole #
    
     +  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
    
     + [Lib] Address 
        - [Int] isContract
        - [Int] sendValue #
        - [Int] functionCall #
        - [Int] functionCall #
        - [Int] functionCallWithValue #
        - [Int] functionCallWithValue #
        - [Int] functionStaticCall
        - [Int] functionStaticCall
        - [Int] functionDelegateCall #
        - [Int] functionDelegateCall #
        - [Int] verifyCallResult
    
     +  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] IMintableERC721 
        - [Ext] exists
        - [Ext] mint #
        - [Ext] mintBatch #
        - [Ext] safeMint #
        - [Ext] safeMint #
        - [Ext] safeMintBatch #
        - [Ext] safeMintBatch #
    
     +  MintableERC721 (ERC721, IMintableERC721, AccessControl, Ownable)
        - [Pub]  #
           - modifiers: ERC721
        - [Int] _baseURI
        - [Pub] tokenURI
        - [Ext] setBaseURI #
           - modifiers: onlyRole
        - [Ext] exists
        - [Pub] mint #
           - modifiers: onlyRole
        - [Pub] mintBatch #
           - modifiers: onlyRole
        - [Pub] safeMint #
           - modifiers: onlyRole
        - [Pub] safeMint #
        - [Pub] safeMintBatch #
        - [Ext] safeMintBatch #
        - [Pub] supportsInterface
        - [Pub] walletOfOwner
        - [Pub] tokenOfOwnerByIndex
        - [Prv] _addTokenToOwnerEnumeration #
        - [Prv] _removeTokenFromOwnerEnumeration #
        - [Int] _beforeTokenTransfer #
    
     +  Eagles (MintableERC721)
        - [Pub]  #
           - modifiers: MintableERC721
    
    
    
     
     

    Details: FounderKeys Contract

    ERC20 Token Graph

    Multi-file Token

    												
    ($) = payable function
     # = non-constant function
    
     
     + [Int] IERC165 
        - [Ext] supportsInterface
    
     + [Int] IERC1155 (IERC165)
        - [Ext] balanceOf
        - [Ext] balanceOfBatch
        - [Ext] setApprovalForAll #
        - [Ext] isApprovedForAll
        - [Ext] safeTransferFrom #
        - [Ext] safeBatchTransferFrom #
    
     + [Int] IERC1155Receiver (IERC165)
        - [Ext] onERC1155Received #
        - [Ext] onERC1155BatchReceived #
    
     + [Int] IERC1155MetadataURI (IERC1155)
        - [Ext] uri
    
     + [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
    
     +  ERC165 (IERC165)
        - [Pub] supportsInterface
    
     +  ERC1155 (Context, ERC165, IERC1155, IERC1155MetadataURI)
        - [Pub]  #
        - [Pub] supportsInterface
        - [Pub] uri
        - [Pub] balanceOf
        - [Pub] balanceOfBatch
        - [Pub] setApprovalForAll #
        - [Pub] isApprovedForAll
        - [Pub] safeTransferFrom #
        - [Pub] safeBatchTransferFrom #
        - [Int] _safeTransferFrom #
        - [Int] _safeBatchTransferFrom #
        - [Int] _setURI #
        - [Int] _mint #
        - [Int] _mintBatch #
        - [Int] _burn #
        - [Int] _burnBatch #
        - [Int] _setApprovalForAll #
        - [Int] _beforeTokenTransfer #
        - [Prv] _doSafeTransferAcceptanceCheck #
        - [Prv] _doSafeBatchTransferAcceptanceCheck #
        - [Prv] _asSingletonArray
    
     +  Ownable (Context)
        - [Pub]  #
        - [Pub] owner
        - [Pub] renounceOwnership #
           - modifiers: onlyOwner
        - [Pub] transferOwnership #
           - modifiers: onlyOwner
        - [Int] _transferOwnership #
    
     + [Int] IAccessControl 
        - [Ext] hasRole
        - [Ext] getRoleAdmin
        - [Ext] grantRole #
        - [Ext] revokeRole #
        - [Ext] renounceRole #
    
     + [Lib] Strings 
        - [Int] toString
        - [Int] toHexString
        - [Int] toHexString
    
     +  AccessControl (Context, IAccessControl, ERC165)
        - [Pub] supportsInterface
        - [Pub] hasRole
        - [Int] _checkRole
        - [Pub] getRoleAdmin
        - [Pub] grantRole #
           - modifiers: onlyRole
        - [Pub] revokeRole #
           - modifiers: onlyRole
        - [Pub] renounceRole #
        - [Int] _setupRole #
        - [Int] _setRoleAdmin #
        - [Int] _grantRole #
        - [Int] _revokeRole #
    
     +  FounderKeys (ERC1155, Ownable, AccessControl)
        - [Pub]  #
           - modifiers: ERC1155
        - [Ext] register ($)
        - [Ext] approve #
           - modifiers: onlyRole,isWaitlisted
        - [Ext] reject #
           - modifiers: onlyRole,isWaitlisted
        - [Int] addToWaitlist #
        - [Int] removeFromWaitlist #
        - [Pub] withdrawTo #
           - modifiers: onlyOwner
        - [Pub] uri
        - [Ext] setURI #
           - modifiers: onlyOwner
        - [Pub] supportsInterface