BRAINS Token and Staking - Smart Contract Audit Report

Audit Summary

BeamSwap Audit Report Brainiac has implemented an ERC-20 token with fee collection for liquidity adds and is building a new staking contract for users to deposit tokens and earn yield.

For this audit, we reviewed the BRAINS contract at 0x39317b8a1ae06c30bb615d88cdc5522781499f1c on the Ethereum Blockchain Mainnet and the MasterChefBrain contract provided to us by the project team.

Audit Findings

Please ensure trust in the team prior to investing as they have notable control in the ecosystem.
Date: January 26th, 2022.

Finding #1 - MasterChefBrain - Medium

Description: In the getjoePerSec() function, the joePerSec variable is calculated based on using the inherited getAmountsOut() function and Uniswap liquidity pools to determine the total value within the contract in USD.
Risk/Impact: Anyone can use flash loans to manipulate the ratio of the reward token to ETH liquidity pair, thereby greatly increasing the determined total value of tokens in the contract address. The new inflated total contract value would automatically set the joePerSec variable value to the corresponding threshold value and incorrectly calculate reward amounts to distribute.
Recommendation: The team should implement a Time Weighted Average Price (TWAP) or utilize Chainlink to mitigate potential price manipulations.

Finding #2 - MasterChefBrain - Informational

Description: Several functions are declared public, but are never called internally.
			
add, set, deposit, compoundtoSas, withdraw, emergencyWithdraw, dev, changeTreasury, setDevPercent
Recommendation: We recommend declaring these functions external for additional gas savings on each call.

Contracts Overview

Brain Contract:
  • The total supply of the token is currently 47 million $BRAINS [47,451,396].
  • The owner can grant the Minter role to any address, which can mint any amount of tokens to any address at any time.
  • Any user can burn their own tokens to reduce the total supply.
  • In addition to the burn function, tokens can also be sent to the 0x..dead address to reduce the circulating supply at any time.
  • At the time of writing this report, 34.20% of the total supply is stored in a MasterChefBrains staking contract. This contract was out of scope for the purpose of this audit.
  • 8.81% of the total supply belongs to the owner.
  • 3.15% is stored in a Treasury contract. This contract was out of scope for the purpose of this audit.
  • 2.43% has been sent to the dead address.
  • The next five holders own a cumulative 5.60% of the total supply.
  • 34.90% of the token's supply is in UniSwap liquidity.
  • Of that liquidity, 75.45% of the LP tokens are stored in a MasterChefBrains staking contract. This contract was out of scope for the purpose of this audit.
  • 23.19% of the LP tokens are stored in an unverified token locking contract behind a proxy. This contract was out of scope for the purpose of this audit.
  • 0.73% of the LP tokens are held by the owner.
  • The next five holders own a cumulative 0.21% of the LP tokens.

  • The tax charged on transfers is stored in the contract balance. On transfers where neither the sender nor recipient is excluded, the sender is not the liquidity pair, and tax is enabled, the contract balance is swapped for ETH for the purpose of being distributed to the marketing and treasury wallet addresses.
  • The owner can trigger the startCreateLiq() function to initiate the liquidity process that starts by creating a Uniswap liquidity pair.
  • The Uniswap liquidity pair is initially funded with all of the $BRAINS tokens and ETH currently stored in the contract balance.
  • The liquidity tokens received through the initial liquidity-add are sent to the current owner's wallet. We recommend that the team locks these newly acquired LP tokens.
  • Any LP tokens from the newly created pair that may be in the contract balance are transferred to the Marketing address.
  • Additionally, taxes are then disabled and transfers are paused for all addresses except the owner and marketing address going forward.
  • Any user can call the manualSwap() function, triggering the contract balance to be swapped for ETH and sent to the Treasury and Marketing wallets at any time.
  • Any user can call the approveRouter() function to approve the Uniswap router address access to withdraw the maximum amount of funds from the contract at any time.

  • The owner can add or remove any address from the Minter role at any time.
  • The owner can withdraw the contract balance at any time.
  • The owner can include and exclude accounts from transfer fees at any time.
  • The owner can change the marketing and treasury address at any time.
  • The owner can toggle and set the maximum transaction amount to any value at any time.
  • The owner can toggle and set the maximum tax amount up to 10% at any time.
  • The owner can add or remove any amount of "bot" addresses at any time.
  • The owner can enable the liquidity functionality at any time.
  • The contract complies with the ERC-20 standard.
  • As the contract is deployed with Solidity v0.8.7, it is protected from overflow/underflow attacks.
MasterChefBrain Contract:
  • This contract allows anyone to stake a variety of ERC-20 token assets determined by the team in order to earn reward tokens.
  • On deposits, any pending rewards are calculated and transferred to the user.
  • On withdrawals, the pending rewards and deposited amount are calculated and transferred to the user. A 5% fee is deducted and sent to the Treasury address.
  • Users will receive a reward amount based on time staked, the pool's allocation points, developer fee, and current reward per second rate.
  • The reward rate is automatically set when the total value in the pool exceeds previously set owner defined thresholds, each with a corresponding reward rate.
  • Users can stake tokens into the SAS staking pool and specify another address as the owner.
  • Users can also choose to immediately re-invest their rewards from either pool back into the SAS staking pool at any time.
  • When the contract is in emergency status, users are able to withdraw any staked assets without collecting any rewards.
  • The owner is able to add any token to be used as a staking token in the contract.
  • The team must also be careful not to add the same token twice for staking.
  • The MasterChefBrain staking contract should not be used with fee-on-transfer or ERC-777 tokens. If a fee-on-transfer token is added as a staking asset, then the contract must be exempt from transfer fees.
  • The owner can toggle the emergency status at any time.
  • The owner can change the amount of allocated points per pool at any time.
  • The owner can update the Treasury address at any time.
  • The owner can set the developer fee to any value up to 100% at any time.
  • The owner can set any amount of total staked value thresholds and corresponding reward rates.
  • As the contract is implemented with Solidity v0.8.x, it is protected from overflow/underflow attacks.

External Threat Results

Vulnerability CategoryNotesResult
Arbitrary Storage WriteN/APASS
Arbitrary JumpN/APASS
Centralization of ControlThe owner can set the developer fee up to 100% of the staking rewards.WARNING
Delegate Call to Untrusted ContractN/APASS
Dependence on Predictable VariablesN/APASS
Deprecated OpcodesN/APASS
Ether ThiefN/APASS
ExceptionsN/APASS
External CallsN/APASS
Flash LoansThe total value of the contract balance can be manipulated to increase the reward rate.WARNING
Integer Over/UnderflowN/APASS
Logical IssuesN/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 WARNING

Brain Contract

 Token Graph

token Chart

												
($) = payable function
 # = non-constant function

Int = Internal
Ext = External
Pub = Public

+ [Lib] EnumerableSet 
    - [Prv] _add #
    - [Prv] _remove #
    - [Prv] _contains
    - [Prv] _length
    - [Prv] _at
    - [Prv] _values
    - [Int] add #
    - [Int] remove #
    - [Int] contains
    - [Int] length
    - [Int] at
    - [Int] values
    - [Int] add #
    - [Int] remove #
    - [Int] contains
    - [Int] length
    - [Int] at
    - [Int] values
    - [Int] add #
    - [Int] remove #
    - [Int] contains
    - [Int] length
    - [Int] at
    - [Int] values

 + [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] IERC20 
    - [Ext] totalSupply
    - [Ext] balanceOf
    - [Ext] transfer #
    - [Ext] allowance
    - [Ext] approve #
    - [Ext] transferFrom #

 + [Int] IERC20Metadata (IERC20)
    - [Ext] name
    - [Ext] symbol
    - [Ext] decimals

 + [Lib] SafeMath 
    - [Int] add
    - [Int] sub
    - [Int] sub
    - [Int] mul
    - [Int] div
    - [Int] div

 + [Lib] SafeERC20 
    - [Int] safeTransfer #
    - [Int] safeTransferFrom #
    - [Int] safeApprove #
    - [Int] safeIncreaseAllowance #
    - [Int] safeDecreaseAllowance #
    - [Prv] _callOptionalReturn #

 +  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 #

 +  Ownable (Context)
    - [Pub] Constructor #
    - [Pub] owner
    - [Pub] renounceOwnership #
       - modifiers: onlyOwner
    - [Pub] transferOwnership #
       - modifiers: onlyOwner
    - [Prv] _setOwner #

 + [Int] IUniswapV2Factory 
    - [Ext] createPair #

 + [Int] IUniswapV2Router02 
    - [Ext] swapExactTokensForETHSupportingFeeOnTransferTokens #
    - [Ext] factory
    - [Ext] WETH
    - [Ext] addLiquidityETH ($)

 + [Int] BRAINToken 
    - [Ext] excludeFromFees #
    - [Ext] includeInFees #
    - [Ext] changeMarketing #
    - [Ext] changeTreasury #
    - [Ext] setMaxTx #
    - [Ext] toggleMaxTx #
    - [Ext] setTax #
    - [Ext] toggleTax #
    - [Ext] addBots #
    - [Ext] removeBot #
    - [Ext] addMinter #
    - [Ext] removeMinter #
    - [Ext] mint #
    - [Ext] burn #
    - [Ext] burn #

 +  BRAIN (Ownable, ERC20, BRAINToken)
    - [Pub] Constructor #
       - modifiers: ERC20
    - [Ext] Receive Ether ($)
    - [Ext] approveRouter #
    - [Ext] excludeFromFees #
       - modifiers: onlyOwner
    - [Ext] includeInFees #
       - modifiers: onlyOwner
    - [Ext] changeMarketing #
       - modifiers: onlyOwner
    - [Ext] changeTreasury #
       - modifiers: onlyOwner
    - [Ext] setMaxTx #
       - modifiers: onlyOwner
    - [Ext] toggleMaxTx #
       - modifiers: onlyOwner
    - [Ext] setTax #
       - modifiers: onlyOwner
    - [Ext] toggleTax #
       - modifiers: onlyOwner
    - [Ext] addBots #
       - modifiers: onlyOwner
    - [Ext] removeBot #
       - modifiers: onlyOwner
    - [Ext] addMinter #
       - modifiers: onlyOwner
    - [Ext] removeMinter #
       - modifiers: onlyOwner
    - [Ext] mint #
       - modifiers: onlyMinter
    - [Ext] burn #
    - [Ext] burn #
    - [Int] _transfer #
    - [Prv] swapTokensForEth #
       - modifiers: lockSwap
    - [Ext] startCreateLiq #
       - modifiers: onlyOwner
    - [Ext] manualswap #
    - [Ext] withdrawEth #
       - modifiers: onlyOwner

MasterChefBrain Contract

staking Graph

staking Chart

												
($) = payable function
 # = non-constant function

Int = Internal
Ext = External
Pub = Public

+ [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

 + [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] EnumerableSet 
    - [Prv] _add #
    - [Prv] _remove #
    - [Prv] _contains
    - [Prv] _length
    - [Prv] _at
    - [Prv] _values
    - [Int] add #
    - [Int] remove #
    - [Int] contains
    - [Int] length
    - [Int] at
    - [Int] values
    - [Int] add #
    - [Int] remove #
    - [Int] contains
    - [Int] length
    - [Int] at
    - [Int] values
    - [Int] add #
    - [Int] remove #
    - [Int] contains
    - [Int] length
    - [Int] at
    - [Int] values

 + [Int] IERC20 
    - [Ext] totalSupply
    - [Ext] balanceOf
    - [Ext] transfer #
    - [Ext] allowance
    - [Ext] approve #
    - [Ext] transferFrom #

 +  Ownable (Context)
    - [Pub]  #
    - [Pub] owner
    - [Pub] renounceOwnership #
       - modifiers: onlyOwner
    - [Pub] transferOwnership #
       - modifiers: onlyOwner
    - [Prv] _setOwner #

 + [Lib] SafeMath 
    - [Int] tryAdd
    - [Int] trySub
    - [Int] tryMul
    - [Int] tryDiv
    - [Int] tryMod
    - [Int] add
    - [Int] sub
    - [Int] mul
    - [Int] div
    - [Int] mod
    - [Int] sub
    - [Int] div
    - [Int] mod

 + [Lib] SafeERC20 
    - [Int] safeTransfer #
    - [Int] safeTransferFrom #
    - [Int] safeApprove #
    - [Int] safeIncreaseAllowance #
    - [Int] safeDecreaseAllowance #
    - [Prv] _callOptionalReturn #

 + [Int] IERC20Metadata (IERC20)
    - [Ext] name
    - [Ext] symbol
    - [Ext] decimals

 +  ERC20 (Context, IERC20, IERC20Metadata)
    - [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] _beforeTokenTransfer #
    - [Int] _afterTokenTransfer #

 + [Lib] BoringERC20 
    - [Int] returnDataToString
    - [Int] safeSymbol
    - [Int] safeName
    - [Int] safeDecimals
    - [Int] safeTransfer #
    - [Int] safeTransferFrom #

 + [Int] BRAINToken 
    - [Ext] excludeFromFees #
    - [Ext] includeInFees #
    - [Ext] changeMarketing #
    - [Ext] changeTreasury #
    - [Ext] setMaxTx #
    - [Ext] toggleMaxTx #
    - [Ext] setTax #
    - [Ext] toggleTax #
    - [Ext] addBots #
    - [Ext] removeBot #
    - [Ext] addMinter #
    - [Ext] removeMinter #
    - [Ext] mint #
    - [Ext] burn #
    - [Ext] burn #

 + [Int] FARM 
    - [Ext] stake #
    - [Ext] viewJoePerSec #

 +  MasterChefBrain (Ownable, FARM)
    - [Pub]  #
    - [Ext] viewJoePerSec
    - [Ext] setEmergency #
       - modifiers: onlyOwner
    - [Ext] poolLength
    - [Pub] add #
       - modifiers: onlyOwner
    - [Pub] set #
       - modifiers: onlyOwner
    - [Ext] pendingTokens
    - [Pub] massUpdatePools #
    - [Pub] updatePool #
    - [Pub] deposit #
    - [Pub] compoundToSas #
    - [Ext] stake #
    - [Pub] withdraw #
    - [Pub] emergencyWithdraw #
    - [Int] safeJoeTransfer #
    - [Pub] dev #
    - [Pub] changeTreasury #
       - modifiers: onlyOwner
    - [Pub] setDevPercent #
       - modifiers: onlyOwner
    - [Ext] setTvlApr #
       - modifiers: onlyOwner
    - [Ext] setTvlThresholds #
       - modifiers: onlyOwner
    - [Pub] getjoePerSec