Exponent - Smart Contract Audit Report

Audit Summary

SonOfABit Audit Report Exponent is creating a new token, Airdrop contract, and NFT contract with MasterChef functionality.

For this audit, we reviewed Exponent's XPN, XPNAirdrop, and FennecBurrow contracts at commit 7307ba83a743d5e323021c895a90da755fa21c50 on the team's private GitHub repository.

Audit Findings

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

Finding #1 - FennecBurrow - Informational

Description: The following functions in the FennecBurrow contract are declared public, but are never called internally:
poolLength(), digBurrow(), updateBurrow(), setWhitelist(), feed(), kill().
Recommendation: These functions can be declared external for additional gas savings on each call.

Contracts Overview

XPN Contract:
  • $XPN is a token used within Exponent's ecosystem.
  • 1 billion $XPN tokens are minted to the owner upon deployment.
  • No other minting or burning functions are present.
  • The Admin can enable or disable token transfers at any time.
  • Any Distributor can still transfer tokens while token transfers are disabled.
  • Token transfers are disabled upon deployment.
  • There are no transfer fees associated with this token.
  • Any Admin can grant or revoke any role from any user.
  • This contract complies with the ERC20 standard.
XPNAirdrop Contract:
  • This contract allows authorized users to claim airdrops in a specified token.
  • A start time and vesting duration are set at the time of deployment.
  • The vesting period will only begin once the start time has passed.
  • Each Airdrop participant will have an upfront amount and a vesting amount.
  • The upfront amount is transferred to a user on their first claim, and the vesting amount is unlocked linearly over the duration of the vesting period.
  • When a user claims for the first time, they must verify by providing a valid proof for the Merkle Tree, authorized address, upfront amount, and vesting amount.
  • They will then receive their upfront amount as well as any vested tokens.
  • Users cannot verify and claim their upfront amount until the start time has passed.
  • Users do not have to provide verification for their subsequent claims.
FennecBurrow Contract:
  • This contract allows users to stake various tokens into specified "Burrows" (pools) in order to earn rewards in $XPN over time until the rewards supply has been depleted.
  • When a user deposits into a Burrow, they will be minted a Fennec NFT which contains the Burrow ID, token series ID, amount staked, reward debt, and birth block.
  • A user must deposit an amount within the Burrow's minimum and maximum staking amounts.
  • A Burrow's total amount staked cannot exceed its "maximum Burrow stake".
  • The number of minted Fennecs corresponding to a Burrow cannot exceed its "population limit".
  • If a Burrow uses a Whitelist, only certain users will be permitted to deposit into the Burrow. Each Whitelisted user will have a custom maximum number of Fennecs that they can mint across all Whitelist-enabled Burrows.
  • Users can also deposit further tokens while providing a Fennec ID to increase their amount staked. This will transfer their Fennec to this contract, so only one deposit can occur per Fennec.
  • Users can withdraw their tokens after both the Burrow's initial unlock block has passed and their Fennec's lifespan has exceeded the Burrow's minimum lock duration.
  • An emergency withdraw function exists so users can withdraw without collecting rewards if desired.
  • When withdrawing, the associated Fennec will be burned.
  • Users will accumulate rewards on each block based on their amount staked, the Burrow's reward per block, and the Burrow's "bonus per NFT" amount per block.
  • The owner can update any Burrow's attributes at any time, including its reward per block, minimum lock duration, and initial unlock block.
  • Users can transfer their Fennec to a different addresses which will then receive its associated rewards, if desired.
  • A Fennec's token URI is composed of its Burrow ID and its token series ID.
  • The owner can update the Whitelist at any time.
  • The owner can create a new Burrow at any time.
  • The owner can update any Burrow's properties at any time, including its unlock time, and minimum lock duration, and reward rate.
  • The team should not add staking tokens that are fee-on-transfer unless the proper exemptions are made, and should also avoid using ERC777-compliant tokens.
  • This contract complies with the ERC721-standard.

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.
  • Any Distributor can disable $XPN transfers at any time.
  • The owner can update any Burrow's attributes at any time.
  • 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: XPN Contract

    ERC20 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 #
    
     + [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 #
    
     +  XPN (ERC20, AccessControl)
        - [Pub]  #
           - modifiers: ERC20
        - [Int] _beforeTokenTransfer #
           - modifiers: onlyDistributor
        - [Ext] setTransfersAllowed #
           - modifiers: onlyRole
    
    
    
     

    Details: XPNAirdrop Contract

    ERC20 Token Graph

    Multi-file Token

    												
    ($) = payable function
     # = non-constant function
    
     + [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 #
    
     + [Lib] MerkleProof 
        - [Int] verify
    
     +  XPNAirdrop 
        - [Pub]  #
        - [Ext] verifyAndClaimReward #
        - [Ext] claimReward #
        - [Int] _claimReward #
        - [Ext] vestedAmount
        - [Int] _vestedAmount
    
    
     
     

    Details: FennecBurrow 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
        - [Prv] _setOwner #
    
     + [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]  #
        - [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 #
    
     + [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
    
     + [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 #
        - [Prv] _checkOnERC721Received #
        - [Int] _beforeTokenTransfer #
    
     + [Int] IERC721Enumerable (IERC721)
        - [Ext] totalSupply
        - [Ext] tokenOfOwnerByIndex
        - [Ext] tokenByIndex
    
     +  ERC721Enumerable (ERC721, IERC721Enumerable)
        - [Pub] supportsInterface
        - [Pub] tokenOfOwnerByIndex
        - [Pub] totalSupply
        - [Pub] tokenByIndex
        - [Int] _beforeTokenTransfer #
        - [Prv] _addTokenToOwnerEnumeration #
        - [Prv] _addTokenToAllTokensEnumeration #
        - [Prv] _removeTokenFromOwnerEnumeration #
        - [Prv] _removeTokenFromAllTokensEnumeration #
    
     +  ReentrancyGuard 
        - [Pub]  #
    
     + [Lib] SafeERC20 
        - [Int] safeTransfer #
        - [Int] safeTransferFrom #
        - [Int] safeApprove #
        - [Int] safeIncreaseAllowance #
        - [Int] safeDecreaseAllowance #
        - [Prv] _callOptionalReturn #
    
     +  FennecBurrow (Ownable, ERC721Enumerable, ReentrancyGuard)
        - [Pub]  #
           - modifiers: ERC721
        - [Pub] poolLength
        - [Pub] digBurrow #
           - modifiers: onlyOwner
        - [Pub] updateBurrow #
           - modifiers: onlyOwner
        - [Pub] setWhitelist #
           - modifiers: onlyOwner
        - [Pub] pendingXPN
        - [Ext] massUpdatePools #
        - [Pub] updatePool #
        - [Pub] mint #
           - modifiers: nonReentrant
        - [Pub] feed #
        - [Pub] harvest #
        - [Pub] kill #
        - [Pub] emergencyKill #
           - modifiers: nonReentrant
        - [Pub] tokenURI