Black Lemon - Smart Contract Audit Report

Summary

Black Lemon Audit Report Black Lemon is a new ERC20 token and platform for NFT staking.

We audited the project team's Token contract at commit 870040de39a768b0844cb7b20e62de88d73f6405 and the team's NFT Staking contract at commit 31d39c6e1e3c8910416235ca265268d555751e31 on the team's private Github repository.

Notes on the Token Contract:
  • The initial supply of the token is set to 10 million [10,000,000].
  • No burn functions are present; though the circulating supply can be reduced by sending tokens to the 0x..dead address, if desired.
  • The owner has the ability to assign and remove addresses to a Minter role.
  • The assigned Minter(s) can mint tokens at any time up to a hard cap of 500 million tokens.
  • As the token has not yet been deployed to the mainnet, there was no token allocation for our team to analyze.
  • Upon deployment, the owner of the contract will be assigned to the Default Admin role.
  • The Default Admin has the ability to assign and remove addresses to a Pauser role.
  • The assigned Pauser has the ability to freeze/unfreeze all token transfers at any time.
  • As the project is deployed with Solidity v0.8.2, it is protected from overflows.

  • Notes on the NFT Staking Contract:
  • Users can stake NFTs in this contract to earn rewards in the form of the project's ERC20 token.
  • Only NFT contracts whitelisted by the team will be allowed to be staked in the contract.
  • Upon staking their ERC-1155 NFT, a user will receive an NFT token representing their stake.
  • Users rewards will be automatically claimed when they unstake from the contract; or users can manually claim them.
  • Users will not be able to stake until the team calls start(); after which staking cannot be stopped.
  • The team has the ability to mint the ERC-1155 tokens at any time.
  • Only contract addresses built to return a specific data value can receive the ERC-1155 which will be minted by the contract.
  • The team can set the reward token address, add rewards, update the weight of staked NFTs, and withdraw ERC20 tokens erroneously sent to the contract.
  • The getCurrentStageInf() and getClaimableRewards() functions have external calls inside a loop, which could consume a large amount of gas if the number of loops is high. Users should not stake a very large number of NFTs from the same address to ensure no issues will be encountered.
  • The start(), getRewards(address) and getCurrentStageInf(address) functions should be declared external insetad of public to save some gas on each call.

  • Notes on the Exchange Contract:
  • The exchange contract holds logic for matching buy and sell orders using atomic swaps.
  • The team can update the treasury addresses and the seller addresses at any time.
  • The personalSignPrefix variable in the ExchangeCore contract should be constant to save gas on deployment and each reference.
  • The bytes32 hash_ input variable to the validateOrderParameters() function is unused and can be removed.
  • The addTreasuryAdd_(), setSeller_(), atomicMatch_(), and ecrecover_() functions should be declared external instead of public to save some gas on each call.


  • Audit Findings Summary
    • No issues from external attackers were identified.
    • We recommend renouncing ownership after a successful deployment.
    • Ensure trust in the team as they can mint tokens, pause transfers, and update variables related to NFT staking.
    • Date: August 31st, 2021

    Vulnerability CategoryNotesResult
    Arbitrary Storage WriteN/APASS
    Arbitrary JumpN/APASS
    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
    Unchecked RetvalN/APASS
    User Supplied AssertionN/APASS
    Critical Solidity CompilerN/APASS
    Overall Contract Safety PASS


    Details: Token Contract


    BEP20 Token Graph

    Multi-file Token

    												
    ($) = payable function
     # = non-constant function
    
     + [Int] IERC20 
        - [Ext] totalSupply
        - [Ext] balanceOf
        - [Ext] transfer #
        - [Ext] allowance
        - [Ext] approve #
        - [Ext] transferFrom #
    
     + [Int] IERC20Metadata (IERC20)
        - [Ext] name
        - [Ext] symbol
        - [Ext] decimals
    
     +  Context 
        - [Int] _msgSender
        - [Int] _msgData
    
     +  ERC20 (Context, IERC20, IERC20Metadata)
        - [Pub]  #
        - [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 #
    
     +  Pausable (Context)
        - [Pub]  #
        - [Pub] paused
        - [Int] _pause #
           - modifiers: whenNotPaused
        - [Int] _unpause #
           - modifiers: whenPaused
    
     + [Int] IAccessControl 
        - [Ext] hasRole
        - [Ext] getRoleAdmin
        - [Ext] grantRole #
        - [Ext] revokeRole #
        - [Ext] renounceRole #
    
     + [Lib] Strings 
        - [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 #
        - [Prv] _grantRole #
        - [Prv] _revokeRole #
    
     +  BlackLemon (ERC20, Pausable, AccessControl)
        - [Pub]  #
           - modifiers: ERC20
        - [Pub] pause #
           - modifiers: onlyRole
        - [Pub] unpause #
           - modifiers: onlyRole
        - [Pub] mint #
           - modifiers: onlyRole
        - [Int] _beforeTokenTransfer #
           - modifiers: whenNotPaused
    	   
    	   

    Details: NFT Staking Contract (V2)


    BEP20 Token Graph

    Multi-file Token

    												
    ($) = payable function
     # = non-constant function
    
     + [Int] IERC165 
        - [Ext] supportsInterface
    
     + [Int] IERC1155Receiver (IERC165)
        - [Ext] onERC1155Received #
        - [Ext] onERC1155BatchReceived #
    
     + [Int] IERC1155 (IERC165)
        - [Ext] balanceOf
        - [Ext] balanceOfBatch
        - [Ext] setApprovalForAll #
        - [Ext] isApprovedForAll
        - [Ext] safeTransferFrom #
        - [Ext] safeBatchTransferFrom #
    
     + [Int] IAccessControl 
        - [Ext] hasRole
        - [Ext] getRoleAdmin
        - [Ext] grantRole #
        - [Ext] revokeRole #
        - [Ext] renounceRole #
    
     +  Context 
        - [Int] _msgSender
        - [Int] _msgData
    
     + [Lib] Strings 
        - [Int] toString
        - [Int] toHexString
        - [Int] toHexString
    
     +  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 #
        - [Prv] _grantRole #
        - [Prv] _revokeRole #
    
     + [Int] IERC20 
        - [Ext] totalSupply
        - [Ext] balanceOf
        - [Ext] transfer #
        - [Ext] allowance
        - [Ext] approve #
        - [Ext] transferFrom #
    
     + [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
    
     +  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] _beforeTokenTransfer #
        - [Prv] _doSafeTransferAcceptanceCheck #
        - [Prv] _doSafeBatchTransferAcceptanceCheck #
        - [Prv] _asSingletonArray
    
     + [Lib] EnumerableSet 
        - [Prv] _add #
        - [Prv] _remove #
        - [Prv] _contains
        - [Prv] _length
        - [Prv] _at
        - [Prv] _values
        - [Int] add #
        - [Int] remove #
        - [Int] contains
        - [Int] length
        - [Int] at
        - [Int] values
        - [Int] add #
        - [Int] remove #
        - [Int] contains
        - [Int] length
        - [Int] at
        - [Int] values
        - [Int] add #
        - [Int] remove #
        - [Int] contains
        - [Int] length
        - [Int] at
        - [Int] values
    
     +  Collection (ERC1155, AccessControl)
        - [Pub]  #
           - modifiers: ERC1155
        - [Int] addSeedIdsBatch #
        - [Int] addSeedId #
        - [Ext] addWeight #
           - modifiers: onlyRole
        - [Ext] mint #
           - modifiers: onlyRole
        - [Ext] mintBatch #
           - modifiers: onlyRole
        - [Pub] supportsInterface
    
     + [Lib] UintSet 
        - [Int] add #
        - [Int] remove #
        - [Int] contains
        - [Int] length
        - [Int] at
        - [Int] getArray
    
     + [Int] IMintableToken 
        - [Ext] mint #
    
     +  NftStakingV2 (AccessControl, IERC1155Receiver)
        - [Pub]  #
        - [Pub] start #
           - modifiers: onlyRole,hasNotStarted
        - [Ext] setRewardToken #
           - modifiers: onlyRole
        - [Ext] addReward #
           - modifiers: hasNotStarted,onlyRole
        - [Ext] addWhitelist #
           - modifiers: onlyRole
        - [Ext] withdrawERC20 #
           - modifiers: onlyRole
        - [Int] _getSeedIds #
        - [Int] _getWeight #
        - [Prv] _stageControl #
        - [Prv] _registerStaker #
        - [Prv] _calculateTotalRew
        - [Int] _stakeNft #
           - modifiers: hasStarted
        - [Int] _batchStakeNfts #
           - modifiers: hasStarted
        - [Ext] unStakeNft #
        - [Ext] batchUnstakeNfts #
        - [Pub] claimRewards #
        - [Pub] getRewards
           - modifiers: hasStarted
        - [Ext] getClaimableRewards
           - modifiers: hasStarted
        - [Pub] getCurrentStageInf
        - [Ext] getUserTokenIds
        - [Ext] getMinted
        - [Ext] onERC1155Received #
        - [Ext] onERC1155BatchReceived # 

    Details: Exchange Contract


    BEP20 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
        - [Prv] _setOwner #
    
     +  ReentrancyGuarded 
    
     +  EIP712 
        - [Int] hash
    
     +  ERC1271 
        - [Pub] isValidSignature
    
     + [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
    
     +  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] _beforeTokenTransfer #
        - [Prv] _doSafeTransferAcceptanceCheck #
        - [Prv] _doSafeBatchTransferAcceptanceCheck #
        - [Prv] _asSingletonArray
    
     + [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 #
    
     + [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
    
     +  ExchangeCore (ReentrancyGuarded, EIP712, Ownable)
        - [Int] addTreasuryAdd #
           - modifiers: onlyOwner
        - [Int] setSeller #
           - modifiers: onlyOwner
        - [Int] hashOrder
        - [Int] hashToSign
        - [Int] exists
        - [Int] validateOrderParameters
        - [Int] validateOrderAuthorization
        - [Int] atomicMatch #
           - modifiers: reentrancyGuard
    
     +  Exchange (ExchangeCore)
        - [Ext] hashOrder_
        - [Ext] hashToSign_
        - [Pub] addTreasuryAdd_ #
           - modifiers: onlyOwner
        - [Pub] setSeller_ #
           - modifiers: onlyOwner
        - [Ext] validateOrderParameters_
        - [Ext] validateOrderAuthorization_
        - [Pub] atomicMatch_ ($)
        - [Pub] ecrecover_