Grim Finance Token and Vault - Smart Contract Audit Report

Summary

Grim Finance Audit Report

Update December 19th, 2021: Grim Finance has been subject to an attack resulting in a loss of funds from numerous vault contracts. The cause of this issue was the ability of users to input arbitrary addresses and have them called within the depositFor function. Via reentrancy, the issue allowed users to falsely increase their shares in Grim's vaults and subsequently withdraw more than they had deposited. In an effort to be transparent, we have posted a thread documenting the attack and the measures we have taken as a response to this incident which can be viewed here.

Everything below this line remains unchanged from the original report.



Grim Finance intends to build a yield aggregator on Fantom's Opera network.

For this audit we reviewed the project's Token and Vault contracts. We reviewed the contracts at the following addresses:

  • Grim Token - 0x7eC94C4327dC757601B4273cD67014d7760Be97E.
  • Grim Pair Vault - 0x6fF9e23BdC45a165f88F723A265d412F403270A0.
  • Grim Single Stake Vault - 0x0d5Ecb27D1574E3B574d6D8c93C628d17348c99B.
  • Notes of the Contracts:

    GrimToken:
    • The current supply of GrimToken (GRIM) is 10,000,000.
    • 40% of GrimTokens are held by the GrimPool contract.
    • 28% of the token is held by an unlocked address.
    • 10.5% of the token is held by a liquidity pool, with 78% of that liquidity staked in a MasterChef staking contract.
    • There is a 1% burn fee and a 1% liquidity fee taken on transfers. These fees can be changed by the owner at any time.
    • The owner and contract are excluded from these fees, and the owner has the power to exclude other addresses at any time.
    • Once the number of tokens collected by the LP fee has reached a certain threshold (beginning at 1000), it will add liquidity through a swap and liquify function. This threshold can be changed by the owner at any time. In addition, the owner can change the destination wallet that the LP tokens are sent to at any time.
    • The swap and liquify function can also be directly called at any time as it is public.
    • Some functions could be declared external instead of public.
    GrimVault:
    • Users can stake various tokens into the Vault contract in order to earn rewards in the project's native token.
    • User's deposited tokens will be forwarded to a Strategy contract to earn yield while the user earns rewards.
    • The owner can initiate a change of the strategy in use by the vault at any time. The delay to upgrade to a new strategy after a new strategy is proposed is set by the team upon deployment. This delay cannot be changed after deployment.
    • Some functions could be declared external instead of public.
    • ReentrancyGuard is used in relevant locations to preent reentrancy attacks.
    • Utilization of SafeMath (or similarily safe functions) to prevent overflow issues.
    • The owner can also recover tokens erroneously sent to the contract. Staked tokens cannot be moved unless the strategy token is changed, in which case the owner has the ability to withdraw the previous strategy's tokens.
    • Note that the Strategy contract, not reviewed by our team, will have significant control of deposited funds.
    Audit Findings Summary
    • No issues from external attackers were identified.
    • Ensure trust in the team as the owner has the ability to change the Strategy contract, the burn fee, and the LP fee at any time.
    • Date: August 24th, 2021.

    External Threat Results

    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: Grim Finance Vault Contract


    ERC20 Token Graph

    Multi-file Token

    
    ($) = payable function
    # = non-constant function
    
    Int = Internal
    Ext = External
    Pub = Public
    
     +  Context 
        - [Int] _msgSender
        - [Int] _msgData
    
     + [Int] IERC20 
        - [Ext] totalSupply
        - [Ext] balanceOf
        - [Ext] transfer #
        - [Ext] allowance
        - [Ext] approve #
        - [Ext] transferFrom #
    
     + [Lib] SafeMath 
        - [Int] add
        - [Int] sub
        - [Int] sub
        - [Int] mul
        - [Int] div
        - [Int] div
        - [Int] mod
        - [Int] mod
    
     + [Lib] Address 
        - [Int] isContract
        - [Int] sendValue #
        - [Int] functionCall #
        - [Int] functionCall #
        - [Int] functionCallWithValue #
        - [Int] functionCallWithValue #
        - [Prv] _functionCallWithValue #
    
     +  ERC20 (Context, IERC20)
        - [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] _setupDecimals #
        - [Int] _beforeTokenTransfer #
    
     + [Lib] SafeERC20 
        - [Int] safeTransfer #
        - [Int] safeTransferFrom #
        - [Int] safeApprove #
        - [Int] safeIncreaseAllowance #
        - [Int] safeDecreaseAllowance #
        - [Prv] _callOptionalReturn #
    
     +  Ownable (Context)
        - [Int]  #
        - [Pub] owner
        - [Pub] renounceOwnership #
           - modifiers: onlyOwner
        - [Pub] transferOwnership #
           - modifiers: onlyOwner
    
     +  ReentrancyGuard 
    
     + [Int] IStrategy 
        - [Ext] vault
        - [Ext] want
        - [Ext] beforeDeposit #
        - [Ext] deposit #
        - [Ext] withdraw #
        - [Ext] balanceOf
        - [Ext] harvest #
        - [Ext] retireStrat #
        - [Ext] panic #
        - [Ext] pause #
        - [Ext] unpause #
        - [Ext] paused
    
     +  GrimVault (ERC20, Ownable, ReentrancyGuard)
        - [Pub]  #
           - modifiers: ERC20
        - [Pub] want
        - [Pub] balance
        - [Pub] available
        - [Pub] getPricePerFullShare
        - [Ext] depositAll #
        - [Pub] deposit #
           - modifiers: nonReentrant
        - [Pub] earn #
        - [Ext] withdrawAll #
        - [Pub] withdraw #
        - [Pub] proposeStrat #
           - modifiers: onlyOwner
        - [Pub] upgradeStrat #
           - modifiers: onlyOwner
        - [Ext] inCaseTokensGetStuck #
           - modifiers: onlyOwner
        - [Pub] depositFor #
    
      
    


    Details: GrimToken Contract


    ERC20 Token Graph

    Multi-file Token

    
    ($) = payable function
    # = non-constant function
    
    Int = Internal
    Ext = External
    Pub = Public
    
     + [Lib] SafeMath 
        - [Int] add
        - [Int] sub
        - [Int] sub
        - [Int] mul
        - [Int] div
        - [Int] div
        - [Int] mod
        - [Int] mod
    
     + [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
    
     + [Lib] Address 
        - [Int] isContract
        - [Int] sendValue #
        - [Int] functionCall #
        - [Int] functionCall #
        - [Int] functionCallWithValue #
        - [Int] functionCallWithValue #
        - [Prv] _functionCallWithValue #
    
     + [Lib] SafeERC20 
        - [Int] safeTransfer #
        - [Int] safeTransferFrom #
        - [Int] safeApprove #
        - [Int] safeIncreaseAllowance #
        - [Int] safeDecreaseAllowance #
        - [Prv] _callOptionalReturn #
    
     +  Ownable (Context)
        - [Pub]  #
        - [Pub] owner
        - [Pub] renounceOwnership #
           - modifiers: onlyOwner
        - [Pub] transferOwnership #
           - modifiers: onlyOwner
    
     + [Int] IUniswapV2Factory 
        - [Ext] feeTo
        - [Ext] feeToSetter
        - [Ext] getPair
        - [Ext] allPairs
        - [Ext] allPairsLength
        - [Ext] createPair #
        - [Ext] setFeeTo #
        - [Ext] setFeeToSetter #
    
     + [Int] IUniswapV2Pair 
        - [Ext] name
        - [Ext] symbol
        - [Ext] decimals
        - [Ext] totalSupply
        - [Ext] balanceOf
        - [Ext] allowance
        - [Ext] approve #
        - [Ext] transfer #
        - [Ext] transferFrom #
        - [Ext] DOMAIN_SEPARATOR
        - [Ext] PERMIT_TYPEHASH
        - [Ext] nonces
        - [Ext] permit #
        - [Ext] MINIMUM_LIQUIDITY
        - [Ext] factory
        - [Ext] token0
        - [Ext] token1
        - [Ext] getReserves
        - [Ext] price0CumulativeLast
        - [Ext] price1CumulativeLast
        - [Ext] kLast
        - [Ext] mint #
        - [Ext] burn #
        - [Ext] swap #
        - [Ext] skim #
        - [Ext] sync #
        - [Ext] initialize #
    
     + [Int] IUniswapV2Router01 
        - [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] IUniswapV2Router02 (IUniswapV2Router01)
        - [Ext] removeLiquidityETHSupportingFeeOnTransferTokens #
        - [Ext] removeLiquidityETHWithPermitSupportingFeeOnTransferTokens #
        - [Ext] swapExactTokensForTokensSupportingFeeOnTransferTokens #
        - [Ext] swapExactETHForTokensSupportingFeeOnTransferTokens ($)
        - [Ext] swapExactTokensForETHSupportingFeeOnTransferTokens #
    
     +  Grim (Ownable)
        - [Pub]  #
        - [Pub] setFee #
           - modifiers: onlyOwner
        - [Pub] changeLpReceiverAddress #
           - modifiers: onlyOwner
        - [Pub] exclude #
           - modifiers: onlyOwner
        - [Pub] setMaxLPCap #
           - modifiers: onlyOwner
        - [Prv] calculateBurnFee
        - [Pub] setSwapAndLiquify #
           - modifiers: onlyOwner
        - [Prv] calculateLiquidityFee
        - [Pub] name
        - [Pub] symbol
        - [Pub] decimals
        - [Pub] totalSupply
        - [Pub] balanceOf
        - [Pub] allowance
        - [Pub] approve #
        - [Pub] transfer #
        - [Pub] transferFrom #
        - [Pub] increaseAllowance #
        - [Pub] decreaseAllowance #
        - [Int] _mint #
        - [Int] _approve #
        - [Prv] _transfer #
        - [Ext]  ($)
        - [Pub] swapAndLiquify #
        - [Prv] swapTokensForEth #
        - [Prv] addLiquidity #
        - [Pub] setRouter #
           - modifiers: onlyOwner