SafeWhale Game - Smart Contract Audit Report

Audit Summary

SafeWhale Game Audit Report SafeWhale is building a new game platform where users can deposit tokens to play and earn rewards.

For this audit, we reviewed the Game contract using code that was provided to us by the team.

Audit Findings

Please ensure trust in the team prior to investing as they have substantial control in the ecosystem.
Date: January 24th, 2022.
Updated: February 7th, 2022 to reflect changes made to the Game contract to resolve Finding #1.

Finding #1 - Game - High (Resolved)

Description: In the depositToPlay() function, a portion of the deposited amount is taken as a fee, but the fee is not deducted from the amount added to the user's total deposit amount.
IERC20(depositToken).transferFrom(acc, env, accumulatedMin);

 if (feePercent > 0) {
	cut = accumulatedMin * feePercent / 100;
	IERC20(depositToken).transfer(feeWallet, cut);

players[acc].plays += rate;
players[acc].deposit += accumulatedMin;
Risk/Impact: The contract will contain fewer tokens than the total deposit amounts for each user. As a result, there will not be a sufficient amount of tokens in the contract for all users to withdraw.
Recommendation: The fee taken should be deducted from the deposit amount prior to adjusting the user's total deposit amount.
Resolution: The team has implemented the above recommendation.

Contract Overview

  • The contract allows users to deposit an asset determined by the owner in exchange for a certain number of plays and the possibility to earn rewards in a second asset determined by the owner.
  • The number of tokens that a user must deposit to be eligible to play is also set by the owner.
  • Users will have to grant the contract an approval for their full deposit amount in order for a deposit to occur successfully.
  • The team must exercise caution when setting the deposit token to avoid any deflationary, fee-on-transfer, or ERC-777 tokens.
  • A deposit discount is available to users if they are the owner of an NFT that has been pre-selected by the team as a discounted NFT. The number of tokens a user must deposit will be subtracted by this discount.
  • There is a deposit fee charged on all deposits that is allocated to the team's Fee wallet.
  • A user can withdraw all of their deposited tokens at any time, but that user's number of plays and rewards (if any) will be forfeited.
  • The amount of rewards due and the user's score must be individually set by the owner for each user. Each time the owner sets these variables per user, the number of plays left for that user is decreased by 1.
  • A user can claim the rewards they have due to them at any time. If a user has any pending rewards from a previous round, they must first claim them before they can deposit again.
  • The team must ensure that a sufficient amount of reward tokens are held in the contract in order for users to be able to claim their rewards.
Ownership Controls:
  • The owner can update the deposit token address and reward token address to any addresses at any time.
  • The owner can update the number of plays a user receives after making a deposit to any value at any time.
  • The owner can update the number of tokens a user must deposit in order to be able to participate in the game to any value at any time.
  • The owner can pre-select any NFT which will apply a discount for the owner of that NFT when depositing.
  • The owner can update the deposit fee to any percent at any time.
  • The owner can advance the game to the next round at any time.
  • The owner can withdraw any BNB or tokens from the contract address at any time.
  • The owner can update the team's Fee wallet to any address at any time.

External Threat Results

Vulnerability CategoryNotesResult
Arbitrary Storage WriteN/APASS
Arbitrary JumpN/APASS
Centralization of Control
  • The owner can set the deposit fee up to 100%.
  • The owner can update the deposit token and reward token to any addresses at any time.
  • The owner can withdraw any tokens from the contract at any time.
    Delegate Call to Untrusted ContractN/APASS
    Dependence on Predictable VariablesN/APASS
    Deprecated OpcodesN/APASS
    Ether ThiefN/APASS
    External CallsN/APASS
    Integer Over/UnderflowN/APASS
    Logical IssuesN/APASS
    Multiple SendsN/APASS
    State Change External CallsN/APASS
    Unchecked RetvalN/APASS
    User Supplied AssertionN/APASS
    Critical Solidity CompilerN/APASS
    Overall Contract Safety PASS

    Function Graph

    BEP20 Token Graph

    Inheritance Chart

    Multi-file Token

    Functions Overview

     ($) = payable function
     # = non-constant function
     + [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] IERC721Metadata (IERC721)
        - [Ext] name
        - [Ext] symbol
        - [Ext] tokenURI
     + [Int] IERC20 
        - [Ext] totalSupply
        - [Ext] balanceOf
        - [Ext] transfer #
        - [Ext] allowance
        - [Ext] approve #
        - [Ext] transferFrom #
     + [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] 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 #
     +  Context 
        - [Int] _msgSender
        - [Int] _msgData
     +  Ownable (Context)
        - [Pub]  #
        - [Pub] owner
        - [Pub] renounceOwnership #
           - modifiers: onlyOwner
        - [Pub] transferOwnership #
           - modifiers: onlyOwner
     +  AccessControl (Ownable)
        - [Pub] addAdmin #
           - modifiers: onlyOwner
        - [Pub] removeAdmin #
           - modifiers: onlyOwner
     +  Game (AccessControl)
        - [Pub]  #
        - [Ext]  ($)
        - [Ext] recoverToken #
           - modifiers: onlyAdmin
        - [Ext] recoverBNB #
           - modifiers: onlyAdmin
        - [Ext] setDepositToken #
           - modifiers: onlyAdmin
        - [Ext] setRewardToken #
           - modifiers: onlyAdmin
        - [Ext] setDepositRate #
           - modifiers: onlyAdmin
        - [Ext] setMinimumDeposit #
           - modifiers: onlyAdmin
        - [Ext] setNFTDepositReduction #
           - modifiers: onlyAdmin
        - [Ext] setFeePercent #
           - modifiers: onlyAdmin
        - [Ext] setFeeWallet #
           - modifiers: onlyAdmin
        - [Ext] recordScore #
           - modifiers: onlyAdmin
        - [Ext] depositToPlay #
        - [Ext] cancelDeposit #
        - [Ext] claimReward #
        - [Ext] newRound #
           - modifiers: onlyAdmin
        - [Prv] updateScore #
        - [Prv] updateReward #