AstroBirdsV2 Dividend - Smart Contract Audit Report

Audit Summary

CBWC Audit Report Passive Income is building a new dividend paying token with liquidity adds and a buyback system for burning supply, found here.

For this audit, we reviewed the project team's implementation contract for AstroBirdsV2 at 0x6f1e5bf9420f355e3f12c65d4382be2f9219d3da, Proxy contract at 0x9624cd2e91504692e120802e80a313f84847dc40 and AstroBirdzDividendTracker implementation contract at 0x53789db481ce032b530b0a20de940c21f5a8bd01 on the team's Binance Smart Chain mainnet.

We previously reviewed the project team's launchpad protocol here.

Audit Findings

Please ensure trust in the team prior to investing as they have substantial control in the ecosystem and can upgrade the token contract at any time.
Date: January 24th, 2022.

Finding #1 - AstroBirdsV2 - Low

Description: The owner can use the lock() function in order to temporarily set ownership to address(0). Ownership is restored after the duration of time determined by the owner has passed and they use the unlock() function.
function lock(uint256 time) public virtual onlyOwner {
    _previousOwner = _owner;
    _owner = address(0);
    _lockTime = block.timestamp + time;
    emit OwnershipTransferred(_owner, address(0));
}
function unlock() public virtual {
    require(
        _previousOwner == msg.sender,
        "You don't have permission to unlock"
    );
    emit OwnershipTransferred(_owner, _previousOwner);
    _owner = _previousOwner;  
}
Risk/Impact: The unlock function has the potential to be used after ownership has been set to address(0), which will restore ownership to the original owner that initially created the ownership lock. This can be used in a nefarious way by the project team to restore ownership and change fee structures.
Recommendation: We recommend upgrading the contract to a fixed version in which the unlock function be modified to set the previous owner variable equal to address(0) at the end of the unlock function to prevent it from being used more than once per lock.

Finding #2 - AstroBirdsV2 - Low

Description: The current dividend amount is calculated based on the set percentage of the dividend fee amount from the total fee amount in the contract.
Risk/Impact: Since the AstroBirdsV2 contract swaps the BNB collected from dividend fees for $PSI tokens to be distributed by the AstroBirdzDividendTracker contract, it is possible that the dividend amount can cause the $PSI token to be susceptible to frontrunning.
Recommendation: The project team should ensure that the dividend amount is not too large to mitigate the risk of frontrunning as well as monitor for suspicious acivity.

Contracts Overview

AstroBirdsV2 Contract:
  • The total supply of the token is currently 413.4 million $ABZ [413,437,361].
  • The team has the ability to mint any amount of tokens to any address at any time.
  • 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, 66.6% of the total supply is stored in the contract and 7.25% has been sent to the dead address.
  • The next five holders own a cumulative 7.3% of the total supply.
  • Currently, 0.87% of the token's supply is in PancakeSwap liquidity.
  • Of that liquidity, 91.8% of the LP tokens are stored in a PSI token locking contract
  • The deployer address holds 8% of the LP tokens.

  • There is a maximum transaction amount, but this does not apply during transactions where the owner is either the sender or the recipient.
  • There is a maximum sell limit when the sell limiter is enabled.
  • There is a liquidity, marketing, PSI, buyback and team fee on all transactions for any non-excluded address that participates in a transfer. All fees have a maximum limit of 15% each for a maximum total of 75%
  • The fees charged on transactions are stored in the contract and, once a threshold value is met, are swapped for BNB and used to fund PancakeSwap liquidity.
  • Liquidity-adds are funded by selling half of the tokens collected as liquidity fees, pairing the received BNB with the token, and adding it as liquidity to the BNB pair.
  • The recipient of the newly created LP tokens is the owner's address. We recommend that the team locks these newly acquired LP tokens.
  • Of the remaining tokens, 1% of the BNB is automatically swapped for $PSI and distributed as dividends to the AstrobirdzDividendTracker contract, 3% is transferred to the marketing wallet controlled by the team, 1% is transferred to the team wallet, and the remaining part is sent to the buyback address also controlled by the team.

  • The owner can mint any amount of tokens to any address at any time unless the owner address is a contract address.
  • The owner can set the buyback address, marketing address, team address, and PSI address at any time.
  • The owner must initialize the AstroBirdzDividendTracker contract.
  • The owner can individually set the liquidity, marketing, PSI, and buyback fees to any value up to 15% at any time.
  • The owner can mint any amount of tokens to any address at any time unless the owner address is a contract address.
  • The owner can set a maximum transfer amount at any time.
  • The owner can include and exclude accounts from transfer fees and dividends at any time.
  • The owner can toggle and set the sell limit to any value at any time.
  • The owner can toggle buying and selling tokens at any time.
  • The owner can toggle transfer functionality at any time.
  • The owner is able to update the maximum amount of gas used for processing to a value between 200,000 and 500,000 at any time; the initial value is 300,000.
  • As the contract is deployed with Solidity v0.8.10, it is protected from overflow/underflow attacks along with following the ERC20 standard.
  • The contract is upgradable, meaning the team can swap out the current contract for a new one at any time.
AstroBirdzDividendTracker Contract:
  • A user must hold 100,000 $ABZ tokens (0.02% of the total supply) to be eligible for dividends
  • Once dividends are distributed, they will need to be claimed; claiming happens automatically on each transfer.
  • Dividend rewards can also be claimed manually by kicking off the claim cycle, which will process all eligible token holders.
  • There is a wait-time of 3600 seconds (1 hour) between claiming dividend rewards.
  • Claimed dividends are sent to the user's wallet address.

  • The owner can update the minimum $ABZ token amount to be eligible for dividends at any time.
  • The owner can set the balance of any user to any value at any time.
  • The owner is able to update the amount of time a user must wait between claiming dividends to a value between 1 and 24 hours (in seconds).
  • The owner is able to exclude any address from dividends at any time.

External Threat Results

Vulnerability CategoryNotesResult
Arbitrary Storage WriteN/APASS
Arbitrary JumpN/APASS
Centralization of Control
  • The owner can mint any amount of tokens at any time.
  • The owner can set the various fees up to a total of 75%.
  • The owner can set users dividend balance to any value at any time.
  • The team can upgrade the token contract at any time.
  • The LP tokens generated through automatic liquidity adds are sent to the owner.
  • WARNING
    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
    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 PASS

    AstroBirdsV2 Contract

    Token Graph

    Token Chart

    												
    ($) = payable function
     # = non-constant function
    
    Int = Internal
    Ext = External
    Pub = Public
    
       +  Initializable 
    
     +  ContextUpgradeable (Initializable)
        - [Int] __Context_init #
           - modifiers: initializer
        - [Int] __Context_init_unchained #
           - modifiers: initializer
        - [Int] _msgSender
        - [Int] _msgData
    
     + [Lib] AddressUpgradeable 
        - [Int] isContract
        - [Int] sendValue #
        - [Int] functionCall #
        - [Int] functionCall #
        - [Int] functionCallWithValue #
        - [Int] functionCallWithValue #
        - [Int] functionStaticCall
        - [Int] functionStaticCall
        - [Int] verifyCallResult
    
     + [Int] IERC20Upgradeable 
        - [Ext] totalSupply
        - [Ext] balanceOf
        - [Ext] transfer #
        - [Ext] allowance
        - [Ext] approve #
        - [Ext] transferFrom #
    
     + [Int] IPancakeFactory 
        - [Ext] feeTo
        - [Ext] feeToSetter
        - [Ext] getPair
        - [Ext] allPairs
        - [Ext] allPairsLength
        - [Ext] createPair #
        - [Ext] setFeeTo #
        - [Ext] setFeeToSetter #
    
     + [Int] IPancakePair 
        - [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] IPancakeRouter01 
        - [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] IPancakeRouter02 (IPancakeRouter01)
        - [Ext] removeLiquidityETHSupportingFeeOnTransferTokens #
        - [Ext] removeLiquidityETHWithPermitSupportingFeeOnTransferTokens #
        - [Ext] swapExactTokensForTokensSupportingFeeOnTransferTokens #
        - [Ext] swapExactETHForTokensSupportingFeeOnTransferTokens ($)
        - [Ext] swapExactTokensForETHSupportingFeeOnTransferTokens #
    
     + [Int] IERC20 
        - [Ext] totalSupply
        - [Ext] balanceOf
        - [Ext] transfer #
        - [Ext] allowance
        - [Ext] approve #
        - [Ext] transferFrom #
    
     + [Int] IERC20Metadata (IERC20)
        - [Ext] name
        - [Ext] symbol
        - [Ext] decimals
    
     + [Int] IBEP20 (IERC20, IERC20Metadata)
        - [Ext] getOwner
    
     + [Int] IDividendPayingTokenInterface 
        - [Ext] dividendToken
        - [Ext] parentToken
        - [Ext] totalDividendsDistributed
        - [Ext] dividendOf
        - [Ext] withdrawDividend #
        - [Ext] distributeDividends #
    
     + [Int] IDividendPayingTokenOptionalInterface 
        - [Ext] withdrawableDividendOf
        - [Ext] withdrawnDividendOf
        - [Ext] accumulativeDividendOf
    
     + [Int] IERC20TokenRecover 
        - [Ext] recoverERC20 #
        - [Ext] recoverETH #
    
     + [Int] IDividendTracker (IBEP20, IDividendPayingTokenInterface, IDividendPayingTokenOptionalInterface, IERC20TokenRecover)
        - [Ext] lastProcessedIndex
        - [Ext] excludedFromDividends
        - [Ext] lastClaimTimes
        - [Ext] claimWait
        - [Ext] minimumTokenBalanceForDividends
        - [Ext] excludeFromDividends #
        - [Ext] includeInDividends #
        - [Ext] updateClaimWait #
        - [Ext] updateMinTokenBalance #
        - [Ext] getLastProcessedIndex
        - [Ext] getNumberOfTokenHolders
        - [Ext] getAccount
        - [Ext] getAccountAtIndex
        - [Ext] ensureBalance #
        - [Ext] ensureBalanceForUsers #
        - [Ext] ensureBalanceForUser #
        - [Ext] setBalance #
        - [Ext] process #
        - [Ext] processAccount #
    
     +  ERC20Upgradeable (Initializable, ContextUpgradeable, IERC20Upgradeable)
        - [Ext]  ($)
        - [Int] _ERC20_init #
           - modifiers: initializer
        - [Ext] initPSIDividendTracker #
           - modifiers: onlyOwner
        - [Pub] name
        - [Pub] symbol
        - [Pub] decimals
        - [Pub] totalSupply
        - [Pub] balanceOf
        - [Int] calculateLiquidityFee
        - [Int] calculatePSIFee
        - [Int] calculateMarketingFee
        - [Int] calculateTeamFee
        - [Int] calculateBuybackFee
        - [Pub] setPSIFee #
           - modifiers: onlyOwner
        - [Pub] setLiquidityFee #
           - modifiers: onlyOwner
        - [Pub] setBuybackFee #
           - modifiers: onlyOwner
        - [Pub] setMarketingFee #
           - modifiers: onlyOwner
        - [Pub] setTeamFee #
           - modifiers: onlyOwner
        - [Ext] toggleSellLimit #
           - modifiers: onlyOwner
        - [Pub] setBuybackAddress #
           - modifiers: onlyOwner
        - [Pub] changeMarketingAddress #
           - modifiers: onlyOwner
        - [Pub] changeTeamAddress #
           - modifiers: onlyOwner
        - [Pub] changePSIAddress #
           - modifiers: onlyOwner
        - [Pub] changeLiquidityAddress #
           - modifiers: onlyOwner
        - [Pub] changeSellLimit #
           - modifiers: onlyOwner
        - [Pub] changeMaxtx #
           - modifiers: onlyOwner
        - [Pub] addExcludedAddress #
           - modifiers: onlyOwner
        - [Pub] removeExcludedAddress #
           - modifiers: onlyOwner
        - [Pub] excludeFromFeesAndDividends #
           - modifiers: onlyOwner
        - [Ext] addNewRouter #
           - modifiers: onlyOwner
        - [Ext] setAutomatedMarketMakerPair #
           - modifiers: onlyOwner
        - [Prv] _setAutomatedMarketMakerPair #
        - [Ext] updateGasForProcessing #
           - modifiers: onlyOwner
        - [Pub] transferOwnership #
           - modifiers: onlyOwner
        - [Pub] getUnlockTime
        - [Pub] lock #
           - modifiers: onlyOwner
        - [Pub] unlock #
        - [Pub] multiTransfer #
        - [Ext] processDividendTracker #
        - [Pub] transfer #
        - [Pub] allowance
        - [Pub] approve #
        - [Pub] transferFrom #
        - [Pub] increaseAllowance #
        - [Pub] decreaseAllowance #
        - [Pub] setSwapAndLiquifyEnabled #
           - modifiers: onlyOwner
        - [Int] _transferExcluded #
        - [Int] _transfer #
        - [Prv] _fixDividendTrackerBalancer #
        - [Int] _simpleTransfer #
        - [Ext] performSwapAndLiquify #
           - modifiers: onlyOwner
        - [Prv] swapAndLiquify #
           - modifiers: lockTheSwap
        - [Pub] toggleTrading #
           - modifiers: onlyOwner
        - [Pub] togglePaused #
           - modifiers: onlyOwner
        - [Prv] swapTokensForEth #
        - [Prv] addLiquidity #
        - [Prv] swapAndSendDividends #
        - [Prv] swapETHForPSI #
        - [Int] _mint #
        - [Ext] mint #
           - modifiers: onlyOwner
        - [Int] _burn #
        - [Ext] burn #
        - [Int] _approve #
        - [Int] _setupDecimals #
        - [Int] _beforeTokenTransfer #
    
     +  AstroBirdsV2 (Initializable, ERC20Upgradeable)
        - [Pub] initialize #
           - modifiers: initializer

    AstroBirdzDividendTracker Contract

    Tracker Token Graph

    Tracker Chart

    												
    ($) = payable function
     # = non-constant function
    
    Int = Internal
    Ext = External
    Pub = Public
    
    +  Context 
        - [Int] _msgSender
        - [Int] _msgData
    
     +  Ownable (Context)
        - [Pub]  #
        - [Pub] owner
        - [Pub] renounceOwnership #
           - modifiers: onlyOwner
        - [Pub] transferOwnership #
           - modifiers: onlyOwner
        - [Int] _transferOwnership #
    
     + [Lib] IterableMapping 
        - [Int] get
        - [Int] getIndexOfKey
        - [Int] getKeyAtIndex
        - [Int] size
        - [Int] set #
        - [Int] remove #
    
     + [Int] IERC20 
        - [Ext] totalSupply
        - [Ext] balanceOf
        - [Ext] transfer #
        - [Ext] allowance
        - [Ext] approve #
        - [Ext] transferFrom #
    
     + [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 #
    
     + [Int] IDividendPayingTokenInterface 
        - [Ext] dividendToken
        - [Ext] parentToken
        - [Ext] totalDividendsDistributed
        - [Ext] dividendOf
        - [Ext] withdrawDividend #
        - [Ext] distributeDividends #
    
     + [Int] IDividendPayingTokenOptionalInterface 
        - [Ext] withdrawableDividendOf
        - [Ext] withdrawnDividendOf
        - [Ext] accumulativeDividendOf
    
     +  DividendPayingToken (Ownable, ERC20, IDividendPayingTokenInterface, IDividendPayingTokenOptionalInterface)
        - [Pub]  #
           - modifiers: ERC20
        - [Pub] distributeDividends #
           - modifiers: onlyOwnerOrParentToken
        - [Pub] withdrawDividend #
        - [Int] _withdrawDividendOfUser #
        - [Pub] dividendOf
        - [Pub] withdrawableDividendOf
        - [Pub] withdrawnDividendOf
        - [Pub] accumulativeDividendOf
        - [Int] _transfer #
        - [Int] _mint #
        - [Int] _burn #
        - [Int] _setBalance #
    
     + [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] SafeERC20 
        - [Int] safeTransfer #
        - [Int] safeTransferFrom #
        - [Int] safeApprove #
        - [Int] safeIncreaseAllowance #
        - [Int] safeDecreaseAllowance #
        - [Prv] _callOptionalReturn #
    
     + [Int] IERC20TokenRecover 
        - [Ext] recoverERC20 #
        - [Ext] recoverETH #
    
     +  ERC20TokenRecover (Ownable, IERC20TokenRecover)
        - [Pub] recoverERC20 #
           - modifiers: onlyOwner
        - [Pub] recoverETH #
           - modifiers: onlyOwner
    
     + [Int] IBEP20 (IERC20, IERC20Metadata)
        - [Ext] getOwner
    
     + [Int] IDividendTracker (IBEP20, IDividendPayingTokenInterface, IDividendPayingTokenOptionalInterface, IERC20TokenRecover)
        - [Ext] lastProcessedIndex
        - [Ext] excludedFromDividends
        - [Ext] lastClaimTimes
        - [Ext] claimWait
        - [Ext] minimumTokenBalanceForDividends
        - [Ext] excludeFromDividends #
        - [Ext] includeInDividends #
        - [Ext] updateClaimWait #
        - [Ext] updateMinTokenBalance #
        - [Ext] getLastProcessedIndex
        - [Ext] getNumberOfTokenHolders
        - [Ext] getAccount
        - [Ext] getAccountAtIndex
        - [Ext] ensureBalance #
        - [Ext] ensureBalanceForUsers #
        - [Ext] ensureBalanceForUser #
        - [Ext] setBalance #
        - [Ext] process #
        - [Ext] processAccount #
    
     +  AstroBirdzDividendTracker (Ownable, DividendPayingToken, ERC20TokenRecover, IDividendTracker)
        - [Pub]  #
           - modifiers: DividendPayingToken
        - [Pub] getOwner
        - [Pub] recoverERC20 #
           - modifiers: onlyOwnerOrParentToken
        - [Int] _transfer
        - [Pub] withdrawDividend
        - [Ext] excludeFromDividends #
           - modifiers: onlyOwnerOrParentToken
        - [Ext] includeInDividends #
           - modifiers: onlyOwnerOrParentToken
        - [Ext] updateClaimWait #
           - modifiers: onlyOwnerOrParentToken
        - [Ext] updateMinTokenBalance #
           - modifiers: onlyOwnerOrParentToken
        - [Ext] getLastProcessedIndex
        - [Ext] getNumberOfTokenHolders
        - [Pub] getAccount
        - [Ext] getAccountAtIndex
        - [Prv] canAutoClaim
        - [Ext] ensureBalance #
        - [Ext] ensureBalanceForUsers #
           - modifiers: onlyOwnerOrParentToken
        - [Prv] bytesToAddress
        - [Pub] ensureBalanceForUser #
           - modifiers: onlyOwnerOrParentToken
        - [Ext] setBalance #
           - modifiers: onlyOwnerOrParentToken
        - [Ext] process #
        - [Pub] processAccount #
           - modifiers: onlyOwnerOrParentToken