EQShares - Smart Contract Audit Report
Summary
EQShares is developing a yield farming strategy on the Fantom Blockchain in which users deposit FTM and earn rewards from an LP yield farming platform.
For this audit, we reviewed the VaultH20 contract at 0xA5aDE4EAC20a1F1f90a51E5eaA2852D8ea098C89 and the Strategy_DAI_FTM contract at 0x584f21aee241dbf21e5d3f4428e9cd9bb4890b61 on the Fantom Blockchain.
Notes on the Contracts:
VaultH20 Contract:Strategy_DAI_FTM Contract:
- Anyone may deposit FTM into the Vault contract at any time; in return, the user will receive an amount of tokens representing shares proportional to the total value they are contributing to the pool.
- The Vault will transfer the FTM to the current Strategy contract determined by the project team; there may be various Strategies associated with the vault, but deposits are made to the current Strategy.
- The team should exercise caution to not add too many Strategy contracts as to avoid reaching the block gas limit during withdrawals and rewards claims.
- The minimum amount that may be deposited is 0.1 FTM.
- There is a cooldown period of 2 blocks between any two deposits.
- Users are able to request a withdraw out of the Strategy contracts through the Vault. The user's Vault tokens will be burned for the proportionate percentage of rewards as YEL tokens from all Strategy contracts. A separate call to claim the YEL is required after requesting a withdraw.
- There is a cooldown period of 10 blocks after a withdrawal before a user may deposit, request another withdrawal, or claim their rewards.
- There are no fees for deposits or withdrawals.
- All deposits, withdrawals, and rewards claims will trigger a compounding of rewards in all Strategy contracts.
- The maximum amount of capital (the total potential value in FTM across all tokens held by the contract) allowed within the contract is 10,000 FTM.
- The Governance contract may execute an emergency withdraw at any time. This will withdraw all forms of capital from all of the Strategy contracts to the Governance contract.
- The owner or Governance contract may migrate a Strategy at any time. This will move a specified percentage of capital from one Strategy to another.
- The owner or Governance contract may add a Strategy and set the current Strategy at any time.
- The owner or Governance contract may remove a Strategy at any time, provided that the Strategy has no capital.
- The owner or Governance contract may set the maximum amount of capital that may be in the contract at any time.
- The owner or Governance contract may set the router for a contract at any time.
- The owner may set the Governance contract to any address at any time.
- The owner may withdraw the total balance of any ERC20 tokens in the Vault.
- The owner may withdraw fees from the Strategy contracts at any time.
- The owner may request an updated time weighted average price at any time. Doing so will trigger a cooldown period of 2 blocks before any deposit, withdrawal, or rewards claim may be executed. The owner may update the cooldown period after price updates at any time.
- As the contract is implemented with Solidity v0.8.x, it is protected from overflows/underflows
Audit Findings Summary
- This contract serves as a valid Strategy contract for the VaultH20 contract.
- All FTM deposited into this contract from the Vault is used to add liquidity in a FTM-DAI liquidity pool.
- A liquidity-add is funded by using half of the deposited FTM to purchase DAI, and pairing the remaining half to add liquidity to the FTM-DAI pair.
- The LP tokens are then deposited into a MasterChef contract that is set upon deployment. The MasterChef contract was not provided in the scope of this audit, so we are unable to provide an assessment of this contract with regards to security.
- During a deposit, the contract requires a minimum amount of tokens when adding liquidity. If the minimum amount is not reached during a deposit, the liquidity will not be added and the user will receive no shares. We recommend the team revert deposits that will not be completed so users will not lose their FTM.
- Rewards are compounded by withdrawing all LP tokens and collecting all rewards from the MasterChef. Once the rewards tokens reach a threshold, they will be swapped to WFTM.
- All WETH in the contract is used to add liquidity. All LP tokens are then deposited back into the MasterChef.
- A fee is taken from the rewards tokens and WFTM balance during each autocompound. Once the fees reach a threshold, they are converted into USDT which the owner must then withdraw.
- As the contract is implemented with Solidity v0.8.x, it is protected from overflows/underflows
- No external threats were identified.
- Ensure trust in the team as they have significant control within the ecosystem.
- Date: November 30th, 2021.
Audit Results
Vulnerability Category | Notes | Result |
---|---|---|
Arbitrary Storage Write | N/A | PASS |
Arbitrary Jump | N/A | PASS |
Centralization of Control | The team retains control of ownership functions described above. | PASS |
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 | Use of TWAP where appropriate. | 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 Loops | N/A | PASS |
Unchecked Retval | N/A | PASS |
User Supplied Assertion | N/A | PASS |
Critical Solidity Compiler | N/A | PASS |
Overall Contract Safety | PASS |
VaultH20 Contract
($) = payable function
# = non-constant function
+ [Int] IERC20Simplified
- [Ext] totalSupply
- [Ext] balanceOf
+ [Int] IERC20
- [Ext] totalSupply
- [Ext] balanceOf
- [Ext] transfer #
- [Ext] allowance
- [Ext] approve #
- [Ext] transferFrom #
+ [Int] IERC20MetadataS (IERC20Simplified)
- [Ext] name
- [Ext] symbol
- [Ext] decimals
+ [Int] IERC20Metadata (IERC20)
- [Ext] name
- [Ext] symbol
- [Ext] decimals
+ [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
- [Int] _transferOwnership #
+ [Lib] SafeERC20
- [Int] safeTransfer #
- [Int] safeTransferFrom #
- [Int] safeApprove #
- [Int] safeIncreaseAllowance #
- [Int] safeDecreaseAllowance #
- [Prv] _callOptionalReturn #
+ ERC20Simplified (Context, IERC20Simplified, IERC20MetadataS)
- [Pub] Constructor #
- [Pub] name
- [Pub] symbol
- [Pub] decimals
- [Pub] totalSupply
- [Pub] balanceOf
- [Int] _mint #
- [Int] _burn #
+ 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] Strings
- [Int] toString
- [Int] toHexString
- [Int] toHexString
+ [Int] IStrategy
- [Ext] WETH
- [Ext] router
- [Ext] lpToken
- [Ext] token0
- [Ext] token1
- [Ext] farm
- [Ext] pid
- [Ext] hasPid
- [Ext] getTotalCapitalInternal
- [Ext] getTotalCapital
- [Ext] getAmountLPFromFarm
- [Ext] getPendingYel
- [Ext] claimYel #
- [Ext] setRouter #
- [Ext] requestWithdraw #
- [Ext] withdrawUSDTFee #
- [Ext] emergencyWithdraw #
- [Ext] autoCompound #
- [Ext] deposit ($)
- [Ext] depositAsMigrate #
- [Ext] migrate #
- [Ext] updateTWAP #
- [Ext] token1TWAP
- [Ext] token0TWAP
- [Ext] token1Price
- [Ext] token0Price
+ VaultH2O (ERC20Simplified, Ownable)
- [Pub] Constructor #
- modifiers: ERC20Simplified
- [Ext] Fallback ($)
- [Pub] deposit ($)
- modifiers: notBlocked
- [Pub] requestWithdraw #
- modifiers: whenNotBlocked
- [Pub] claimYel #
- modifiers: notBlocked
- [Pub] setDefaultStrategy #
- modifiers: onlyOwnerOrGovernance
- [Pub] getPendingYel
- [Pub] getRemainingBlocks
- [Pub] nameIDs
- [Pub] nameIDLength
- [Pub] currentStrategy
- [Pub] strategyInfo
- [Pub] strategyInfo2
- [Pub] autoCompound #
- modifiers: executableAfterUpdate
- [Pub] getTotalCapital
- [Pub] getTotalCapitalInternal
- [Pub] withdrawFee #
- modifiers: onlyOwner
- [Pub] setNumberOfBlocksBtwTX #
- modifiers: onlyOwner
- [Pub] updateTWAP #
- modifiers: onlyOwner
- [Pub] emergencyWithdraw #
- modifiers: onlyGovernance
- [Ext] setGovernance #
- modifiers: onlyOwner
- [Ext] setDepositLimit #
- modifiers: onlyOwnerOrGovernance
- [Pub] addStrategy #
- modifiers: onlyOwnerOrGovernance
- [Pub] removeStrategy #
- modifiers: onlyOwnerOrGovernance
- [Pub] setRouterForStrategy #
- modifiers: onlyOwnerOrGovernance
- [Pub] migrate #
- modifiers: onlyOwnerOrGovernance
- [Pub] withdrawSuddenTokens #
- modifiers: onlyOwner
- [Int] _executableAfterUpdate
- [Int] _checkParameters
- [Int] _isNotBlockedByTime
- [Int] _checkBlockedByTime
- [Int] _migrate #
- [Int] _requestYelFromStrategies #
- [Int] _checkDeposit
Strategy_DAI_FTM Contract
($) = payable function
# = non-constant function
+ [Lib] FullMath
- [Int] fullMul
- [Prv] fullDiv
- [Int] mulDiv
+ [Lib] FixedPoint
- [Int] decode144
- [Int] mul
- [Int] fraction
+ [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 #
+ [Int] IWETH (IERC20)
- [Ext] deposit ($)
- [Ext] transfer #
- [Ext] withdraw #
+ [Int] IRouter
- [Ext] factory
- [Ext] WETH
- [Ext] addLiquidity #
- [Ext] addLiquidityETH ($)
- [Ext] removeLiquidity #
- [Ext] removeLiquidityETH #
- [Ext] removeLiquidityWithPermit #
- [Ext] removeLiquidityETHWithPermit #
- [Ext] swapExactTokensForTokens #
- [Ext] swapTokensForExactTokens #
- [Ext] swapExactETHForTokens ($)
- [Ext] swapTokensForExactETH #
- [Ext] swapExactTokensForETH #
- [Ext] swapETHForExactTokens ($)
- [Ext] quote
- [Ext] getAmountOut
- [Ext] getAmountIn
- [Ext] getAmountsOut
- [Ext] getAmountsIn
+ [Int] IPair
- [Ext] token0
- [Ext] token1
- [Ext] price0CumulativeLast
- [Ext] price1CumulativeLast
- [Ext] blockTimestampLast
- [Ext] getReserves
- [Ext] totalSupply
- [Ext] MINIMUM_LIQUIDITY
- [Ext] mint #
+ [Int] IFarm
- [Ext] boo
- [Ext] deposit #
- [Ext] withdraw #
- [Ext] userInfo
- [Ext] poolInfo
+ [Lib] UniswapV2OracleLibrary
- [Int] currentBlockTimestamp
- [Int] currentCumulativePrices
+ [Lib] Math
- [Int] min
- [Int] sqrt
+ Strategy_DAI_FTM
- [Pub] Constructor #
- [Ext] Fallback ($)
- modifiers: onlyVault
- [Pub] getRewardToken
- [Int] _withdrawFromFarm #
- [Pub] getAmountLPFromFarm
- [Pub] earn #
- [Ext] autoCompound #
- [Pub] claimYel #
- modifiers: onlyVault
- [Pub] emergencyWithdraw #
- modifiers: onlyVault
- [Pub] requestWithdraw #
- modifiers: onlyVault
- [Pub] migrate #
- modifiers: onlyVault
- [Pub] deposit ($)
- modifiers: onlyVault
- [Pub] depositAsMigrate #
- modifiers: onlyVault
- [Pub] getTotalCapitalInternal
- [Pub] getTotalCapital
- [Pub] getPendingYel
- [Pub] getBalanceOfToken
- [Int] _getAmountsOut
- [Int] _getTokenValues
- [Pub] setRouter #
- modifiers: onlyVault
- [Pub] withdrawUSDTFee #
- modifiers: onlyVault
- [Int] _transfer #
- [Int] _calculateAmountFee
- [Int] _approveToken #
- [Int] _takeFee #
- [Int] _getLiquidityAmounts
- [Int] _addLiquidity #
- [Int] _canAddLiquidity
- [Int] _addLiquidityFromAllTokens #
- [Int] _removeLiquidity #
- [Pub] updateTWAP #
- modifiers: onlyVault
- [Int] _updateAveragePrices #
- [Int] _updateTWAP #
- [Int] _checkPrice #
- [Int] _swapExactETHForTokens #
- [Int] _addLiquidityETH #
- [Int] __addLiquidityETH #
- [Int] _swapLPtoWETH #
- [Int] _swapToYELs #
- [Int] _swapTokenToWETH #
- [Int] _swapWETHToToken #
- [Int] _swapExactTokensForTokens #
- [Int] _swapWETHToTokens #
- [Int] _getTokenPrice
- [Int] _getTokenPrice1
- [Int] _getSimpleTCI
- [Int] _getSimpleTC