// File: Aggregate.sol




pragma solidity ^0.8.0;

import "./ERC20.sol";
import "./Ownable.sol";
import "./Pausable.sol";

    /// @title A Fee on Transfer token with automatic reflections to holders.
    /// @notice Token contract inheriting ERC20 standard with basic access
    /// control and emergency pause mechanism. The token contract implements
    /// Fee on Transfer distributed among marketing wallet, acquisition wallets,
    /// and all token holders (via reflections) on Buy / Sell transactions
    /// only. Wallet-to-wallet transfers do not incur a fee on transfer.
contract Aggregate is ERC20, Pausable, Ownable {

    //--------------------------State Variables---------------------------------

    struct FeeValues {
          uint256 Amount;
          uint256 TransferAmount;
          uint256 ReflectFee;
          uint256 MarketingFee;
          uint256 AcquisitionFee;
      }
    enum MarketSide {
      NONE,
      BUY,
      SELL
    }

    mapping (address => uint256) private _rOwned;
    mapping (address => uint256) private _tOwned;
    mapping (address => bool) private _isExcluded;
    address[] private _excluded;
    uint256 private _tTotal;
    uint256 private _rTotal;
    uint256 private _tFeeTotal;

    address private _marketingWallet;
    address[5] private _acquisitionWallets;
    mapping (address => bool) private _isExchange;

    uint8 private _buyFeeReflect;
    uint8 private _buyFeeMarketing;
    uint8 private _buyFeeAcquisition;
    uint8 private _sellFeeReflect;
    uint8 private _sellFeeMarketing;
    uint8 private _sellFeeAcquisition;

    //--------------------------Constructor-------------------------------------

    /// @notice Sets the values for name, symbol, totalSupply, marketingWallet,
    /// and acquisitionWallets. Initial allocation: 95% to Admin account (for
    /// liquidity), 2% to Marketing wallet, 3% to Acquisition wallets.
    /// @param name_ is token name.
    /// @param symbol_ is token symbol.
    /// @param supply_ is total token supply.
    /// @param marketing_ is inital marketing wallet address.
    /// @param acquisition_ is list of initial 5 acquisition wallet addresses.
    constructor (
      string memory name_,
      string memory symbol_,
      uint256 supply_,
      address marketing_,
      address[] memory acquisition_
      ) {

      _name = name_;
      _symbol = symbol_;
      _tTotal = supply_ * 10**4;
      _rTotal = (~uint256(0) - (~uint256(0) % _tTotal));
      _buyFeeReflect = 1;
      _buyFeeMarketing = 1;
      _buyFeeAcquisition = 7;
      _sellFeeReflect = 5;
      _sellFeeMarketing = 1;
      _sellFeeAcquisition = 3;
      _marketingWallet = marketing_;
      for(uint i = 0; i < _acquisitionWallets.length; i++) {
        _acquisitionWallets[i] = acquisition_[i];
      }

      _tOwned[_msgSender()] += _tTotal * 95 / 100;
      _rOwned[_msgSender()] += _rTotal / 100 * 95;
      emit Transfer(address(0), _msgSender(), _tOwned[_msgSender()]);

      _tOwned[_marketingWallet] += _tTotal * 2 / 100;
      _rOwned[_marketingWallet] += _rTotal / 100 * 2;
      emit Transfer(address(0), _marketingWallet, _tTotal * 2 / 100);

      for(uint i = 0; i < _acquisitionWallets.length; i++){
        _tOwned[_acquisitionWallets[i]] +=
          _tTotal * 3 / 100 / _acquisitionWallets.length;
        _rOwned[_acquisitionWallets[i]] +=
          _rTotal / 100 * 3 / _acquisitionWallets.length;

        emit Transfer(
          address(0),
          _acquisitionWallets[i],
          _tTotal * 3 / 100 / _acquisitionWallets.length
          );
      }

    }

    //--------------------------ERC20 Override Functions------------------------

    /// @notice See {IERC20-totalSupply}.
    /// @dev Overrides ERC20 totalSupply function.
    /// @return supply_ is total token supply.
    function totalSupply() public view override returns (uint256) {
        return _tTotal;
    }

    /// @notice See {IERC20-balanceOf}.
    /// @dev Overrides ERC20 balanceOf function. If account is excluded then
    /// _tOwned balance is returned since that tracks token balance without
    /// reflections. Otherwise, _rOwned balance is returned after scaling down
    /// by reflection rate.
    /// @param account is address to be checked for token balance.
    /// @return balance_ is token balance of 'account'.
    function balanceOf(address account) public view override returns (uint256) {
        if (_isExcluded[account]) return _tOwned[account];
        return tokenFromReflection(_rOwned[account]);
    }

    /// @notice Number of decimals for token representation.
    /// @dev Overrides ERC20 decimals function. Value of 4 decimals is required
    /// to maintain precision of arithmetic operations for reflection fee
    /// distributions, given the token supply.
    /// @return decimals_ is number of decimals for display purposes.
    function decimals() public pure override returns (uint8) {
        return 4;
    }

    /// @notice See {IERC20-transfer}.
    /// @dev Overrides ERC20 _transfer function. Requires 'sender' and
    /// 'recipient' to be non-zero address to prevent minting/burning and
    /// non-zero transfer amount. Function determines transaction type 'BUY',
    /// 'SELL', or 'NONE' depending on whether sender or recipient is exchange
    /// pair address. Actual token transfer is delegated to {_transferStandard}.
    /// Function is pausable by token administrator.
    /// @param sender is address sending token.
    /// @param recipient is address receiving token.
    /// @param amount is number of tokens being transferred.
    function _transfer(
      address sender,
      address recipient,
      uint256 amount
      ) internal override whenNotPaused {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");
        require(amount > 0, "ERC20: transfer amount must be greater than zero");
        uint256 senderBalance = balanceOf(sender);
        require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");

        MarketSide _side;
        if(_isExchange[sender]){
            _side = MarketSide.BUY;
        } else if(_isExchange[recipient]) {
            _side = MarketSide.SELL;
        } else {
            _side = MarketSide.NONE;
        }

        _transferStandard(sender, recipient, amount, _side);
    }

    //--------------------------View Functions----------------------------------

    /// @notice Provides scaled down amount based on current reflection rate.
    /// @dev Helper function for balanceOf function. Scales down a given amount,
    /// inclusive of reflections, by reflection rate.
    /// @param rAmount is the amount, inclusive of reflections, to be scaled
    /// down by reflection rate.
    /// @return tAmount_ is amount scaled down by current reflection rate.
    function tokenFromReflection(uint256 rAmount) public view returns(uint256) {
        require(rAmount <= _rTotal, "Amount must be less than total supply");
        uint256 currentRate =  _getRate();
        return rAmount / currentRate;
    }

    /// @notice Allows checking whether an account has been excluded from
    /// receiving reflection distributions.
    /// @param account is address to be checked if excluded from reflections.
    /// @return excluded_ is true if account is excluded, otherwise, returns
    /// false.
    function isExcluded(address account) public view returns (bool) {
        return _isExcluded[account];
    }

    /// @notice Returns which address is receiving marketing fees
    /// from 'BUY' / 'SELL' transactions.
    function getMarketingWallet() public view returns (address){
      return _marketingWallet;
    }

    /// @notice Returns which address is receiving acquisition fees
    /// from 'BUY' / 'SELL' transactions at a given index.
    /// @param index is number between 0 - 4 representing wallets 1 through 5.
    function getAcquisitionWallet(uint256 index) public view returns (address){
      require(index < _acquisitionWallets.length, "Invalid index");
      return _acquisitionWallets[index];
    }

    /// @notice Allows to view total amount of reflection fees collected since
    /// contract creation.
    /// @return totalFees_ is total reflection fees collected.
    function totalFees() public view returns (uint256) {
        return _tFeeTotal;
    }

    //--------------------------Token Transfer----------------------------------

    /// @dev Updates _rOwned and _tOwned balances after deducting applicable
    /// transaction fees and allocates fees to marketing and acquisition
    /// wallets. {_getValues} helper function calculates all relevant amounts.
    /// Emits a {Transfer} event after the balances have been updated.
    /// @param sender is address sending token.
    /// @param recipient is address receiving token.
    /// @param tAmount is number of tokens being transferred.
    /// @param _side is transaction type: 'BUY', 'SELL', 'NONE'.
    function _transferStandard(
      address sender,
      address recipient,
      uint256 tAmount,
      MarketSide _side
      ) private {

        (
          FeeValues memory _tValues,
          FeeValues memory _rValues
          ) = _getValues(tAmount, _side);

        if(_isExcluded[sender]){
          _tOwned[sender] -= _tValues.Amount;
          _rOwned[sender] -= _rValues.Amount;
        } else {
          _rOwned[sender] -= _rValues.Amount;
        }

        if(_isExcluded[recipient]){
          _tOwned[recipient] += _tValues.TransferAmount;
          _rOwned[recipient] += _rValues.TransferAmount;
        } else {
          _rOwned[recipient] += _rValues.TransferAmount;
        }
        emit Transfer(sender, recipient, _tValues.TransferAmount);

        if(_side != MarketSide.NONE){
          _reflectFee(_rValues.ReflectFee, _tValues.ReflectFee);
          if(_tValues.MarketingFee > 0) {
            if(_isExcluded[_marketingWallet]){
              _tOwned[_marketingWallet] += _tValues.MarketingFee;
              _rOwned[_marketingWallet] += _rValues.MarketingFee;
            } else {
              _rOwned[_marketingWallet] += _rValues.MarketingFee;
            }
            emit Transfer(sender, _marketingWallet, _tValues.MarketingFee);
          }

          if(_tValues.AcquisitionFee > 0) {
            _acquisitionWalletAlloc(
              sender, _tValues.AcquisitionFee,
              _rValues.AcquisitionFee
              );
          }
        }
    }

    /// @dev Allocates the acquisition wallet fees to each of the five
    /// acquisition addresses in equal proportion.
    /// @param sender is address sending token.
    /// @param tAmount is amount of tokens to be allocated.
    /// @param rAmount is scaled up amount, inclusive of reflections, of tokens
    /// to be allocated.
    function _acquisitionWalletAlloc(
      address sender,
      uint256 tAmount,
      uint256 rAmount
      ) private {
        uint256 _tAllocation = tAmount / _acquisitionWallets.length;
        uint256 _rAllocation = rAmount / _acquisitionWallets.length;

        for(uint i = 0; i < _acquisitionWallets.length; i++){
          if(_isExcluded[_acquisitionWallets[i]]){
            _tOwned[_acquisitionWallets[i]] += _tAllocation;
            _rOwned[_acquisitionWallets[i]] += _rAllocation;
          } else {
            _rOwned[_acquisitionWallets[i]] += _rAllocation;
          }
          emit Transfer(sender, _acquisitionWallets[i], _tAllocation);
        }
    }

    //--------------------------Fee Calculation---------------------------------

    /// @dev Updates {_rTotal} supply by subtracting reflection fees. Updates
    /// {_tFeeTotal} to add reflection fees. This is used to update the
    /// reflection rate to calculate users' balances included in reflection.
    /// @param rFee Scaled up reflection fees from transaction
    /// @param tFee Actual reflection fees from transaction
    function _reflectFee(uint256 rFee, uint256 tFee) private {
        _rTotal = _rTotal - rFee;
        _tFeeTotal = _tFeeTotal + tFee;
    }

    /// @dev Calculates the required fees to be deducted for given transaction
    /// amount and transaction type.
    /// @param tAmount is the amount being transferred by user.
    /// @param _side is the transaction type: {BUY}, {SELL}, {NONE}.
    /// @return tValues_ is the calculated actual fee values for transfer
    /// amount {tAmount}.
    function _getValues(
      uint256 tAmount,
      MarketSide _side
      ) private view returns (
        FeeValues memory tValues_,
        FeeValues memory rValues_
        ) {

        uint256 currentRate =  _getRate();
        FeeValues memory _tValues = _getTValues(tAmount, _side);
        FeeValues memory _rValues = _getRValues(_tValues, currentRate);

        return (_tValues, _rValues);
    }

    /// @dev Function call {_getFeeValues} to obtain the relevant fee
    /// percentage for the {_side} transaction type. Calculates the actual
    /// marketing, acquistion, and reflection fees to be deducted from the
    /// transfer amount.
    /// @param tAmount is the amount being transferred by user.
    /// @param _side is the transaction type: 'BUY', 'SELL', 'NONE'.
    function _getTValues(
      uint256 tAmount,
      MarketSide _side
      ) private view returns (FeeValues memory) {
        (
          uint8 feeReflect_,
          uint8 feeMarketing_,
          uint8 feeAcquisition_
          ) = _getFeeValues(_side);

        FeeValues memory _tValues;
        _tValues.Amount = tAmount;
        _tValues.ReflectFee = tAmount * feeReflect_ / 100;
        _tValues.MarketingFee = tAmount * feeMarketing_ / 100;
        _tValues.AcquisitionFee = tAmount * feeAcquisition_ / 100;
        _tValues.TransferAmount =
          _tValues.Amount
          - _tValues.ReflectFee
          - _tValues.MarketingFee
          - _tValues.AcquisitionFee;

        return (_tValues);
    }

    /// @dev Scales up the actual transaction fees {_tValues} by reflection
    /// rate to allow proper update of _rOwned user balance.
    /// @param _tValues is the struct containing actual transfer amount and
    /// fees to be deducted.
    /// @param currentRate is current reflection rate.
    function _getRValues(
      FeeValues memory _tValues,
      uint256 currentRate
      ) private pure returns (FeeValues memory) {

        FeeValues memory _rValues;
        _rValues.Amount = _tValues.Amount * currentRate;
        _rValues.ReflectFee = _tValues.ReflectFee * currentRate;
        _rValues.MarketingFee = _tValues.MarketingFee * currentRate;
        _rValues.AcquisitionFee = _tValues.AcquisitionFee * currentRate;
        _rValues.TransferAmount =
          _rValues.Amount
          - _rValues.ReflectFee
          - _rValues.MarketingFee
          - _rValues.AcquisitionFee;

        return (_rValues);
    }

    /// @dev Calculates the reflection rate based on rSupply and rSupply. As
    /// reflection fees are deducted from rSupply by {_reflectFee} function,
    /// the reflection rate will decrease, causing users' balances to increase
    /// by the reflection fee in proportion to the user's balance / total supply
    function _getRate() private view returns (uint256) {
        (uint256 rSupply, uint256 tSupply) = _getCurrentSupply();
        return rSupply / tSupply;
    }

    /// @dev Calculates the transaction fee percentages depending on whether
    /// user is buying, selling, or transferring the token.
    /// @param _side is the transaction type: 'BUY', 'SELL', 'NONE'.
    function _getFeeValues(MarketSide _side) private view returns (
      uint8,
      uint8,
      uint8
      ) {
        if(_side == MarketSide.BUY){
            return (_buyFeeReflect, _buyFeeMarketing, _buyFeeAcquisition);
        } else if(_side == MarketSide.SELL){
            return (_sellFeeReflect, _sellFeeMarketing, _sellFeeAcquisition);
        } else {
            return (0, 0, 0);
        }
    }

    /// @dev Calculates the scaled up and actual token supply exclusive of
    /// excluded addresses. This impacts the reflection rate (greater decrease)
    /// to allow included addresses to receive reflections that would have gone
    /// to excluded accounts.
    function _getCurrentSupply() private view returns (uint256, uint256) {
        uint256 rSupply = _rTotal;
        uint256 tSupply = _tTotal;
        for (uint256 i = 0; i < _excluded.length; i++) {
          if (_rOwned[_excluded[i]] > rSupply || _tOwned[_excluded[i]] > tSupply)
          return (_rTotal, _tTotal);

          rSupply = rSupply - _rOwned[_excluded[i]];
          tSupply = tSupply - _tOwned[_excluded[i]];
        }
        if (rSupply < _rTotal / _tTotal) return (_rTotal, _tTotal);
        return (rSupply, tSupply);
    }

    //--------------------------Restricted Functions----------------------------

    /// @notice Sets the exchange pair address for the token to detect 'BUY',
    /// 'SELL', or 'NONE' transactions for fee collection. Can only be updated
    /// by administrator.
    /// @dev Only transactions to, and from this address will trigger fee
    /// collection.
    /// @param exchangePair is the DEX-created contract address of the
    /// exchange pair.
    function setExchange(address exchangePair) external onlyOwner {
        require(!_isExchange[exchangePair], "Address already Exchange");
        _isExchange[exchangePair] = true;
    }

    /// @notice Removes an exchange pair address from fee collection. Can
    /// only be updated by administrator.
    /// @param exchangePair is the DEX-created contract address of the exchange
    /// pair to be removed as an "exchange" for fee collection.
    function removeExchange(address exchangePair) external onlyOwner {
        require(_isExchange[exchangePair], "Address not Exchange");
        _isExchange[exchangePair] = false;
    }

    /// @notice Changes marketing wallet address to receive marketing fee going
    /// forward. Can only be updated by administrator.
    /// @param newAddress is the new address to replace existing
    /// marketing wallet address.
    function changeMarketing(address newAddress) external onlyOwner {
        require(newAddress != address(0), "Address cannot be zero address");
        _marketingWallet = newAddress;
    }

    /// @notice Changes acquisition wallets address to receive acquisition fee
    /// going forward. Can only be updated by administrator.
    /// @param index is the acquisition wallet address to be replaced,
    /// from 0 to 4.
    /// @param newAddress is the new address to replace existing
    /// acquisition wallet address.
    function changeAcquisition(
      uint256 index,
      address newAddress
      ) external onlyOwner {
        require(index < _acquisitionWallets.length, "Invalid index value");
        require(newAddress != address(0), "Address cannot be zero address");
        _acquisitionWallets[index] = newAddress;
    }

    /// @notice Changes the reflection, marketing, and acquisition fee
    /// percentages to be deducted from 'BUY' transaction type. Can only be
    /// updated by administrator.
    /// @param reflectFee is the new reflection fee percentage.
    /// @param marketingFee is the new marketing fee percentage.
    /// @param acquisitionFee is the new acquisition fee percentage.
    function setBuyFees(
      uint8 reflectFee,
      uint8 marketingFee,
      uint8 acquisitionFee
      ) external onlyOwner {
        require(reflectFee + marketingFee + acquisitionFee < 100,
          "Total fee percentage must be less than 100%"
          );

        _buyFeeReflect = reflectFee;
        _buyFeeMarketing = marketingFee;
        _buyFeeAcquisition = acquisitionFee;
    }

    /// @notice Changes the reflection, marketing, and acquisition fee
    /// percentages to be deducted from {SELL} transaction type. Can only be
    /// updated by administrator.
    /// @param reflectFee is the new reflection fee percentage.
    /// @param marketingFee is the new marketing fee percentage.
    /// @param acquisitionFee is the new acquisition fee percentage.
    function setSellFees(
      uint8 reflectFee,
      uint8 marketingFee,
      uint8 acquisitionFee
      ) external onlyOwner {
        require(reflectFee + marketingFee + acquisitionFee < 100,
          "Total fee percentage must be less than 100%"
          );

        _sellFeeReflect = reflectFee;
        _sellFeeMarketing = marketingFee;
        _sellFeeAcquisition = acquisitionFee;
    }

    /// @notice Removes address from receiving future reflection distributions.
    /// Can only be updated by administrator.
    /// @param account is address to be excluded from reflections.
    function excludeAccount(address account) external onlyOwner {
        require(!_isExcluded[account], "Account already excluded");
        require(balanceOf(account) < _tTotal, "Cannot exclude total supply");
         _tOwned[account] = balanceOf(account);
         _excluded.push(account);
        _isExcluded[account] = true;
    }

    /// @notice Includes previously excluded address to receive reflection
    /// distributions in case of erroneously excluded address. NOTE: Included
    /// address will receive all previous reflection distribution it should
    /// have received while address was excluded. Can only be updated by
    /// administrator.
    /// @param account is address to be re-included to reflections.
    function includeAccount(address account) external onlyOwner {
      require(_isExcluded[account], "Account already included");

      for (uint256 i = 0; i < _excluded.length; i++) {
        if (_excluded[i] == account) {
          _excluded[i] = _excluded[_excluded.length - 1];
          _excluded.pop();
          _isExcluded[account] = false;
          break;
        }
      }
    }

    /// @notice Pauses token transfer functionality in case of emergency.
    /// Can only be updated by administrator.
    function lockToken() external onlyOwner {
        _pause();
    }

    /// @notice Unpauses token transfer functionality to allow users to
    /// transfer token. Can only be updated by administrator.
    function unlockToken() external onlyOwner {
        _unpause();
    }
}

// File: Context.sol



// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

// File: ERC20.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./Context.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context {
    mapping(address => uint256) internal _balances;

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

    uint256 internal _totalSupply;

    string internal _name;
    string internal _symbol;

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

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual returns (string memory) {
        return _name;
    }


    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual 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}.
     * @return decimal_ is number of decimals for display purposes.
     */
    function decimals() public view virtual returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual 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 returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual 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 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 returns (bool) {
        uint256 currentAllowance = _allowances[sender][_msgSender()];
        require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");

        _transfer(sender, recipient, amount);
        _approve(sender, _msgSender(), currentAllowance - amount);

        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] + 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) {
        uint256 currentAllowance = _allowances[_msgSender()][spender];
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        _approve(_msgSender(), spender, currentAllowance - subtractedValue);

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `sender` to `recipient`.
     *
     * This 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");
        uint256 senderBalance = _balances[sender];
        require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");

        _balances[sender] = senderBalance - amount;
        _balances[recipient] += amount;

        emit Transfer(sender, recipient, 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);
    }

}

// File: Ownable.sol



// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (access/Ownable.sol)

pragma solidity ^0.8.0;

import "./Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract 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() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual 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 {
        _transferOwnership(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");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// File: Pausable.sol



// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (security/Pausable.sol)

pragma solidity ^0.8.0;

import "./Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     * @return status is current pause status. Returns true if contract is paused, otherwise, returns false.
     */
    function paused() public view virtual returns (bool status) {
        return _paused;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        require(!paused(), "Pausable: paused");
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        require(paused(), "Pausable: not paused");
        _;
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}