EQShares - Smart Contract Audit Report

Summary

crypto_audit 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:
  • 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
Strategy_DAI_FTM Contract:
  • 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
Audit Findings Summary
  • 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 CategoryNotesResult
Arbitrary Storage WriteN/APASS
Arbitrary JumpN/APASS
Centralization of ControlThe team retains control of ownership functions described above.PASS
Delegate Call to Untrusted ContractN/APASS
Dependence on Predictable VariablesN/APASS
Deprecated OpcodesN/APASS
Ether ThiefN/APASS
ExceptionsN/APASS
External CallsN/APASS
Flash LoansUse of TWAP where appropriate.PASS
Integer Over/UnderflowN/APASS
Logical IssuesN/APASS
Multiple SendsN/APASS
OraclesN/APASS
SuicideN/APASS
State Change External CallsN/APASS
Unbounded LoopsN/APASS
Unchecked RetvalN/APASS
User Supplied AssertionN/APASS
Critical Solidity CompilerN/APASS
Overall Contract Safety PASS

VaultH20 Contract

smart_contract_audit_company

token_audit


 ($) = 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

smart_contract_audit_company

token_audit


 ($) = 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