SafeWhale Game - Smart Contract Audit Report
Audit Summary
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.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.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;
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
Ownership Controls:
- 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.
- 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 Category | Notes | Result |
---|---|---|
Arbitrary Storage Write | N/A | PASS |
Arbitrary Jump | N/A | PASS |
Centralization of Control | WARNING | |
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 |
Integer Over/Underflow | N/A | PASS |
Logical Issues | N/A | PASS |
Multiple Sends | N/A | PASS |
Suicide | N/A | PASS |
State Change External Calls | N/A | PASS |
Unchecked Retval | N/A | PASS |
User Supplied Assertion | N/A | PASS |
Critical Solidity Compiler | N/A | PASS |
Overall Contract Safety | PASS |
Function Graph
Inheritance Chart
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] 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 #
+ 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 #