HIGH severity: Untrusted Source (US). The contract uses an external contract in order to determine the transaction's flow, which may produce security issues and harm the transactions.

Vulnerable code:
// SPDX-License-Identifier: MIT



pragma solidity ^0.8.19;



abstract contract Context {

    function _msgSender() internal view virtual returns (address) {

        return msg.sender;

    }



    function _msgData() internal view virtual returns (bytes calldata) {

        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691

        return msg.data;

    }

}



/**

 * @dev Interface of the ERC20 standard as defined in the EIP.

 */

interface IERC20 {

    /**

     * @dev Returns the amount of tokens in existence.

     */

    function totalSupply() external view returns (uint256);



    /**

     * @dev Returns the amount of tokens owned by `account`.

     */

    function balanceOf(address account) external view returns (uint256);



    /**

     * @dev Moves `amount` tokens from the caller's account to `recipient`.

     *

     * Returns a boolean value indicating whether the operation succeeded.

     *

     * Emits a {Transfer} event.

     */

    function transfer(address recipient, uint256 amount) external returns (bool);



    /**

     * @dev Returns the remaining number of tokens that `spender` will be

     * allowed to spend on behalf of `owner` through {transferFrom}. This is

     * zero by default.

     *

     * This value changes when {approve} or {transferFrom} are called.

     */

    function allowance(address owner, address spender) external view returns (uint256);



    /**

     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.

     *

     * Returns a boolean value indicating whether the operation succeeded.

     *

     * IMPORTANT: Beware that changing an allowance with this method brings the risk

     * that someone may use both the old and the new allowance by unfortunate

     * transaction ordering. One possible solution to mitigate this race

     * condition is to first reduce the spender's allowance to 0 and set the

     * desired value afterwards:

     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729

     *

     * Emits an {Approval} event.

     */

    function approve(address spender, uint256 amount) external returns (bool);



    /**

     * @dev Moves `amount` tokens from `sender` to `recipient` using the

     * allowance mechanism. `amount` is then deducted from the caller's

     * allowance.

     *

     * Returns a boolean value indicating whether the operation succeeded.

     *

     * Emits a {Transfer} event.

     */

    function transferFrom(

        address sender,

        address recipient,

        uint256 amount

    ) external returns (bool);



    /**

     * @dev Emitted when `value` tokens are moved from one account (`from`) to

     * another (`to`).

     *

     * Note that `value` may be zero.

     */

    event Transfer(address indexed from, address indexed to, uint256 value);



    /**

     * @dev Emitted when the allowance of a `spender` for an `owner` is set by

     * a call to {approve}. `value` is the new allowance.

     */

    event Approval(address indexed owner, address indexed spender, uint256 value);

}



/**

 * @dev Interface for the optional metadata functions from the ERC20 standard.

 *

 * _Available since v4.1._

 */

interface IERC20Metadata is IERC20 {

    /**

     * @dev Returns the name of the token.

     */

    function name() external view returns (string memory);



    /**

     * @dev Returns the symbol of the token.

     */

    function symbol() external view returns (string memory);



    /**

     * @dev Returns the decimals places of the token.

     */

    function decimals() external view returns (uint8);

}



contract ERC20 is Context, IERC20, IERC20Metadata {

    using SafeMath for uint256;



    mapping(address => uint256) private _balances;



    mapping(address => mapping(address => uint256)) private _allowances;



    uint256 private _totalSupply;



    string private _name;

    string private _symbol;



    /**

     * @dev Sets the values for {name} and {symbol}.

     *

     * The default value of {decimals} is 18. To select a different value for

     * {decimals} you should overload it.

     *

     * All two of these values are immutable: they can only be set once during

     * construction.

     */

    constructor(string memory name_, string memory symbol_) {

        _name = name_;

        _symbol = symbol_;

    }



    /**

     * @dev Returns the name of the token.

     */

    function name() public view virtual override returns (string memory) {

        return _name;

    }



    /**

     * @dev Returns the symbol of the token, usually a shorter version of the

     * name.

     */

    function symbol() public view virtual override returns (string memory) {

        return _symbol;

    }



    /**

     * @dev Returns the number of decimals used to get its user representation.

     * For example, if `decimals` equals `2`, a balance of `505` tokens should

     * be displayed to a user as `5,05` (`505 / 10 ** 2`).

     *

     * Tokens usually opt for a value of 18, imitating the relationship between

     * Ether and Wei. This is the value {ERC20} uses, unless this function is

     * overridden;

     *

     * NOTE: This information is only used for _display_ purposes: it in

     * no way affects any of the arithmetic of the contract, including

     * {IERC20-balanceOf} and {IERC20-transfer}.

     */

    function decimals() public view virtual override returns (uint8) {

        return 9;

    }



    /**

     * @dev See {IERC20-totalSupply}.

     */

    function totalSupply() public view virtual override returns (uint256) {

        return _totalSupply;

    }



    /**

     * @dev See {IERC20-balanceOf}.

     */

    function balanceOf(address account) public view virtual override returns (uint256) {

        return _balances[account];

    }



    /**

     * @dev See {IERC20-transfer}.

     *

     * Requirements:

     *

     * - `recipient` cannot be the zero address.

     * - the caller must have a balance of at least `amount`.

     */

    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {

        _transfer(_msgSender(), recipient, amount);

        return true;

    }



    /**

     * @dev See {IERC20-allowance}.

     */

    function allowance(address owner, address spender) public view virtual override returns (uint256) {

        return _allowances[owner][spender];

    }



    /**

     * @dev See {IERC20-approve}.

     *

     * Requirements:

     *

     * - `spender` cannot be the zero address.

     */

    function approve(address spender, uint256 amount) public virtual override returns (bool) {

        _approve(_msgSender(), spender, amount);

        return true;

    }



    /**

     * @dev See {IERC20-transferFrom}.

     *

     * Emits an {Approval} event indicating the updated allowance. This is not

     * required by the EIP. See the note at the beginning of {ERC20}.

     *

     * Requirements:

     *

     * - `sender` and `recipient` cannot be the zero address.

     * - `sender` must have a balance of at least `amount`.

     * - the caller must have allowance for ``sender``'s tokens of at least

     * `amount`.

     */

    function transferFrom(

        address sender,

        address recipient,

        uint256 amount

    ) public virtual override returns (bool) {

        _transfer(sender, recipient, amount);

        _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));

        return true;

    }



    /**

     * @dev Atomically increases the allowance granted to `spender` by the caller.

     *

     * This is an alternative to {approve} that can be used as a mitigation for

     * problems described in {IERC20-approve}.

     *

     * Emits an {Approval} event indicating the updated allowance.

     *

     * Requirements:

     *

     * - `spender` cannot be the zero address.

     */

    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {

        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));

        return true;

    }



    /**

     * @dev Atomically decreases the allowance granted to `spender` by the caller.

     *

     * This is an alternative to {approve} that can be used as a mitigation for

     * problems described in {IERC20-approve}.

     *

     * Emits an {Approval} event indicating the updated allowance.

     *

     * Requirements:

     *

     * - `spender` cannot be the zero address.

     * - `spender` must have allowance for the caller of at least

     * `subtractedValue`.

     */

    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {

        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));

        return true;

    }



    /**

     * @dev Moves tokens `amount` from `sender` to `recipient`.

     *

     * This is internal function is equivalent to {transfer}, and can be used to

     * e.g. implement automatic token fees, slashing mechanisms, etc.

     *

     * Emits a {Transfer} event.

     *

     * Requirements:

     *

     * - `sender` cannot be the zero address.

     * - `recipient` cannot be the zero address.

     * - `sender` must have a balance of at least `amount`.

     */

    function _transfer(

        address sender,

        address recipient,

        uint256 amount

    ) internal virtual {

        require(sender != address(0), "ERC20: transfer from the zero address");

        require(recipient != address(0), "ERC20: transfer to the zero address");



        _beforeTokenTransfer(sender, recipient, amount);



        _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");

        _balances[recipient] = _balances[recipient].add(amount);

        emit Transfer(sender, recipient, amount);

    }



        /*

            _tokengeneration is an internal function in ERC20.sol that is only called here to generate the total supply first time,

            and CANNOT be called ever again

        */

    function _tokengeneration(address account, uint256 amount) internal virtual {

        require(account != address(0), "ERC20: new tokens to the zero address");



        _beforeTokenTransfer(address(0), account, amount);



        _totalSupply = _totalSupply.add(amount);

        _balances[account] = _balances[account].add(amount);

        emit Transfer(address(0), account, amount);

    }



    /**

     * @dev Destroys `amount` tokens from `account`, reducing the

     * total supply.

     *

     * Emits a {Transfer} event with `to` set to the zero address.

     *

     * Requirements:

     *

     * - `account` cannot be the zero address.

     * - `account` must have at least `amount` tokens.

     */

    function _burn(address account, uint256 amount) internal virtual {

        require(account != address(0), "ERC20: burn from the zero address");



        _beforeTokenTransfer(account, address(0), amount);



        _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");

        _totalSupply = _totalSupply.sub(amount);

        emit Transfer(account, address(0), amount);

    }



    /**

     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.

     *

     * This internal function is equivalent to `approve`, and can be used to

     * e.g. set automatic allowances for certain subsystems, etc.

     *

     * Emits an {Approval} event.

     *

     * Requirements:

     *

     * - `owner` cannot be the zero address.

     * - `spender` cannot be the zero address.

     */

    function _approve(

        address owner,

        address spender,

        uint256 amount

    ) internal virtual {

        require(owner != address(0), "ERC20: approve from the zero address");

        require(spender != address(0), "ERC20: approve to the zero address");



        _allowances[owner][spender] = amount;

        emit Approval(owner, spender, amount);

    }



    function _beforeTokenTransfer(

        address from,

        address to,

        uint256 amount

    ) internal virtual {}

}



library SafeMath {

    /**

     * @dev Returns the addition of two unsigned integers, reverting on

     * overflow.

     *

     * Counterpart to Solidity's `+` operator.

     *

     * Requirements:

     *

     * - Addition cannot overflow.

     */

    function add(uint256 a, uint256 b) internal pure returns (uint256) {

        uint256 c = a + b;

        require(c >= a, "SafeMath: addition overflow");



        return c;

    }



    /**

     * @dev Returns the subtraction of two unsigned integers, reverting on

     * overflow (when the result is negative).

     *

     * Counterpart to Solidity's `-` operator.

     *

     * Requirements:

     *

     * - Subtraction cannot overflow.

     */

    function sub(uint256 a, uint256 b) internal pure returns (uint256) {

        return sub(a, b, "SafeMath: subtraction overflow");

    }



    /**

     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on

     * overflow (when the result is negative).

     *

     * Counterpart to Solidity's `-` operator.

     *

     * Requirements:

     *

     * - Subtraction cannot overflow.

     */

    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {

        require(b <= a, errorMessage);

        uint256 c = a - b;



        return c;

    }



    /**

     * @dev Returns the multiplication of two unsigned integers, reverting on

     * overflow.

     *

     * Counterpart to Solidity's `*` operator.

     *

     * Requirements:

     *

     * - Multiplication cannot overflow.

     */

    function mul(uint256 a, uint256 b) internal pure returns (uint256) {

        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the

        // benefit is lost if 'b' is also tested.

        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522

        if (a == 0) {

            return 0;

        }



        uint256 c = a * b;

        require(c / a == b, "SafeMath: multiplication overflow");



        return c;

    }



    /**

     * @dev Returns the integer division of two unsigned integers. Reverts on

     * division by zero. The result is rounded towards zero.

     *

     * Counterpart to Solidity's `/` operator. Note: this function uses a

     * `revert` opcode (which leaves remaining gas untouched) while Solidity

     * uses an invalid opcode to revert (consuming all remaining gas).

     *

     * Requirements:

     *

     * - The divisor cannot be zero.

     */

    function div(uint256 a, uint256 b) internal pure returns (uint256) {

        return div(a, b, "SafeMath: division by zero");

    }



    /**

     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on

     * division by zero. The result is rounded towards zero.

     *

     * Counterpart to Solidity's `/` operator. Note: this function uses a

     * `revert` opcode (which leaves remaining gas untouched) while Solidity

     * uses an invalid opcode to revert (consuming all remaining gas).

     *

     * Requirements:

     *

     * - The divisor cannot be zero.

     */

    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {

        require(b > 0, errorMessage);

        uint256 c = a / b;

        // assert(a == b * c + a % b); // There is no case in which this doesn't hold



        return c;

    }



    /**

     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),

     * Reverts when dividing by zero.

     *

     * Counterpart to Solidity's `%` operator. This function uses a `revert`

     * opcode (which leaves remaining gas untouched) while Solidity uses an

     * invalid opcode to revert (consuming all remaining gas).

     *

     * Requirements:

     *

     * - The divisor cannot be zero.

     */

    function mod(uint256 a, uint256 b) internal pure returns (uint256) {

        return mod(a, b, "SafeMath: modulo by zero");

    }



    /**

     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),

     * Reverts with custom message when dividing by zero.

     *

     * Counterpart to Solidity's `%` operator. This function uses a `revert`

     * opcode (which leaves remaining gas untouched) while Solidity uses an

     * invalid opcode to revert (consuming all remaining gas).

     *

     * Requirements:

     *

     * - The divisor cannot be zero.

     */

    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {

        require(b != 0, errorMessage);

        return a % b;

    }

}



/**

 * @title SafeMathInt

 * @dev Math operations for int256 with overflow safety checks.

 */

library SafeMathInt {

    int256 private constant MIN_INT256 = int256(1) << 255;

    int256 private constant MAX_INT256 = ~(int256(1) << 255);



    /**

     * @dev Multiplies two int256 variables and fails on overflow.

     */

    function mul(int256 a, int256 b) internal pure returns (int256) {

        int256 c = a * b;



        // Detect overflow when multiplying MIN_INT256 with -1

        require(c != MIN_INT256 || (a & MIN_INT256) != (b & MIN_INT256));

        require((b == 0) || (c / b == a));

        return c;

    }



    /**

     * @dev Division of two int256 variables and fails on overflow.

     */

    function div(int256 a, int256 b) internal pure returns (int256) {

        // Prevent overflow when dividing MIN_INT256 by -1

        require(b != -1 || a != MIN_INT256);



        // Solidity already throws when dividing by 0.

        return a / b;

    }



    /**

     * @dev Subtracts two int256 variables and fails on overflow.

     */

    function sub(int256 a, int256 b) internal pure returns (int256) {

        int256 c = a - b;

        require((b >= 0 && c <= a) || (b < 0 && c > a));

        return c;

    }



    /**

     * @dev Adds two int256 variables and fails on overflow.

     */

    function add(int256 a, int256 b) internal pure returns (int256) {

        int256 c = a + b;

        require((b >= 0 && c >= a) || (b < 0 && c < a));

        return c;

    }



    /**

     * @dev Converts to absolute value, and fails on overflow.

     */

    function abs(int256 a) internal pure returns (int256) {

        require(a != MIN_INT256);

        return a < 0 ? -a : a;

    }





    function toUint256Safe(int256 a) internal pure returns (uint256) {

        require(a >= 0);

        return uint256(a);

    }

}



/**

 * @title SafeMathUint

 * @dev Math operations with safety checks that revert on error

 */

library SafeMathUint {

  function toInt256Safe(uint256 a) internal pure returns (int256) {

    int256 b = int256(a);

    require(b >= 0);

    return b;

  }

}



contract Ownable is Context {

    address private _owner;



    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);



    /**

     * @dev Initializes the contract setting the deployer as the initial owner.

     */

    constructor () {

        address msgSender = _msgSender();

        _owner = msgSender;

        emit OwnershipTransferred(address(0), msgSender);

    }



    /**

     * @dev Returns the address of the current owner.

     */

    function owner() public view returns (address) {

        return _owner;

    }



    /**

     * @dev Throws if called by any account other than the owner.

     */

    modifier onlyOwner() {

        require(_owner == _msgSender(), "Ownable: caller is not the owner");

        _;

    }



    /**

     * @dev Leaves the contract without owner. It will not be possible to call

     * `onlyOwner` functions anymore. Can only be called by the current owner.

     *

     * NOTE: Renouncing ownership will leave the contract without an owner,

     * thereby removing any functionality that is only available to the owner.

     */

    function renounceOwnership() public virtual onlyOwner {

        emit OwnershipTransferred(_owner, address(0));

        _owner = address(0);

    }



    /**

     * @dev Transfers ownership of the contract to a new account (`newOwner`).

     * Can only be called by the current owner.

     */

    function transferOwnership(address newOwner) public virtual onlyOwner {

        require(newOwner != address(0), "Ownable: new owner is the zero address");

        emit OwnershipTransferred(_owner, newOwner);

        _owner = newOwner;

    }

}



interface IPair {

    function sync() external;

}



interface IFactory{

        function createPair(address tokenA, address tokenB) external returns (address pair);

        function getPair(address tokenA, address tokenB) external view returns (address pair);

}



interface IRouter {

    function factory() external pure returns (address);

    function WETH() external pure returns (address);

    function addLiquidityETH(

        address token,

        uint amountTokenDesired,

        uint amountTokenMin,

        uint amountETHMin,

        address to,

        uint deadline

    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);

    

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(

        uint amountIn,

        uint amountOutMin,

        address[] calldata path,

        address to,

        uint deadline

    ) external;

    

    function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)

        external

        payable

        returns (uint[] memory amounts);



    function swapExactTokensForETHSupportingFeeOnTransferTokens(

        uint amountIn,

        uint amountOutMin,

        address[] calldata path,

        address to,

        uint deadline) external;

}



/// @title Dividend-Paying Token Interface

/// @author Roger Wu (https://github.com/roger-wu)

/// @dev An interface for a dividend-paying token contract.

interface DividendPayingTokenInterface {

  /// @notice View the amount of dividend in wei that an address can withdraw.

  /// @param _owner The address of a token holder.

  /// @return The amount of dividend in wei that `_owner` can withdraw.

  function dividendOf(address _owner) external view returns(uint256);

  

  function distributeDividends() external payable;

  

  /// @notice View the amount of dividend in wei that an address can withdraw.

  /// @param _owner The address of a token holder.

  /// @return The amount of dividend in wei that `_owner` can withdraw.

  function withdrawableDividendOf(address _owner) external view returns(uint256);



  /// @notice View the amount of dividend in wei that an address has withdrawn.

  /// @param _owner The address of a token holder.

  /// @return The amount of dividend in wei that `_owner` has withdrawn.

  function withdrawnDividendOf(address _owner) external view returns(uint256);



  /// @notice View the amount of dividend in wei that an address has earned in total.

  /// @dev accumulativeDividendOf(_owner) = withdrawableDividendOf(_owner) + withdrawnDividendOf(_owner)

  /// @param _owner The address of a token holder.

  /// @return The amount of dividend in wei that `_owner` has earned in total.

  function accumulativeDividendOf(address _owner) external view returns(uint256);





  /// @dev This event MUST emit when ether is distributed to token holders.

  /// @param from The address which sends ether to this contract.

  /// @param weiAmount The amount of distributed ether in wei.

  event DividendsDistributed(

    address indexed from,

    uint256 weiAmount

  );



  /// @dev This event MUST emit when an address withdraws their dividend.

  /// @param to The address which withdraws ether from this contract.

  /// @param weiAmount The amount of withdrawn ether in wei.

  event DividendWithdrawn(

    address indexed to,

    uint256 weiAmount

  );

  

}



contract DividendPayingToken is ERC20, DividendPayingTokenInterface, Ownable {

  using SafeMath for uint256;

  using SafeMathUint for uint256;

  using SafeMathInt for int256;



  // With `magnitude`, we can properly distribute dividends even if the amount of received ether is small.

  // For more discussion about choosing the value of `magnitude`,

  //  see https://github.com/ethereum/EIPs/issues/1726#issuecomment-472352728

  uint256 constant internal magnitude = 2**128;



  IRouter public router;

  address public rewardToken;



  uint256 internal magnifiedDividendPerShare;



  // About dividendCorrection:

  // If the token balance of a `_user` is never changed, the dividend of `_user` can be computed with:

  //   `dividendOf(_user) = dividendPerShare * balanceOf(_user)`.

  // When `balanceOf(_user)` is changed (via new tokens/burning/transferring tokens),

  //   `dividendOf(_user)` should not be changed,

  //   but the computed value of `dividendPerShare * balanceOf(_user)` is changed.

  // To keep the `dividendOf(_user)` unchanged, we add a correction term:

  //   `dividendOf(_user) = dividendPerShare * balanceOf(_user) + dividendCorrectionOf(_user)`,

  //   where `dividendCorrectionOf(_user)` is updated whenever `balanceOf(_user)` is changed:

  //   `dividendCorrectionOf(_user) = dividendPerShare * (old balanceOf(_user)) - (new balanceOf(_user))`.

  // So now `dividendOf(_user)` returns the same value before and after `balanceOf(_user)` is changed.

  mapping(address => int256) internal magnifiedDividendCorrections;

  mapping(address => uint256) internal withdrawnDividends;



  uint256 public totalDividendsDistributed;



  constructor(string memory _name, string memory _symbol)  ERC20(_name, _symbol) {

      IRouter _router = IRouter(0x10ED43C718714eb63d5aA57B78B54704E256024E);

      router = _router;

      rewardToken = 0x55d398326f99059fF775485246999027B3197955;

  }



    /// @dev Distributes dividends whenever ether is paid to this contract.

    receive() external payable{

        distributeDividends();

    }



     function distributeDividends() public override payable {

      require(totalSupply() > 0);



      if (msg.value > 0) {

        magnifiedDividendPerShare = magnifiedDividendPerShare.add(

          (msg.value).mul(magnitude) / totalSupply()

        );

        emit DividendsDistributed(msg.sender, msg.value);



        totalDividendsDistributed = totalDividendsDistributed.add(msg.value);

      }

    }



    /// @notice Withdraws the ether distributed to the sender.

    /// @dev It emits a `DividendWithdrawn` event if the amount of withdrawn ether is greater than 0.

    function _withdrawDividendOfUser(address payable user) internal returns (uint256) {

        uint256 _withdrawableDividend = withdrawableDividendOf(user);

        if (_withdrawableDividend > 0) {

            withdrawnDividends[user] = withdrawnDividends[user].add(_withdrawableDividend);

            emit DividendWithdrawn(user, _withdrawableDividend);

            if(rewardToken != router.WETH()){

                (bool success) = swapBnbForCustomToken(user, _withdrawableDividend);

                if(!success) {

                    (bool secondSuccess,) = user.call{value: _withdrawableDividend, gas: 3000}("");

                    if(!secondSuccess) {

                        withdrawnDividends[user] = withdrawnDividends[user].sub(_withdrawableDividend);

                        return 0;

                    }       

                }

            }

            else{

                (bool success,) = user.call{value: _withdrawableDividend, gas: 3000}("");

                if(!success) {

                    withdrawnDividends[user] = withdrawnDividends[user].sub(_withdrawableDividend);

                    return 0;

                }

            }

            return _withdrawableDividend;

        }

        return 0;

    }

    

    function setRewardToken(address newToken) external onlyOwner{

        rewardToken = newToken;

    }

  

    function swapBnbForCustomToken(address user, uint256 amt) internal returns (bool) {

          address[] memory path = new address[](2);

          path[0] = router.WETH();

          path[1] = rewardToken;



          try router.swapExactETHForTokens{value: amt}(0, path, user, block.timestamp + 2){

            return true;

        } catch {

            return false;

        }

    }



    /// @notice View the amount of dividend in wei that an address can withdraw.

    /// @param _owner The address of a token holder.

    /// @return The amount of dividend in wei that `_owner` can withdraw.

    function dividendOf(address _owner) public view override returns(uint256) {

      return withdrawableDividendOf(_owner);

    }



    /// @notice View the amount of dividend in wei that an address can withdraw.

    /// @param _owner The address of a token holder.

    /// @return The amount of dividend in wei that `_owner` can withdraw.

    function withdrawableDividendOf(address _owner) public view override returns(uint256) {

      return accumulativeDividendOf(_owner).sub(withdrawnDividends[_owner]);

    }



    /// @notice View the amount of dividend in wei that an address has withdrawn.

    /// @param _owner The address of a token holder.

    /// @return The amount of dividend in wei that `_owner` has withdrawn.

    function withdrawnDividendOf(address _owner) public view override returns(uint256) {

      return withdrawnDividends[_owner];

    }





    /// @notice View the amount of dividend in wei that an address has earned in total.

    /// @dev accumulativeDividendOf(_owner) = withdrawableDividendOf(_owner) + withdrawnDividendOf(_owner)

    /// = (magnifiedDividendPerShare * balanceOf(_owner) + magnifiedDividendCorrections[_owner]) / magnitude

    /// @param _owner The address of a token holder.

    /// @return The amount of dividend in wei that `_owner` has earned in total.

    function accumulativeDividendOf(address _owner) public view override returns(uint256) {

      return magnifiedDividendPerShare.mul(balanceOf(_owner)).toInt256Safe()

        .add(magnifiedDividendCorrections[_owner]).toUint256Safe() / magnitude;

    }



    /// @dev Internal function that transfer tokens from one address to another.

    /// Update magnifiedDividendCorrections to keep dividends unchanged.

    /// @param from The address to transfer from.

    /// @param to The address to transfer to.

    /// @param value The amount to be transferred.

    function _transfer(address from, address to, uint256 value) internal virtual override {

      require(false);



      int256 _magCorrection = magnifiedDividendPerShare.mul(value).toInt256Safe();

      magnifiedDividendCorrections[from] = magnifiedDividendCorrections[from].add(_magCorrection);

      magnifiedDividendCorrections[to] = magnifiedDividendCorrections[to].sub(_magCorrection);

    }



    /// Update magnifiedDividendCorrections to keep dividends unchanged.

    /// @param account The account that will receive the created tokens.

    /// @param value The amount that will be created.

    function _tokengeneration(address account, uint256 value) internal override {

      super._tokengeneration(account, value);



      magnifiedDividendCorrections[account] = magnifiedDividendCorrections[account]

        .sub( (magnifiedDividendPerShare.mul(value)).toInt256Safe() );

    }



    /// @dev Internal function that burns an amount of the token of a given account.

    /// Update magnifiedDividendCorrections to keep dividends unchanged.

    /// @param account The account whose tokens will be burnt.

    /// @param value The amount that will be burnt.

    function _burn(address account, uint256 value) internal override {

      super._burn(account, value);



      magnifiedDividendCorrections[account] = magnifiedDividendCorrections[account]

        .add( (magnifiedDividendPerShare.mul(value)).toInt256Safe() );

    }



    function _setBalance(address account, uint256 newBalance) internal {

      uint256 currentBalance = balanceOf(account);



      if(newBalance > currentBalance) {

        uint256 rewardtokensAmount = newBalance.sub(currentBalance);

        _tokengeneration(account, rewardtokensAmount);

      } else if(newBalance < currentBalance) {

        uint256 burnAmount = currentBalance.sub(newBalance);

        _burn(account, burnAmount);

      }

    }

  }



library IterableMapping {

    // Iterable mapping from address to uint;

    struct Map {

        address[] keys;

        mapping(address => uint) values;

        mapping(address => uint) indexOf;

        mapping(address => bool) inserted;

    }



    function get(Map storage map, address key) public view returns (uint) {

        return map.values[key];

    }



    function getIndexOfKey(Map storage map, address key) public view returns (int) {

        if(!map.inserted[key]) {

            return -1;

        }

        return int(map.indexOf[key]);

    }



    function getKeyAtIndex(Map storage map, uint index) public view returns (address) {

        return map.keys[index];

    }







    function size(Map storage map) public view returns (uint) {

        return map.keys.length;

    }



    function set(Map storage map, address key, uint val) public {

        if (map.inserted[key]) {

            map.values[key] = val;

        } else {

            map.inserted[key] = true;

            map.values[key] = val;

            map.indexOf[key] = map.keys.length;

            map.keys.push(key);

        }

    }



    function remove(Map storage map, address key) public {

        if (!map.inserted[key]) {

            return;

        }



        delete map.inserted[key];

        delete map.values[key];



        uint index = map.indexOf[key];

        uint lastIndex = map.keys.length - 1;

        address lastKey = map.keys[lastIndex];



        map.indexOf[lastKey] = index;

        delete map.indexOf[key];



        map.keys[index] = lastKey;

        map.keys.pop();

    }

}



library Address {

    function sendValue(address payable recipient, uint256 amount) internal {

        require(address(this).balance >= amount, "Address: insufficient balance");



        (bool success, ) = recipient.call{ value: amount }("");

        require(success, "Address: unable to send value, recipient may have reverted");

    }

}



contract DreamAi is ERC20, Ownable {

    using Address for address payable;



    IRouter public router;

    address public pair;



    bool private swapping;

    bool public swapEnabled = true;

    bool public tradingEnabled = false;

    uint256 public startTradingBlock;



    DreamAi_DividendTracker public dividendTracker;

    

    address public constant deadWallet = 0x000000000000000000000000000000000000dEaD;

    address public marketingWallet = 0xb54C5B1E0E8c7902456FFA711E139181e29dC062;

    address public developmentWallet = 0xf579326E9659465dB5C4C10Be9C1412c0eCb4923;



    uint256 public swapTokensAtAmount = 2e5 * 10**9;

    

    string private currentRewardToken;



    struct Taxes {

        uint256 rewards;

        uint256 marketing;

        uint256 development;

        uint256 liquidity;

    }



    Taxes public buyTaxes = Taxes(2, 2, 1, 0);

    Taxes public sellTaxes = Taxes(2, 2, 2, 2);



    // use by default 300,000 gas to process auto-claiming dividends

    uint256 public gasForProcessing = 300000;



    uint256 private antiBotBlocks = 0;

    uint256 private launchtax = 99;

    

    mapping(address => bool) private _isExcludedFromFees;

    mapping(address => bool) public automatedMarketMakerPairs;



    event ExcludeFromFees(address indexed account, bool isExcluded);

    event ExcludeMultipleAccountsFromFees(address[] accounts, bool isExcluded);

    event SetAutomatedMarketMakerPair(address indexed pair, bool indexed value);

    event GasForProcessingUpdated(uint256 indexed newValue, uint256 indexed oldValue);

    event SendDividends(uint256 tokensSwapped, uint256 amount);

    event ProcessedDividendTracker(

        uint256 iterations,

        uint256 claims,

        uint256 lastProcessedIndex,

        bool indexed automatic,

        uint256 gas,

        address indexed processor

    );



    constructor() ERC20("DreamAi", "DRM") {

        dividendTracker = new DreamAi_DividendTracker();



        IRouter _router = IRouter(0x10ED43C718714eb63d5aA57B78B54704E256024E);

        address _pair = IFactory(_router.factory()).createPair(address(this), _router.WETH());



        router = _router;

        pair = _pair;



        _setAutomatedMarketMakerPair(_pair, true);



        dividendTracker.excludeFromDividends(address(dividendTracker), true);

        dividendTracker.excludeFromDividends(address(this), true);

        dividendTracker.excludeFromDividends(owner(), true);

        dividendTracker.excludeFromDividends(deadWallet, true);

        dividendTracker.excludeFromDividends(address(_router), true);



        excludeFromFees(owner(), true);

        excludeFromFees(marketingWallet, true);

        excludeFromFees(developmentWallet, true);

        excludeFromFees(address(this), true);



        /*

            _tokengeneration is an internal function in ERC20.sol that is only called here,

            and CANNOT be called ever again

        */

        _tokengeneration(owner(), 1e8 * (10**9));

    }



    receive() external payable {}



    function updateDividendTracker(address newAddress) public onlyOwner {

        DreamAi_DividendTracker newDividendTracker = DreamAi_DividendTracker(

            payable(newAddress)

        );



        newDividendTracker.excludeFromDividends(address(newDividendTracker), true);

        newDividendTracker.excludeFromDividends(address(this), true);

        newDividendTracker.excludeFromDividends(owner(), true);

        newDividendTracker.excludeFromDividends(address(router), true);

        dividendTracker = newDividendTracker;

    }



    function processDividendTracker(uint256 gas) external {

        (uint256 iterations, uint256 claims, uint256 lastProcessedIndex) = dividendTracker

            .process(gas);

        emit ProcessedDividendTracker(

            iterations,

            claims,

            lastProcessedIndex,

            false,

            gas,

            tx.origin

        );

    }



    /// @notice Manual claim the dividends after claimWait is passed

    ///    This can be useful during low volume days.

    function claim() external {

        dividendTracker.processAccount(payable(msg.sender), false);

    }



    /// @notice Withdraw tokens sent by mistake.

    /// @param tokenAddress The address of the token to withdraw

    function rescueBEP20Tokens(address tokenAddress) external onlyOwner {

        require(tokenAddress != address(this), "Owner can't claim contract's balance of its own tokens");

        IERC20(tokenAddress).transfer(msg.sender,IERC20(tokenAddress).balanceOf(address(this)));

    }



    function forceSend() external {

        uint256 BNBbalance = address(this).balance;

        payable(owner()).sendValue(BNBbalance);

    }



    /////////////////////////////////

    // Exclude / Include functions //

    /////////////////////////////////



    function excludeFromFees(address account, bool excluded) public onlyOwner {

        require(

            _isExcludedFromFees[account] != excluded,

            "Account is already the value of 'excluded'"

        );

        _isExcludedFromFees[account] = excluded;



        emit ExcludeFromFees(account, excluded);

    }



    function excludeMultipleAccountsFromFees(address[] calldata accounts, bool excluded)

        public

        onlyOwner

    {

        for (uint256 i = 0; i < accounts.length; i++) {

            _isExcludedFromFees[accounts[i]] = excluded;

        }

        emit ExcludeMultipleAccountsFromFees(accounts, excluded);

    }



    /// @dev "true" to exlcude, "false" to include

    function excludeFromDividends(address account, bool value) external onlyOwner {

        dividendTracker.excludeFromDividends(account, value);

    }



    ///////////////////////

    //  Setter Functions //

    ///////////////////////



    function setMarketingWallet(address newWallet) external onlyOwner {

        require(newWallet != address(this), "Fee Address cannot be Contract Address");

        require(newWallet != address(0),"Fee Address cannot be zero address");

        marketingWallet = newWallet;

    }



     function setdevelopmentWallet(address newWallet) external onlyOwner {

        require(newWallet != address(this), "Fee Address cannot be Contract Address");

        require(newWallet != address(0),"Fee Address cannot be zero address");

        developmentWallet = newWallet;

    }





    function setSwapTokensAtAmount(uint256 amount) external onlyOwner {

        swapTokensAtAmount = amount * 10**9;

    }



    function setBuyTaxes(uint256 _rewards, uint256 _marketing, uint256 _development, uint256 _liquidity) external onlyOwner{

        buyTaxes = Taxes(_rewards, _marketing, _development, _liquidity);

        require((_rewards + _marketing + _development + _liquidity ) <= 12, "Must keep fees at 12% or less");

    }



    function setSellTaxes(uint256 _rewards, uint256 _marketing, uint256 _development, uint256 _liquidity) external onlyOwner{

        sellTaxes = Taxes(_rewards, _marketing, _development, _liquidity);

        require((_rewards + _marketing + _development + _liquidity ) <= 12, "Must keep fees at 12% or less");

    }



    function setSwapEnabled(bool _enabled) external onlyOwner {

        swapEnabled = _enabled;

    }    



    function enableTradingEnabled() external onlyOwner {

        require(!tradingEnabled, "Trading is already enabled");

        tradingEnabled = true;

        startTradingBlock = block.number;

    }



    function setAntiBotBlocks(uint256 numberOfBlocks) external onlyOwner{

        require(!tradingEnabled, "Can't change when trading has started");

        require(numberOfBlocks < 5,"Deadline should be less than 5 Blocks");

        antiBotBlocks = numberOfBlocks;

    }



    function setMinBalanceForDividends(uint256 amount) external onlyOwner {

        dividendTracker.setMinBalanceForDividends(amount);

    }

    

    

    function _setAutomatedMarketMakerPair(address newPair, bool value) private {

        require(automatedMarketMakerPairs[newPair] != value,"Automated market maker pair is already set to that value");

        automatedMarketMakerPairs[newPair] = value;



        if (value) {

            dividendTracker.excludeFromDividends(newPair, true);

        }



        emit SetAutomatedMarketMakerPair(newPair, value);

    }



    /// @notice Update the gasForProcessing needed to auto-distribute rewards

    /// @param newValue The new amount of gas needed

    /// @dev The amount should not be greater than 500k to avoid expensive transactions

    function setGasForProcessing(uint256 newValue) external onlyOwner {

        require(

            newValue >= 200000 && newValue <= 500000,

            "GasForProcessing must be between 200,000 and 500,000"

        );

        require(

            newValue != gasForProcessing,

            "Cannot update gasForProcessing to same value"

        );

        emit GasForProcessingUpdated(newValue, gasForProcessing);

        gasForProcessing = newValue;

    }



    /// @dev Update the dividendTracker claimWait

    function setClaimWait(uint256 claimWait) external onlyOwner {

        dividendTracker.updateClaimWait(claimWait);

    }



    //////////////////////

    // Getter Functions //

    //////////////////////



    function getClaimWait() external view returns (uint256) {

        return dividendTracker.claimWait();

    }



    function getTotalDividendsDistributed() external view returns (uint256) {

        return dividendTracker.totalDividendsDistributed();

    }



    function isExcludedFromFees(address account) public view returns (bool) {

        return _isExcludedFromFees[account];

    }



    function withdrawableDividendOf(address account) public view returns (uint256) {

        return dividendTracker.withdrawableDividendOf(account);

    }



    function getCurrentRewardToken() external view returns (string memory) {

        return dividendTracker.getCurrentRewardToken();

    }



    function dividendTokenBalanceOf(address account) public view returns (uint256) {

        return dividendTracker.balanceOf(account);

    }



    function getAccountDividendsInfo(address account)

        external

        view

        returns (

            address,

            int256,

            int256,

            uint256,

            uint256,

            uint256,

            uint256,

            uint256

        )

    {

        return dividendTracker.getAccount(account);

    }



    function getAccountDividendsInfoAtIndex(uint256 index)

        external

        view

        returns (

            address,

            int256,

            int256,

            uint256,

            uint256,

            uint256,

            uint256,

            uint256

        )

    {

        return dividendTracker.getAccountAtIndex(index);

    }



    function getLastProcessedIndex() external view returns (uint256) {

        return dividendTracker.getLastProcessedIndex();

    }



    function getNumberOfDividendTokenHolders() external view returns (uint256) {

        return dividendTracker.getNumberOfTokenHolders();

    }



    ////////////////////////

    // Transfer Functions //

    ////////////////////////



    function _transfer(

        address from,

        address to,

        uint256 amount

    ) internal override {

        require(from != address(0), "ERC20: transfer from the zero address");

        require(to != address(0), "ERC20: transfer to the zero address");



        if (!_isExcludedFromFees[from] && !_isExcludedFromFees[to]) {

                require(tradingEnabled, "Trading no active");

        }

       

        if (amount == 0) {

            super._transfer(from, to, 0);

            return;

        }



        uint256 contractTokenBalance = balanceOf(address(this));

        bool canSwap = contractTokenBalance >= swapTokensAtAmount;

        uint256 swapTax = sellTaxes.rewards + sellTaxes.marketing + sellTaxes.development + sellTaxes.liquidity;

        

        if (

            canSwap &&

            !swapping &&

            swapEnabled &&

            !automatedMarketMakerPairs[from] &&

            !_isExcludedFromFees[from] &&

            !_isExcludedFromFees[to]

        ) {

            swapping = true;



            if (swapTax > 0) {

                swapAndLiquify(swapTokensAtAmount, swapTax);

            }



            swapping = false;

        }



        bool takeFee = !swapping;



        if (_isExcludedFromFees[from] || _isExcludedFromFees[to]) {

            takeFee = false;

        }

            if (takeFee) {

            bool useLaunchFee = block.number <= startTradingBlock + antiBotBlocks;

            uint256 swapAmt;

            

            if (automatedMarketMakerPairs[to] && !useLaunchFee) {

                swapAmt = (amount * swapTax) / 100;

            

            } else if (automatedMarketMakerPairs[from] && !useLaunchFee) {

            swapAmt = (amount * (buyTaxes.rewards + buyTaxes.marketing + buyTaxes.development + buyTaxes.liquidity )) / 100;

            

            } else if (useLaunchFee) {

                swapAmt = (amount * launchtax) / 100; 

            }

            

            amount = amount - (swapAmt);

            super._transfer(from, address(this), swapAmt);

        }

        

        super._transfer(from, to, amount);

        

        try dividendTracker.setBalance(from, balanceOf(from)) {} catch {}

        try dividendTracker.setBalance(to, balanceOf(to)) {} catch {}



        if (!swapping) {

            uint256 gas = gasForProcessing;



            try dividendTracker.process(gas) returns (

                uint256 iterations,

                uint256 claims,

                uint256 lastProcessedIndex

            ) {

                emit ProcessedDividendTracker(

                    iterations,

                    claims,

                    lastProcessedIndex,

                    true,

                    gas,

                    tx.origin

                );

            } catch {}

        }

    }



    function swapAndLiquify(uint256 tokens, uint256 swapTax) private {

        

        uint256 denominator = swapTax * 2;

        uint256 tokensToAddLiquidityWith = (tokens * sellTaxes.liquidity) / denominator;

        uint256 toSwap = tokens - tokensToAddLiquidityWith;



        uint256 initialBalance = address(this).balance;



        swapTokensForBNB(toSwap);



        uint256 deltaBalance = address(this).balance - initialBalance;

        uint256 unitBalance = deltaBalance / (denominator - sellTaxes.liquidity);

        uint256 bnbToAddLiquidityWith = unitBalance * sellTaxes.liquidity;



        if (bnbToAddLiquidityWith > 0) {

            // Add liquidity to pancake

            addLiquidity(tokensToAddLiquidityWith, bnbToAddLiquidityWith);

        }



       

        uint256 marketingWalletAmt = unitBalance * 2 * sellTaxes.marketing;

        if (marketingWalletAmt > 0) {

            payable(marketingWallet).sendValue(marketingWalletAmt);

        }



       uint256 developmentAmt = unitBalance * 2 * sellTaxes.development;

        if (developmentAmt > 0) {

            payable(developmentWallet).sendValue(developmentAmt);

        }



        uint256 dividends = unitBalance * 2 * sellTaxes.rewards;

        if (dividends > 0) {

            (bool success, ) = address(dividendTracker).call{ value: dividends }("");

            if (success) emit SendDividends(tokens, dividends);

        }

    }



    function swapTokensForBNB(uint256 tokenAmount) private {

        address[] memory path = new address[](2);

        path[0] = address(this);

        path[1] = router.WETH();



        _approve(address(this), address(router), tokenAmount);



        router.swapExactTokensForETHSupportingFeeOnTransferTokens(

            tokenAmount,

            0, // accept any amount of ETH

            path,

            address(this),

            block.timestamp

        );

    }



    function addLiquidity(uint256 tokenAmount, uint256 ethAmount) private {

        // approve token transfer to cover all possible scenarios

        _approve(address(this), address(router), tokenAmount);



        // add the liquidity

        router.addLiquidityETH{ value: ethAmount }(

            address(this),

            tokenAmount,

            0, // slippage is unavoidable

            0, // slippage is unavoidable

            owner(),

            block.timestamp

        );

    }

}



contract DreamAi_DividendTracker is Ownable, DividendPayingToken {

    using SafeMath for uint256;

    using SafeMathInt for int256;

    using IterableMapping for IterableMapping.Map;



    IterableMapping.Map private tokenHoldersMap;

    uint256 public lastProcessedIndex;



    mapping(address => bool) public excludedFromDividends;



    mapping(address => uint256) public lastClaimTimes;



    uint256 public claimWait;

    uint256 public minimumTokenBalanceForDividends;



    event ExcludeFromDividends(address indexed account, bool value);

    event ClaimWaitUpdated(uint256 indexed newValue, uint256 indexed oldValue);



    event Claim(address indexed account, uint256 amount, bool indexed automatic);



    constructor()

        DividendPayingToken("DreamAi_Dividen_Tracker", "DreamAi_Dividend_Tracker")

    {

        claimWait = 3600;

        minimumTokenBalanceForDividends = 10000 * (10**decimals()); 

    }



    function _transfer(

        address,

        address,

        uint256

    ) internal pure override {

        require(false, "DreamAi_Dividend_Tracker: No transfers allowed");

    }



    function setMinBalanceForDividends(uint256 amount) external onlyOwner {

        minimumTokenBalanceForDividends = amount * 10**decimals();

    }



    function excludeFromDividends(address account, bool value) external onlyOwner {

        require(excludedFromDividends[account] != value);

        excludedFromDividends[account] = value;

        if (value == true) {

            _setBalance(account, 0);

            tokenHoldersMap.remove(account);

        } else {

            _setBalance(account, balanceOf(account));

            tokenHoldersMap.set(account, balanceOf(account));

        }

        emit ExcludeFromDividends(account, value);

    }



    function updateClaimWait(uint256 newClaimWait) external onlyOwner {

        require(

            newClaimWait >= 3600 && newClaimWait <= 86400,

            "DreamAi_Dividend_Tracker: claimWait must be updated to between 1 and 24 hours"

        );

        require(

            newClaimWait != claimWait,

            "DreamAi_Dividend_Tracker: Cannot update claimWait to same value"

        );

        emit ClaimWaitUpdated(newClaimWait, claimWait);

        claimWait = newClaimWait;

    }



    function getLastProcessedIndex() external view returns (uint256) {

        return lastProcessedIndex;

    }



    function getNumberOfTokenHolders() external view returns (uint256) {

        return tokenHoldersMap.keys.length;

    }



    function getCurrentRewardToken() external view returns (string memory) {

        return IERC20Metadata(rewardToken).name();

    }



    function getAccount(address _account)

        public

        view

        returns (

            address account,

            int256 index,

            int256 iterationsUntilProcessed,

            uint256 withdrawableDividends,

            uint256 totalDividends,

            uint256 lastClaimTime,

            uint256 nextClaimTime,

            uint256 secondsUntilAutoClaimAvailable

        )

    {

        account = _account;



        index = tokenHoldersMap.getIndexOfKey(account);



        iterationsUntilProcessed = -1;



        if (index >= 0) {

            if (uint256(index) > lastProcessedIndex) {

                iterationsUntilProcessed = index.sub(int256(lastProcessedIndex));

            } else {

                uint256 processesUntilEndOfArray = tokenHoldersMap.keys.length >

                    lastProcessedIndex

                    ? tokenHoldersMap.keys.length.sub(lastProcessedIndex)

                    : 0;



                iterationsUntilProcessed = index + (int256(processesUntilEndOfArray));

            }

        }



        withdrawableDividends = withdrawableDividendOf(account);

        totalDividends = accumulativeDividendOf(account);



        lastClaimTime = lastClaimTimes[account];



        nextClaimTime = lastClaimTime > 0 ? lastClaimTime + (claimWait) : 0;



        secondsUntilAutoClaimAvailable = nextClaimTime > block.timestamp

            ? nextClaimTime.sub(block.timestamp)

            : 0;

    }



    function getAccountAtIndex(uint256 index)

        public

        view

        returns (

            address,

            int256,

            int256,

            uint256,

            uint256,

            uint256,

            uint256,

            uint256

        )

    {

        if (index >= tokenHoldersMap.size()) {

            return (0x0000000000000000000000000000000000000000, -1, -1, 0, 0, 0, 0, 0);

        }



        address account = tokenHoldersMap.getKeyAtIndex(index);



        return getAccount(account);

    }



    function canAutoClaim(uint256 lastClaimTime) private view returns (bool) {

        if (lastClaimTime > block.timestamp) {

            return false;

        }



        return block.timestamp.sub(lastClaimTime) >= claimWait;

    }



    function setBalance(address account, uint256 newBalance) public onlyOwner {

        if (excludedFromDividends[account]) {

            return;

        }



        if (newBalance >= minimumTokenBalanceForDividends) {

            _setBalance(account, newBalance);

            tokenHoldersMap.set(account, newBalance);

        } else {

            _setBalance(account, 0);

            tokenHoldersMap.remove(account);

        }



        processAccount(payable(account), true);

    }



    function process(uint256 gas)

        public

        returns (

            uint256,

            uint256,

            uint256

        )

    {

        uint256 numberOfTokenHolders = tokenHoldersMap.keys.length;



        if (numberOfTokenHolders == 0) {

            return (0, 0, lastProcessedIndex);

        }



        uint256 _lastProcessedIndex = lastProcessedIndex;



        uint256 gasUsed = 0;



        uint256 gasLeft = gasleft();



        uint256 iterations = 0;

        uint256 claims = 0;



        while (gasUsed < gas && iterations < numberOfTokenHolders) {

            _lastProcessedIndex++;



            if (_lastProcessedIndex >= tokenHoldersMap.keys.length) {

                _lastProcessedIndex = 0;

            }



            address account = tokenHoldersMap.keys[_lastProcessedIndex];



            if (canAutoClaim(lastClaimTimes[account])) {

                if (processAccount(payable(account), true)) {

                    claims++;

                }

            }



            iterations++;



            uint256 newGasLeft = gasleft();



            if (gasLeft > newGasLeft) {

                gasUsed = gasUsed + (gasLeft.sub(newGasLeft));

            }



            gasLeft = newGasLeft;

        }



        lastProcessedIndex = _lastProcessedIndex;



        return (iterations, claims, lastProcessedIndex);

    }



    function processAccount(address payable account, bool automatic)

        public

        onlyOwner

        returns (bool)

    {

        uint256 amount = _withdrawDividendOfUser(account);



        if (amount > 0) {

            lastClaimTimes[account] = block.timestamp;

            emit Claim(account, amount, automatic);

            return true;

        }



        return false;

    }

}

Vulnerability type: CWE-707|CWE-20