Safu Investments Presale Platform - Smart Contract Audit Report

Summary

Safu Audit Report Safu Investments is a launchpad for projects on the Ethereum mainnet to launch in a safe, trusted, and decentralized manner. The platform has had dozens of successful presales in a few short months.

We reviewed Safu Investments' updated contracts at the following addresses on mainnet:


Notes on the Contracts:
  • The Factory contract exists to deploy Presale and LiquidityLock contracts.
  • The Presale contract allows teams to create presales, and users to contribute ETH to participate in that presale. This contract is re-deployed for each new presale.
  • The LiquidityLock contract holds the liquidity added to Uniswap and shall release it to the team after a set amount of time.
  • The Info contract exists to hold information such as the developers' fee, owner's address, and a counter of presales counducted.

  • Any user can call the createPresle() function on the Factory contract to generate a presale, passing in variables around the presale duration, token price, liquidity lock time & percentage, min & max contributions, hard & soft caps, start & end dates, etc.
  • When a presale is created via this function, a Presale contract will be deployed at a new address for use by the caller.
  • While the sale is active, users can contribute ETH to purchase tokens in a presale at the rate defined by the project team hosting the presale.
  • If the sale's soft cap is not reached, the sale will be cancelled and user's will be able to claim refunds.
  • The team running the presale can also end the sale early if they so choose.

  • At the conclusion of the sale, liquidity will been added to Uniswap and users who bought into the presale can claim their tokens.
  • If the hard cap is reached prior to the sale closing date, the team hosting the presale can conclude the process early; adding liquidity to Uniswap and allowing token claims by investors.
  • When a user claims their tokens, their ETH contribution is sent to the project team running the presale. 24 hours after the presale concludes and liquidity is added, all of the ETH raised will be available to be claimed by the project team.
  • Upon adding liquidity to Uniswap, the amount of liquidity set by the team running the presale will be sent to and locked in the LiquidityLock contract.
  • The liquidity lock contract will hold the LP tokens until the unlock time (set by the project team) is met; at which point the team will be able to claim the LP tokens.

  • A 1% fee or 1 ETH (Whichever is greater) will be sent to the Safu Investments team at the conclusion of the sale. These amounts can be updated to any amount at any time in the Info contract. This, however, would only impact newly deployed presales; not existing ones.
  • The Safu Investments team can choose to exempt presale from developer fees after deployment if desired.
  • The Info contract allows anyone to add an address as a presale, incrementing the counter. While this may be unintneded (as opposed to only allowing the factory to call this), it has no impact on security or safety of the contracts.
  • The contracts utilize SafeMath to prevent overflow issues and properly structure logic around ETH transfers to prevent reentrancy issues. Usage of ERC777 tokens (very uncommon) with the contract could lead to reentrancy issues; thus it is advisable that this style of token not be used with the platform.


  • Audit Findings Summary:
    • No security issues from outside attackers were identified.
    • The project lead has completed KYC with our firm.
    • Date: March 26th, 2021.

    External Threats

    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
    Integer Over/UnderflowN/APASS
    Multiple SendsN/APASS
    SuicideN/APASS
    State Change External CallsN/APass
    Unchecked RetvalN/APASS
    User Supplied AssertionN/APASS
    Critical Solidity CompilerN/APASS
    Overall Contract Safety PASS


    Details - SafuInvestmentsFactory Contract


    Smart Contract Graph

    Contract Inheritance

    
     ($) = payable function
     # = non-constant function
     
     Int = Internal
     Ext = External
     Pub = Public
     
     + [Lib] Address 
        - [Int] isContract
        - [Int] sendValue #
        - [Int] functionCall #
        - [Int] functionCall #
        - [Int] functionCallWithValue #
        - [Int] functionCallWithValue #
        - [Int] functionStaticCall
        - [Int] functionStaticCall
        - [Prv] _verifyCallResult
    
     +  Context 
        - [Int] _msgSender
        - [Int] _msgData
    
     + [Int] IERC20 
        - [Ext] totalSupply
        - [Ext] balanceOf
        - [Ext] transfer #
        - [Ext] allowance
        - [Ext] approve #
        - [Ext] transferFrom #
    
     +  Ownable (Context)
        - [Int]  #
        - [Pub] owner
        - [Pub] renounceOwnership #
           - modifiers: onlyOwner
        - [Pub] transferOwnership #
           - modifiers: onlyOwner
    
     + [Lib] SafeERC20 
        - [Int] safeTransfer #
        - [Int] safeTransferFrom #
        - [Int] safeApprove #
        - [Int] safeIncreaseAllowance #
        - [Int] safeDecreaseAllowance #
        - [Prv] _callOptionalReturn #
    
     + [Lib] SafeMath 
        - [Int] add
        - [Int] sub
        - [Int] sub
        - [Int] mul
        - [Int] div
        - [Int] div
        - [Int] mod
        - [Int] mod
    
     + [Int] IUniswapV2Factory 
        - [Ext] getPair
    
     +  SafuInvestmentsFactory 
        - [Pub]  #
        - [Int] uniV2LibPairFor
        - [Int] initializePresale #
        - [Ext] createPresale #
    
     +  SafuInvestmentsInfo (Ownable)
        - [Ext] addPresaleAddress #
        - [Ext] getPresalesCount
        - [Ext] getPresaleAddress
        - [Ext] getDevFeePercentage
        - [Ext] setDevFeePercentage #
           - modifiers: onlyOwner
        - [Ext] getMinDevFeeInWei
        - [Ext] setMinDevFeeInWei #
           - modifiers: onlyOwner
    
     + [Int] IUniswapV2Router02 
        - [Ext] addLiquidityETH ($)
    
     +  SafuInvestmentsPresale 
        - [Pub]  #
        - [Ext] setAddressInfo #
           - modifiers: onlySafuFactory
        - [Ext] setGeneralInfo #
           - modifiers: onlySafuFactory
        - [Ext] setUniswapInfo #
           - modifiers: onlySafuFactory
        - [Ext] setStringInfo #
           - modifiers: onlyPresaleCreatorOrSafuFactory
        - [Ext] setSafuInfo #
           - modifiers: onlySafuDev
        - [Ext] setSafuDevFeesExempted #
           - modifiers: onlySafuDev
        - [Ext] setOnlyWhitelistedAddressesAllowed #
           - modifiers: onlyPresaleCreatorOrSafuFactory
        - [Ext] addwhitelistedAddresses #
           - modifiers: onlyPresaleCreatorOrSafuFactory
        - [Int] getTokenAmount
        - [Pub] invest ($)
           - modifiers: whitelistedAddressOnly,presaleIsNotCancelled
        - [Ext]  ($)
        - [Ext] addLiquidityAndLockLPTokens #
           - modifiers: presaleIsNotCancelled
        - [Ext] claimTokens #
           - modifiers: whitelistedAddressOnly,presaleIsNotCancelled,investorOnly,notYetClaimedOrRefunded
        - [Ext] getRefund #
           - modifiers: whitelistedAddressOnly,investorOnly,notYetClaimedOrRefunded
        - [Ext] cancelAndTransferTokensToPresaleCreator #
        - [Ext] collectFundsRaised #
           - modifiers: onlyPresaleCreator
    
     +  TokenTimelock 
        - [Pub]  #
        - [Pub] token
        - [Pub] beneficiary
        - [Pub] releaseTime
        - [Pub] release #
    
     +  SafuInvestmentsLiquidityLock (TokenTimelock)
        - [Pub]  #
           - modifiers: TokenTimelock
    
    
     ($) = payable function
     # = non-constant function
      
    
    							


    Details - SafuInvestmentsPresale Contract


    Smart Contract Graph

    Contract Inheritance

    
     ($) = payable function
     # = non-constant function
     
     Int = Internal
     Ext = External
     Pub = Public
     
     + [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] SafeMath 
        - [Int] add
        - [Int] sub
        - [Int] sub
        - [Int] mul
        - [Int] div
        - [Int] div
        - [Int] mod
        - [Int] mod
    
     + [Int] IUniswapV2Router02 
        - [Ext] addLiquidityETH ($)
    
     +  SafuInvestmentsPresale 
        - [Pub]  #
        - [Ext] setAddressInfo #
           - modifiers: onlySafuFactory
        - [Ext] setGeneralInfo #
           - modifiers: onlySafuFactory
        - [Ext] setUniswapInfo #
           - modifiers: onlySafuFactory
        - [Ext] setStringInfo #
           - modifiers: onlyPresaleCreatorOrSafuFactory
        - [Ext] setSafuInfo #
           - modifiers: onlySafuDev
        - [Ext] setSafuDevFeesExempted #
           - modifiers: onlySafuDev
        - [Ext] setOnlyWhitelistedAddressesAllowed #
           - modifiers: onlyPresaleCreatorOrSafuFactory
        - [Ext] addwhitelistedAddresses #
           - modifiers: onlyPresaleCreatorOrSafuFactory
        - [Int] getTokenAmount
        - [Pub] invest ($)
           - modifiers: whitelistedAddressOnly,presaleIsNotCancelled
        - [Ext]  ($)
        - [Ext] addLiquidityAndLockLPTokens #
           - modifiers: presaleIsNotCancelled
        - [Ext] claimTokens #
           - modifiers: whitelistedAddressOnly,presaleIsNotCancelled,investorOnly,notYetClaimedOrRefunded
        - [Ext] getRefund #
           - modifiers: whitelistedAddressOnly,investorOnly,notYetClaimedOrRefunded
        - [Ext] cancelAndTransferTokensToPresaleCreator #
        - [Ext] collectFundsRaised #
           - modifiers: onlyPresaleCreator
    
    							


    Details - SafuInvestmentsLiquidityLock Contract


    Smart Contract Graph

    Contract Inheritance

    
     ($) = payable function
     # = non-constant function
     
     Int = Internal
     Ext = External
     Pub = Public
     
     + [Int] IUniswapV2Router02 
        - [Ext] addLiquidityETH ($)
    
     +  SafuInvestmentsPresale 
        - [Pub]  #
        - [Ext] setAddressInfo #
           - modifiers: onlySafuFactory
        - [Ext] setGeneralInfo #
           - modifiers: onlySafuFactory
        - [Ext] setUniswapInfo #
           - modifiers: onlySafuFactory
        - [Ext] setStringInfo #
           - modifiers: onlyPresaleCreatorOrSafuFactory
        - [Ext] setSafuInfo #
           - modifiers: onlySafuDev
        - [Ext] setSafuDevFeesExempted #
           - modifiers: onlySafuDev
        - [Ext] setOnlyWhitelistedAddressesAllowed #
           - modifiers: onlyPresaleCreatorOrSafuFactory
        - [Ext] addwhitelistedAddresses #
           - modifiers: onlyPresaleCreatorOrSafuFactory
        - [Int] getTokenAmount
        - [Pub] invest ($)
           - modifiers: whitelistedAddressOnly,presaleIsNotCancelled
        - [Ext]  ($)
        - [Ext] addLiquidityAndLockLPTokens #
           - modifiers: presaleIsNotCancelled
        - [Ext] claimTokens #
           - modifiers: whitelistedAddressOnly,presaleIsNotCancelled,investorOnly,notYetClaimedOrRefunded
        - [Ext] getRefund #
           - modifiers: whitelistedAddressOnly,investorOnly,notYetClaimedOrRefunded
        - [Ext] cancelAndTransferTokensToPresaleCreator #
        - [Ext] collectFundsRaised #
           - modifiers: onlyPresaleCreator
    
     + [Lib] Address 
        - [Int] isContract
        - [Int] sendValue #
        - [Int] functionCall #
        - [Int] functionCall #
        - [Int] functionCallWithValue #
        - [Int] functionCallWithValue #
        - [Int] functionStaticCall
        - [Int] functionStaticCall
        - [Prv] _verifyCallResult
    
     + [Int] IERC20 
        - [Ext] totalSupply
        - [Ext] balanceOf
        - [Ext] transfer #
        - [Ext] allowance
        - [Ext] approve #
        - [Ext] transferFrom #
    
     + [Lib] SafeERC20 
        - [Int] safeTransfer #
        - [Int] safeTransferFrom #
        - [Int] safeApprove #
        - [Int] safeIncreaseAllowance #
        - [Int] safeDecreaseAllowance #
        - [Prv] _callOptionalReturn #
    
     +  TokenTimelock 
        - [Pub]  #
        - [Pub] token
        - [Pub] beneficiary
        - [Pub] releaseTime
        - [Pub] release #
    
     +  TokenTimelock 
        - [Pub]  #
        - [Pub] token
        - [Pub] beneficiary
        - [Pub] releaseTime
        - [Pub] release #
    
     +  SafuInvestmentsLiquidityLock (TokenTimelock)
        - [Pub]  #
           - modifiers: TokenTimelock
    							


    Details - SafuInvestmentsInfo Contract


    Smart Contract Graph

    Contract Inheritance

    
     ($) = payable function
     # = non-constant function
     
     Int = Internal
     Ext = External
     Pub = Public
     
     +  Context 
        - [Int] _msgSender
        - [Int] _msgData
    
     +  Ownable (Context)
        - [Int]  #
        - [Pub] owner
        - [Pub] renounceOwnership #
           - modifiers: onlyOwner
        - [Pub] transferOwnership #
           - modifiers: onlyOwner
    
     +  SafuInvestmentsInfo (Ownable)
        - [Ext] addPresaleAddress #
        - [Ext] getPresalesCount
        - [Ext] getPresaleAddress
        - [Ext] getDevFeePercentage
        - [Ext] setDevFeePercentage #
           - modifiers: onlyOwner
        - [Ext] getMinDevFeeInWei
        - [Ext] setMinDevFeeInWei #
           - modifiers: onlyOwner