Exponent - Smart Contract Audit Report
Audit Summary
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:Recommendation: These functions can be declared external for additional gas savings on each call.poolLength(), digBurrow(), updateBurrow(), setWhitelist(), feed(), kill().
Contracts Overview
XPN Contract:XPNAirdrop 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.
FennecBurrow 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.
- 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 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 |
Unbounded Loop | N/A | PASS |
Unchecked Retval | N/A | PASS |
User Supplied Assertion | N/A | PASS |
Critical Solidity Compiler | N/A | PASS |
Overall Contract Safety | PASS |
Details: XPN Contract
($) = 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
($) = 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
($) = 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