ETH Price: $2,272.69 (-6.95%)
Gas: 0.3 Gwei

Transaction Decoder

Block:
16012118 at Nov-20-2022 03:27:59 PM +UTC
Transaction Fee:
0.002614703297748737 ETH $5.94
Gas Used:
183,209 Gas / 14.271696793 Gwei

Account State Difference:

  Address   Before After State Difference Code
0x0d31DF7d...3aBCC3A5A
0x31C0b202...de2F858F3
0.363670075511830242 Eth
Nonce: 20
0.361055372214081505 Eth
Nonce: 21
0.002614703297748737
(Flashbots: Builder)
1.196861152708800267 Eth1.197135966208800267 Eth0.0002748135
0xe550AF09...E66745fc6

Execution Trace

PoolStakingLock.withdraw( _amount=499001010100 )
  • ethTCGCoin20.balanceOf( account=0xe550AF09aFc9292Bb26616C9e74ABA8E66745fc6 ) => ( 119892897645485 )
  • ethTCGCoin20.transfer( recipient=0x31C0b202Eb94018Ffdc6366160626Dede2F858F3, amount=51044647860 ) => ( True )
  • ethTCGCoin20.transfer( recipient=0x31C0b202Eb94018Ffdc6366160626Dede2F858F3, amount=499001010100 ) => ( True )
    File 1 of 2: PoolStakingLock
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.0;
    import "@openzeppelin/contracts/access/Ownable.sol";
    import "@openzeppelin/contracts/utils/math/SafeMath.sol";
    import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
    import "@openzeppelin/contracts/utils/Address.sol";
    import "./imports/IBEP20.sol";
    import "./imports/SafeBEP20.sol";
    contract PoolStakingLock is Ownable, ReentrancyGuard {
        using SafeMath for uint256;
        using SafeBEP20 for IBEP20;
        // The address of retrostaking factory
        address public POOL_STAKING_FACTORY;
        // Whether a limit is set for users
        bool public hasUserLimit;
        // Whether a limit is set for Pool
        bool public hasPoolLimit;
        // Whether a HarvestLock
        bool public hasPoolHL;
        // Whether a WithdrawLock
        bool public hasPoolWL;
        // Whether it is initialized
        bool public isInitialized;
        // Accrued token per share
        uint256 public accTokenPerShare;
        // The block number when mining ends.
        uint256 public bonusEndBlock;
        // The block number when mining starts.
        uint256 public startBlock;
        // The block number of the last pool update
        uint256 public lastRewardBlock;
        // The pool limit (0 if none)
        uint256 public poolLimitPerUser;
        // The pool limit global staking (0 if none)
        uint256 public poolLimitGlobal;
        // The pool minimum limit for amount deposited
        uint256 public poolMinDeposit;
        // Tokens created per block.
        uint256 public rewardPerBlock;
        // Total locked up rewards
        uint256 public totalLockedUpRewards;
        // The precision factor
        uint256 public PRECISION_FACTOR;
        // Keep track of number of tokens staked in case the contract earns reflect fees
        uint256 public totalStaked = 0;
        // The reward token
        IBEP20 public rewardToken;
        // The staked token
        IBEP20 public stakedToken;
        // Info of each user that stakes tokens (stakedToken)
        mapping(address => UserInfo) public userInfo;
        struct UserInfo {
            uint256 amount; // How many staked tokens the user has provided
            uint256 rewardDebt; // Reward debt
            uint256 rewardLockedUp; //Reward locked up
        }
        event AdminTokenRecovery(address tokenRecovered, uint256 amount);
        event Deposit(address indexed user, uint256 amount);
        event EmergencyWithdraw(address indexed user, uint256 amount);
        event NewStartAndEndBlocks(uint256 startBlock, uint256 endBlock);
        event NewRewardPerBlock(uint256 rewardPerBlock);
        event NewPoolLimit(uint256 poolLimitPerUser);
        event RewardsStop(uint256 blockNumber);
        event Withdraw(address indexed user, uint256 amount);
        event Harvest(address indexed user, uint256 amount);
        constructor() {
            POOL_STAKING_FACTORY = msg.sender;
        }
        /*
         * @notice Initialize the contract
         * @param _stakedToken: staked token address
         * @param _rewardToken: reward token address
         * @param _rewardPerBlock: reward per block (in rewardToken)
         * @param _startBlock: start block
         * @param _bonusEndBlock: end block
         * @param _poolLimitPerUser: pool limit per user in stakedToken (if any, else 0)
         * @param _poolLimitGlobal: pool limit global in stakedToken (if any, else 0)
         * @param _poolMinDeposit: pool minimal limit for deposited amount
         * @param _poolHarvestLock: pool Harvest is locked (if true is enable, else false is disable)
         * @param _poolWithdrawLock: pool Withdraw is locked (if true is enable, else false is disable)
         * @param _admin: admin address with ownership
         */
        function initialize(
            IBEP20 _stakedToken,
            IBEP20 _rewardToken,
            uint256 _rewardPerBlock,
            uint256 _startBlock,
            uint256 _bonusEndBlock,
            uint256 _poolLimitPerUser,
            uint256 _poolLimitGlobal,
            uint256 _poolMinDeposit,
            bool _poolHarvestLock,
            bool _poolWithdrawLock,
            address _admin
        ) external {
            require(!isInitialized, "Already initialized");
            require(msg.sender == POOL_STAKING_FACTORY, "Not factory");
            // Make this contract initialized
            isInitialized = true;
            stakedToken = _stakedToken;
            rewardToken = _rewardToken;
            rewardPerBlock = _rewardPerBlock;
            startBlock = _startBlock;
            bonusEndBlock = _bonusEndBlock;
            if (_poolLimitPerUser > 0) {
                hasUserLimit = true;
                poolLimitPerUser = _poolLimitPerUser;
            }
            if (_poolLimitGlobal > 0) {
                hasPoolLimit = true;
                poolLimitGlobal = _poolLimitGlobal;
            }
            if (_poolMinDeposit > 0) {
                poolMinDeposit = _poolMinDeposit;
            }
            if (_poolHarvestLock) {
                hasPoolHL = true;
            }
            if (_poolWithdrawLock) {
                hasPoolWL = true;
            }
            uint256 decimalsRewardToken = uint256(rewardToken.decimals());
            require(decimalsRewardToken < 30, "Must be inferior to 30");
            PRECISION_FACTOR = uint256(10**(uint256(30).sub(decimalsRewardToken)));
            // Set the lastRewardBlock as the startBlock
            lastRewardBlock = startBlock;
            // Transfer ownership to the admin address who becomes owner of the contract
            transferOwnership(_admin);
        }
        /*
         * @notice Deposit staked tokens and collect reward tokens (if any)
         * @param _amount: amount to withdraw (in rewardToken)
         */
        function deposit(uint256 _amount) external nonReentrant {
            UserInfo storage user = userInfo[msg.sender];
            require(
                _getBlockNumber() < bonusEndBlock, 
                "Cannot deposit after the last reward block"
            );
            uint256 finalDepositAmount = 0;
            if (hasUserLimit) {
                require(
                    _amount.add(user.amount) <= poolLimitPerUser,
                    "User amount above limit"
                );
            }
            if (hasPoolLimit) {
                require(
                    _amount.add(totalStaked) <= poolLimitGlobal,
                    "Global amount above limit"
                );
            }
            require(
                user.amount + _amount >= poolMinDeposit,
                "Amount under limit"
            );
            _updatePool();
            if (user.amount > 0) {
                payOrLockupPending(user);
            }
            if (_amount > 0) {
                uint256 preStakeBalance = stakedToken.balanceOf(address(this));
                stakedToken.safeTransferFrom(
                    address(msg.sender),
                    address(this),
                    _amount
                );
                finalDepositAmount = stakedToken.balanceOf(address(this)).sub(
                    preStakeBalance
                );
                user.amount = user.amount.add(finalDepositAmount);
                totalStaked = totalStaked.add(finalDepositAmount);
            }
            _updateRewardDebt(user);
            emit Deposit(msg.sender, _amount);
        }
        /*
         * @notice Withdraw staked tokens and collect reward tokens
         * @param _amount: amount to withdraw (in rewardToken)
         */
        function withdraw(uint256 _amount) external nonReentrant {
            UserInfo storage user = userInfo[msg.sender];
            bool poolStatusWithdraw = poolWIsLock();
            require(user.amount >= _amount, "Amount to withdraw too high");
            _updatePool();
            // Withdraw pending AUTO
            payOrLockupPending(user);
            if (!poolStatusWithdraw) {
                if (_amount > 0) {
                    stakedToken.safeTransfer(address(msg.sender), _amount);
                    user.amount = user.amount.sub(_amount);
                    totalStaked = totalStaked.sub(_amount);
                }
            } else {
                revert("Pool locked");
            }
            _updateRewardDebt(user);
            emit Withdraw(msg.sender, _amount);
        }
        function harvest() external nonReentrant {
            UserInfo storage user = userInfo[msg.sender];
            _updatePool();
            // Withdraw pending AUTO
            require(payOrLockupPending(user), "Harvests locked");
            _updateRewardDebt(user);
        }
        /*
         * @notice Withdraw staked tokens without caring about rewards
         * @dev Needs to be for emergency.
         */
        function emergencyWithdraw() external nonReentrant {
            UserInfo storage user = userInfo[msg.sender];
            uint256 amountToTransfer = user.amount;
            user.amount = 0;
            user.rewardDebt = 0;
            if (amountToTransfer > 0) {
                stakedToken.safeTransfer(address(msg.sender), amountToTransfer);
                totalStaked = totalStaked.sub(amountToTransfer);
            }
            emit EmergencyWithdraw(msg.sender, user.amount);
        }
        function rewardBalance() public view returns (uint256) {
            uint256 balance = rewardToken.balanceOf(address(this));
            if (stakedToken == rewardToken) return balance.sub(totalStaked);
            return balance;
        }
        function totalStakeTokenBalance() public view returns (uint256) {
            if (stakedToken == rewardToken) return totalStaked;
            return stakedToken.balanceOf(address(this));
        }
        function poolHIsLock() public view returns (bool) {
            bool statusPool;
            if (hasPoolHL) {
                statusPool = bonusEndBlock >= _getBlockNumber();
                if (startBlock >= _getBlockNumber()) {
                    statusPool = false;
                }
            }
            return statusPool;
        }
        function poolWIsLock() public view returns (bool) {
            bool statusPool;
            if (hasPoolWL) {
                statusPool = bonusEndBlock >= _getBlockNumber();
                if (startBlock >= _getBlockNumber()) {
                    statusPool = false;
                }
            }
            return statusPool;
        }
        function poolChangeHLock(bool _value) public onlyOwner {
            hasPoolHL = _value;
        }
        function poolChangeWLock(bool _value) public onlyOwner {
            hasPoolWL = _value;
        }
        /*
         * @notice Stop rewards
         * @dev Only callable by owner. Needs to be for emergency.
         */
        function emergencyRewardWithdraw(uint256 _amount) external onlyOwner {
            require(_amount <= rewardBalance(), "not enough rewards");
            rewardToken.safeTransfer(address(msg.sender), _amount);
        }
        /**
         * @notice It allows the admin to recover wrong tokens sent to the contract
         * @param _tokenAddress: the address of the token to withdraw
         * @param _tokenAmount: the number of tokens to withdraw
         * @dev This function is only callable by admin.
         */
        function recoverWrongTokens(address _tokenAddress, uint256 _tokenAmount)
            external
            onlyOwner
        {
            require(
                _tokenAddress != address(stakedToken),
                "Cannot be staked token"
            );
            IBEP20(_tokenAddress).safeTransfer(address(msg.sender), _tokenAmount);
            emit AdminTokenRecovery(_tokenAddress, _tokenAmount);
        }
        /*
         * @notice Stop rewards
         * @dev Only callable by owner
         */
        function stopReward() external onlyOwner {
            bonusEndBlock = _getBlockNumber();
        }
        /*
         * @notice Update pool limit per user
         * @dev Only callable by owner.
         * @param _hasUserLimit: whether the limit remains forced
         * @param _poolLimitPerUser: new pool limit per user
         */
        function updatePoolLimitPerUser(
            bool _hasUserLimit,
            uint256 _poolLimitPerUser
        ) external onlyOwner {
            require(hasUserLimit, "Must be set");
            if (_hasUserLimit) {
                require(
                    _poolLimitPerUser > poolLimitPerUser,
                    "New limit must be higher"
                );
                poolLimitPerUser = _poolLimitPerUser;
            } else {
                hasUserLimit = _hasUserLimit;
                poolLimitPerUser = 0;
            }
            emit NewPoolLimit(poolLimitPerUser);
        }
        /*
         * @notice Update reward per block
         * @dev Only callable by owner.
         * @param _rewardPerBlock: the reward per block
         */
        function updateRewardPerBlock(uint256 _rewardPerBlock) external onlyOwner {
            require(_getBlockNumber() < startBlock, "Pool has started");
            rewardPerBlock = _rewardPerBlock;
            emit NewRewardPerBlock(_rewardPerBlock);
        }
        /**
         * @notice It allows the admin to update start and end blocks
         * @dev This function is only callable by owner.
         * @param _startBlock: the new start block
         * @param _bonusEndBlock: the new end block
         */
        function updateStartAndEndBlocks(
            uint256 _startBlock,
            uint256 _bonusEndBlock
        ) external onlyOwner {
            require(_getBlockNumber() < startBlock, "Pool has started");
            require(
                _startBlock < _bonusEndBlock,
                "New startBlock must be lower than new endBlock"
            );
            require(
                _getBlockNumber() < _startBlock,
                "New startBlock must be higher than current block"
            );
            startBlock = _startBlock;
            bonusEndBlock = _bonusEndBlock;
            // Set the lastRewardBlock as the startBlock
            lastRewardBlock = startBlock;
            emit NewStartAndEndBlocks(_startBlock, _bonusEndBlock);
        }
        /*
         * @notice View function to see pending reward on frontend.
         * @param _user: user address
         * @return Pending reward for a given user
         */
        function pendingReward(address _user) external view returns (uint256) {
            UserInfo storage user = userInfo[_user];
            uint256 stakedTokenSupply = totalStaked;
            if (_getBlockNumber() > lastRewardBlock && stakedTokenSupply != 0) {
                uint256 multiplier = _getMultiplier(lastRewardBlock, _getBlockNumber());
                uint256 reward = multiplier.mul(rewardPerBlock);
                uint256 adjustedTokenPerShare = accTokenPerShare.add(
                    reward.mul(PRECISION_FACTOR).div(stakedTokenSupply)
                );
                uint256 pending = user
                    .amount
                    .mul(adjustedTokenPerShare)
                    .div(PRECISION_FACTOR)
                    .sub(user.rewardDebt);
                return pending.add(user.rewardLockedUp);
            } else {
                uint256 pending = user
                    .amount
                    .mul(accTokenPerShare)
                    .div(PRECISION_FACTOR)
                    .sub(user.rewardDebt);
                return pending.add(user.rewardLockedUp);
            }
        }
        function payOrLockupPending(UserInfo storage user) internal returns(bool) {
            bool poolStatusHarvest = poolHIsLock();
            uint256 pending = user
                .amount
                .mul(accTokenPerShare)
                .div(PRECISION_FACTOR)
                .sub(user.rewardDebt);
            uint256 totalRewards = pending.add(user.rewardLockedUp);
            if (!poolStatusHarvest) {
                if (totalRewards > 0) {
                    // reset lockup
                    totalLockedUpRewards = totalLockedUpRewards.sub(
                        user.rewardLockedUp
                    );
                    user.rewardLockedUp = 0;
                    // send rewards
                    uint256 currentRewardBalance = rewardBalance();
                    if (currentRewardBalance > 0) {
                        if (totalRewards > currentRewardBalance) {
                            rewardToken.safeTransfer(
                                address(msg.sender),
                                currentRewardBalance
                            );
                            emit Harvest(msg.sender, currentRewardBalance);
                        } else {
                            rewardToken.safeTransfer(
                                address(msg.sender),
                                totalRewards
                            );
                            emit Harvest(msg.sender, totalRewards);
                        }
                    }
                }
            } else if (pending > 0) {
                user.rewardLockedUp = user.rewardLockedUp.add(pending);
                totalLockedUpRewards = totalLockedUpRewards.add(pending);
            }
            return !poolStatusHarvest;
        }
        function _updateRewardDebt(UserInfo storage user) internal {
            user.rewardDebt = user.amount.mul(accTokenPerShare).div(
                PRECISION_FACTOR
            );
        }
        /*
         * @notice Update reward variables of the given pool to be up-to-date.
         */
        function _updatePool() internal {
            if (_getBlockNumber() <= lastRewardBlock) {
                return;
            }
            uint256 stakedTokenSupply = totalStaked;
            if (stakedTokenSupply == 0) {
                lastRewardBlock = _getBlockNumber();
                return;
            }
            uint256 multiplier = _getMultiplier(lastRewardBlock, _getBlockNumber());
            uint256 reward = multiplier.mul(rewardPerBlock);
            accTokenPerShare = accTokenPerShare.add(
                reward.mul(PRECISION_FACTOR).div(stakedTokenSupply)
            );
            lastRewardBlock = _getBlockNumber();
        }
        /*
         * @notice Return reward multiplier over the given _from to _to block.
         * @param _from: block to start
         * @param _to: block to finish
         */
        function _getMultiplier(uint256 _from, uint256 _to)
            internal
            view
            returns (uint256)
        {
            if (_to <= bonusEndBlock) {
                return _to.sub(_from);
            } else if (_from >= bonusEndBlock) {
                return 0;
            } else {
                return bonusEndBlock.sub(_from);
            }
        }
        function _getBlockNumber() internal view virtual returns(uint256) {
            return block.number;
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
    pragma solidity ^0.8.0;
    import "../utils/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 Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            _checkOwner();
            _;
        }
        /**
         * @dev Returns the address of the current owner.
         */
        function owner() public view virtual returns (address) {
            return _owner;
        }
        /**
         * @dev Throws if the sender is not the owner.
         */
        function _checkOwner() internal view virtual {
            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);
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)
    pragma solidity ^0.8.0;
    // CAUTION
    // This version of SafeMath should only be used with Solidity 0.8 or later,
    // because it relies on the compiler's built in overflow checks.
    /**
     * @dev Wrappers over Solidity's arithmetic operations.
     *
     * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
     * now has built in overflow checking.
     */
    library SafeMath {
        /**
         * @dev Returns the addition of two unsigned integers, with an overflow flag.
         *
         * _Available since v3.4._
         */
        function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            unchecked {
                uint256 c = a + b;
                if (c < a) return (false, 0);
                return (true, c);
            }
        }
        /**
         * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
         *
         * _Available since v3.4._
         */
        function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            unchecked {
                if (b > a) return (false, 0);
                return (true, a - b);
            }
        }
        /**
         * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
         *
         * _Available since v3.4._
         */
        function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            unchecked {
                // 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 (true, 0);
                uint256 c = a * b;
                if (c / a != b) return (false, 0);
                return (true, c);
            }
        }
        /**
         * @dev Returns the division of two unsigned integers, with a division by zero flag.
         *
         * _Available since v3.4._
         */
        function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            unchecked {
                if (b == 0) return (false, 0);
                return (true, a / b);
            }
        }
        /**
         * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
         *
         * _Available since v3.4._
         */
        function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            unchecked {
                if (b == 0) return (false, 0);
                return (true, a % b);
            }
        }
        /**
         * @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) {
            return a + b;
        }
        /**
         * @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 a - b;
        }
        /**
         * @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) {
            return a * b;
        }
        /**
         * @dev Returns the integer division of two unsigned integers, reverting on
         * division by zero. The result is rounded towards zero.
         *
         * Counterpart to Solidity's `/` operator.
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function div(uint256 a, uint256 b) internal pure returns (uint256) {
            return a / b;
        }
        /**
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
         * reverting 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 a % b;
        }
        /**
         * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
         * overflow (when the result is negative).
         *
         * CAUTION: This function is deprecated because it requires allocating memory for the error
         * message unnecessarily. For custom revert reasons use {trySub}.
         *
         * Counterpart to Solidity's `-` operator.
         *
         * Requirements:
         *
         * - Subtraction cannot overflow.
         */
        function sub(
            uint256 a,
            uint256 b,
            string memory errorMessage
        ) internal pure returns (uint256) {
            unchecked {
                require(b <= a, errorMessage);
                return a - b;
            }
        }
        /**
         * @dev Returns the integer division of two unsigned integers, reverting 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) {
            unchecked {
                require(b > 0, errorMessage);
                return a / b;
            }
        }
        /**
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
         * reverting with custom message when dividing by zero.
         *
         * CAUTION: This function is deprecated because it requires allocating memory for the error
         * message unnecessarily. For custom revert reasons use {tryMod}.
         *
         * 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) {
            unchecked {
                require(b > 0, errorMessage);
                return a % b;
            }
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)
    pragma solidity ^0.8.0;
    /**
     * @dev Contract module that helps prevent reentrant calls to a function.
     *
     * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
     * available, which can be applied to functions to make sure there are no nested
     * (reentrant) calls to them.
     *
     * Note that because there is a single `nonReentrant` guard, functions marked as
     * `nonReentrant` may not call one another. This can be worked around by making
     * those functions `private`, and then adding `external` `nonReentrant` entry
     * points to them.
     *
     * TIP: If you would like to learn more about reentrancy and alternative ways
     * to protect against it, check out our blog post
     * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
     */
    abstract contract ReentrancyGuard {
        // Booleans are more expensive than uint256 or any type that takes up a full
        // word because each write operation emits an extra SLOAD to first read the
        // slot's contents, replace the bits taken up by the boolean, and then write
        // back. This is the compiler's defense against contract upgrades and
        // pointer aliasing, and it cannot be disabled.
        // The values being non-zero value makes deployment a bit more expensive,
        // but in exchange the refund on every call to nonReentrant will be lower in
        // amount. Since refunds are capped to a percentage of the total
        // transaction's gas, it is best to keep them low in cases like this one, to
        // increase the likelihood of the full refund coming into effect.
        uint256 private constant _NOT_ENTERED = 1;
        uint256 private constant _ENTERED = 2;
        uint256 private _status;
        constructor() {
            _status = _NOT_ENTERED;
        }
        /**
         * @dev Prevents a contract from calling itself, directly or indirectly.
         * Calling a `nonReentrant` function from another `nonReentrant`
         * function is not supported. It is possible to prevent this from happening
         * by making the `nonReentrant` function external, and making it call a
         * `private` function that does the actual work.
         */
        modifier nonReentrant() {
            // On the first call to nonReentrant, _notEntered will be true
            require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
            // Any calls to nonReentrant after this point will fail
            _status = _ENTERED;
            _;
            // By storing the original value once again, a refund is triggered (see
            // https://eips.ethereum.org/EIPS/eip-2200)
            _status = _NOT_ENTERED;
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
    pragma solidity ^0.8.1;
    /**
     * @dev Collection of functions related to the address type
     */
    library Address {
        /**
         * @dev Returns true if `account` is a contract.
         *
         * [IMPORTANT]
         * ====
         * It is unsafe to assume that an address for which this function returns
         * false is an externally-owned account (EOA) and not a contract.
         *
         * Among others, `isContract` will return false for the following
         * types of addresses:
         *
         *  - an externally-owned account
         *  - a contract in construction
         *  - an address where a contract will be created
         *  - an address where a contract lived, but was destroyed
         * ====
         *
         * [IMPORTANT]
         * ====
         * You shouldn't rely on `isContract` to protect against flash loan attacks!
         *
         * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
         * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
         * constructor.
         * ====
         */
        function isContract(address account) internal view returns (bool) {
            // This method relies on extcodesize/address.code.length, which returns 0
            // for contracts in construction, since the code is only stored at the end
            // of the constructor execution.
            return account.code.length > 0;
        }
        /**
         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
         * `recipient`, forwarding all available gas and reverting on errors.
         *
         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
         * of certain opcodes, possibly making contracts go over the 2300 gas limit
         * imposed by `transfer`, making them unable to receive funds via
         * `transfer`. {sendValue} removes this limitation.
         *
         * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
         *
         * IMPORTANT: because control is transferred to `recipient`, care must be
         * taken to not create reentrancy vulnerabilities. Consider using
         * {ReentrancyGuard} or the
         * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
         */
        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");
        }
        /**
         * @dev Performs a Solidity function call using a low level `call`. A
         * plain `call` is an unsafe replacement for a function call: use this
         * function instead.
         *
         * If `target` reverts with a revert reason, it is bubbled up by this
         * function (like regular Solidity function calls).
         *
         * Returns the raw returned data. To convert to the expected return value,
         * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
         *
         * Requirements:
         *
         * - `target` must be a contract.
         * - calling `target` with `data` must not revert.
         *
         * _Available since v3.1._
         */
        function functionCall(address target, bytes memory data) internal returns (bytes memory) {
            return functionCall(target, data, "Address: low-level call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
         * `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal returns (bytes memory) {
            return functionCallWithValue(target, data, 0, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but also transferring `value` wei to `target`.
         *
         * Requirements:
         *
         * - the calling contract must have an ETH balance of at least `value`.
         * - the called Solidity function must be `payable`.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(
            address target,
            bytes memory data,
            uint256 value
        ) internal returns (bytes memory) {
            return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
        }
        /**
         * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
         * with `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(
            address target,
            bytes memory data,
            uint256 value,
            string memory errorMessage
        ) internal returns (bytes memory) {
            require(address(this).balance >= value, "Address: insufficient balance for call");
            require(isContract(target), "Address: call to non-contract");
            (bool success, bytes memory returndata) = target.call{value: value}(data);
            return verifyCallResult(success, returndata, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
            return functionStaticCall(target, data, "Address: low-level static call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal view returns (bytes memory) {
            require(isContract(target), "Address: static call to non-contract");
            (bool success, bytes memory returndata) = target.staticcall(data);
            return verifyCallResult(success, returndata, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a delegate call.
         *
         * _Available since v3.4._
         */
        function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
            return functionDelegateCall(target, data, "Address: low-level delegate call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
         * but performing a delegate call.
         *
         * _Available since v3.4._
         */
        function functionDelegateCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal returns (bytes memory) {
            require(isContract(target), "Address: delegate call to non-contract");
            (bool success, bytes memory returndata) = target.delegatecall(data);
            return verifyCallResult(success, returndata, errorMessage);
        }
        /**
         * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
         * revert reason using the provided one.
         *
         * _Available since v4.3._
         */
        function verifyCallResult(
            bool success,
            bytes memory returndata,
            string memory errorMessage
        ) internal pure returns (bytes memory) {
            if (success) {
                return returndata;
            } else {
                // Look for revert reason and bubble it up if present
                if (returndata.length > 0) {
                    // The easiest way to bubble the revert reason is using memory via assembly
                    /// @solidity memory-safe-assembly
                    assembly {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert(errorMessage);
                }
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.0;
    interface IBEP20 {
        /**
         * @dev Returns the amount of tokens in existence.
         */
        function totalSupply() external view returns (uint256);
        /**
         * @dev Returns the token decimals.
         */
        function decimals() external view returns (uint8);
        /**
         * @dev Returns the token symbol.
         */
        function symbol() external view returns (string memory);
        /**
         * @dev Returns the token name.
         */
        function name() external view returns (string memory);
        /**
         * @dev Returns the bep token owner.
         */
        function getOwner() external view returns (address);
        /**
         * @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
        );
    }pragma solidity >=0.8.0;
    import "@openzeppelin/contracts/utils/math/SafeMath.sol";
    import "@openzeppelin/contracts/utils/Address.sol";
    import "./IBEP20.sol";
    /**
     * @title SafeBEP20
     * @dev Wrappers around BEP20 operations that throw on failure (when the token
     * contract returns false). Tokens that return no value (and instead revert or
     * throw on failure) are also supported, non-reverting calls are assumed to be
     * successful.
     * To use this library you can add a `using SafeBEP20 for IBEP20;` statement to your contract,
     * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
     */
    library SafeBEP20 {
        using SafeMath for uint256;
        using Address for address;
        function safeTransfer(
            IBEP20 token,
            address to,
            uint256 value
        ) internal {
            _callOptionalReturn(
                token,
                abi.encodeWithSelector(token.transfer.selector, to, value)
            );
        }
        function safeTransferFrom(
            IBEP20 token,
            address from,
            address to,
            uint256 value
        ) internal {
            _callOptionalReturn(
                token,
                abi.encodeWithSelector(token.transferFrom.selector, from, to, value)
            );
        }
        /**
         * @dev Deprecated. This function has issues similar to the ones found in
         * {IBEP20-approve}, and its usage is discouraged.
         *
         * Whenever possible, use {safeIncreaseAllowance} and
         * {safeDecreaseAllowance} instead.
         */
        function safeApprove(
            IBEP20 token,
            address spender,
            uint256 value
        ) internal {
            // safeApprove should only be called when setting an initial allowance,
            // or when resetting it to zero. To increase and decrease it, use
            // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
            // solhint-disable-next-line max-line-length
            require(
                (value == 0) || (token.allowance(address(this), spender) == 0),
                "SafeBEP20: approve from non-zero to non-zero allowance"
            );
            _callOptionalReturn(
                token,
                abi.encodeWithSelector(token.approve.selector, spender, value)
            );
        }
        function safeIncreaseAllowance(
            IBEP20 token,
            address spender,
            uint256 value
        ) internal {
            uint256 newAllowance = token.allowance(address(this), spender).add(
                value
            );
            _callOptionalReturn(
                token,
                abi.encodeWithSelector(
                    token.approve.selector,
                    spender,
                    newAllowance
                )
            );
        }
        function safeDecreaseAllowance(
            IBEP20 token,
            address spender,
            uint256 value
        ) internal {
            uint256 newAllowance = token.allowance(address(this), spender).sub(
                value,
                "SafeBEP20: decreased allowance below zero"
            );
            _callOptionalReturn(
                token,
                abi.encodeWithSelector(
                    token.approve.selector,
                    spender,
                    newAllowance
                )
            );
        }
        /**
         * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
         * on the return value: the return value is optional (but if data is returned, it must not be false).
         * @param token The token targeted by the call.
         * @param data The call data (encoded using abi.encode or one of its variants).
         */
        function _callOptionalReturn(IBEP20 token, bytes memory data) private {
            // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
            // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
            // the target address contains contract code and also asserts for success in the low-level call.
            bytes memory returndata = address(token).functionCall(
                data,
                "SafeBEP20: low-level call failed"
            );
            if (returndata.length > 0) {
                // Return data is optional
                // solhint-disable-next-line max-line-length
                require(
                    abi.decode(returndata, (bool)),
                    "SafeBEP20: BEP20 operation did not succeed"
                );
            }
        }
    }// SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.1 (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 2 of 2: ethTCGCoin20
    /**
     * author: BlockCzech R&D Lab <[email protected]>
     * 
     * 
     *░░████████╗░█████╗░░██████╗░░░░█████╗░░█████╗░██╗███╗░░██╗░░██████╗░░░░░█████╗░░░
     *░░╚══██╔══╝██╔══██╗██╔════╝░░░██╔══██╗██╔══██╗██║████╗░██║░░╚════██╗░░░██╔══██╗░░
     *░░░░░██║░░░██║░░╚═╝██║░░██╗░░░██║░░╚═╝██║░░██║██║██╔██╗██║░░░░███╔═╝░░░██║░░██║░░
     *░░░░░██║░░░██║░░██╗██║░░╚██╗░░██║░░██╗██║░░██║██║██║╚████║░░██╔══╝░░░░░██║░░██║░░
     *░░░░░██║░░░╚█████╔╝╚██████╔╝░░╚█████╔╝╚█████╔╝██║██║░╚███║░░███████╗██╗╚█████╔╝░░
     *░░░░░╚═╝░░░░╚════╝░░╚═════╝░░░░╚════╝░░╚════╝░╚═╝╚═╝░░╚══╝░░╚══════╝╚═╝░╚════╝░░░
     *
     * 
     * The TCGCoin20 [ETH] is based on the Automatic Liquidity Pool & Custom Fees Architecture.
     *
     * 
     * SPDX-License-Identifier: MIT
     * 
     */
    
    pragma solidity 0.8.11;
    
    abstract contract Context {
        function _msgSender() internal view virtual returns (address) {
            return msg.sender;
        }
    
        function _msgData() internal view virtual returns (bytes calldata) {
            return msg.data;
        }
    }
    
    interface IUniswapV2Factory {
        event PairCreated(address indexed token0, address indexed token1, address pair, uint);
    
        function feeTo() external view returns (address);
        function feeToSetter() external view returns (address);
    
        function getPair(address tokenA, address tokenB) external view returns (address pair);
        function allPairs(uint) external view returns (address pair);
        function allPairsLength() external view returns (uint);
    
        function createPair(address tokenA, address tokenB) external returns (address pair);
    
        function setFeeTo(address) external;
        function setFeeToSetter(address) external;
    
        function INIT_CODE_PAIR_HASH() external view returns (bytes32);
    }
    
    interface IUniswapV2Router01 {
        function factory() external pure returns (address);
        function WETH() external pure returns (address);
    
        function addLiquidity(
            address tokenA,
            address tokenB,
            uint amountADesired,
            uint amountBDesired,
            uint amountAMin,
            uint amountBMin,
            address to,
            uint deadline
        ) external returns (uint amountA, uint amountB, uint liquidity);
    
        function addLiquidityETH(
            address token,
            uint amountTokenDesired,
            uint amountTokenMin,
            uint amountETHMin,
            address to,
            uint deadline
        ) external payable returns (uint amountToken, uint amountETH, uint liquidity);
    
        function removeLiquidity(
            address tokenA,
            address tokenB,
            uint liquidity,
            uint amountAMin,
            uint amountBMin,
            address to,
            uint deadline
        ) external returns (uint amountA, uint amountB);
    
        function removeLiquidityETH(
            address token,
            uint liquidity,
            uint amountTokenMin,
            uint amountETHMin,
            address to,
            uint deadline
        ) external returns (uint amountToken, uint amountETH);
    
        function removeLiquidityWithPermit(
            address tokenA,
            address tokenB,
            uint liquidity,
            uint amountAMin,
            uint amountBMin,
            address to,
            uint deadline,
            bool approveMax, uint8 v, bytes32 r, bytes32 s
        ) external returns (uint amountA, uint amountB);
    
        function removeLiquidityETHWithPermit(
            address token,
            uint liquidity,
            uint amountTokenMin,
            uint amountETHMin,
            address to,
            uint deadline,
            bool approveMax, uint8 v, bytes32 r, bytes32 s
        ) external returns (uint amountToken, uint amountETH);
    
        function swapExactTokensForTokens(
            uint amountIn,
            uint amountOutMin,
            address[] calldata path,
            address to,
            uint deadline
        ) external returns (uint[] memory amounts);
    
        function swapTokensForExactTokens(
            uint amountOut,
            uint amountInMax,
            address[] calldata path,
            address to,
            uint deadline
        ) external returns (uint[] memory amounts);
    
        function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
            external
            payable
            returns (uint[] memory amounts);
    
        function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
            external
            returns (uint[] memory amounts);
    
        function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
            external
            returns (uint[] memory amounts);
    
        function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
            external
            payable
            returns (uint[] memory amounts);
    
        function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
        function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
        function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
        function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
        function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
    }
    
    interface IUniswapV2Router02 is IUniswapV2Router01 {
        function removeLiquidityETHSupportingFeeOnTransferTokens(
            address token,
            uint liquidity,
            uint amountTokenMin,
            uint amountETHMin,
            address to,
            uint deadline
        ) external returns (uint amountETH);
        function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
            address token,
            uint liquidity,
            uint amountTokenMin,
            uint amountETHMin,
            address to,
            uint deadline,
            bool approveMax, uint8 v, bytes32 r, bytes32 s
        ) external returns (uint amountETH);
        function swapExactTokensForTokensSupportingFeeOnTransferTokens(
            uint amountIn,
            uint amountOutMin,
            address[] calldata path,
            address to,
            uint deadline
        ) external;
        function swapExactETHForTokensSupportingFeeOnTransferTokens(
            uint amountOutMin,
            address[] calldata path,
            address to,
            uint deadline
        ) external payable;
        function swapExactTokensForETHSupportingFeeOnTransferTokens(
            uint amountIn,
            uint amountOutMin,
            address[] calldata path,
            address to,
            uint deadline
        ) external;
    }
    
    interface IUniswapV2Pair {
        event Approval(address indexed owner, address indexed spender, uint value);
        event Transfer(address indexed from, address indexed to, uint value);
    
        function name() external pure returns (string memory);
        function symbol() external pure returns (string memory);
        function decimals() external pure returns (uint8);
        function totalSupply() external view returns (uint);
        function balanceOf(address owner) external view returns (uint);
        function allowance(address owner, address spender) external view returns (uint);
        function approve(address spender, uint value) external returns (bool);
        function transfer(address to, uint value) external returns (bool);
        function transferFrom(address from, address to, uint value) external returns (bool);
    
        function DOMAIN_SEPARATOR() external view returns (bytes32);
        function PERMIT_TYPEHASH() external pure returns (bytes32);
        function nonces(address owner) external view returns (uint);
        function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
    
        event Mint(address indexed sender, uint amount0, uint amount1);
        event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
        event Swap(
            address indexed sender,
            uint amount0In,
            uint amount1In,
            uint amount0Out,
            uint amount1Out,
            address indexed to
        );
        event Sync(uint112 reserve0, uint112 reserve1);
    
        function MINIMUM_LIQUIDITY() external pure returns (uint);
        function factory() external view returns (address);
        function token0() external view returns (address);
        function token1() external view returns (address);
        function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
        function price0CumulativeLast() external view returns (uint);
        function price1CumulativeLast() external view returns (uint);
        function kLast() external view returns (uint);
        function mint(address to) external returns (uint liquidity);
        function burn(address to) external returns (uint amount0, uint amount1);
        function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
        function skim(address to) external;
        function sync() external;
        function initialize(address, address) external;
    }
    
    library SafeMath {
    
        function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            unchecked {
                uint256 c = a + b;
                if (c < a) return (false, 0);
                return (true, c);
            }
        }
    
        function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            unchecked {
                if (b > a) return (false, 0);
                return (true, a - b);
            }
        }
    
        function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            unchecked {
                // 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 (true, 0);
                uint256 c = a * b;
                if (c / a != b) return (false, 0);
                return (true, c);
            }
        }
    
        function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            unchecked {
                if (b == 0) return (false, 0);
                return (true, a / b);
            }
        }
    
        function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            unchecked {
                if (b == 0) return (false, 0);
                return (true, a % b);
            }
        }
    
        function add(uint256 a, uint256 b) internal pure returns (uint256) {
            return a + b;
        }
    
        function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            return a - b;
        }
    
        function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            return a * b;
        }
    
        function div(uint256 a, uint256 b) internal pure returns (uint256) {
            return a / b;
        }
    
        function mod(uint256 a, uint256 b) internal pure returns (uint256) {
            return a % b;
        }
    
        function sub(
            uint256 a,
            uint256 b,
            string memory errorMessage
        ) internal pure returns (uint256) {
            unchecked {
                require(b <= a, errorMessage);
                return a - b;
            }
        }
    
        function div(
            uint256 a,
            uint256 b,
            string memory errorMessage
        ) internal pure returns (uint256) {
            unchecked {
                require(b > 0, errorMessage);
                return a / b;
            }
        }
    
        function mod(
            uint256 a,
            uint256 b,
            string memory errorMessage
        ) internal pure returns (uint256) {
            unchecked {
                require(b > 0, errorMessage);
                return a % b;
            }
        }
    }
    
    contract Ownable is Context {
        address private _owner;
        address private _previousOwner;
        uint256 private _lockTime;
    
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    
        constructor () {
            address msgSender = _msgSender();
            _owner = msgSender;
            emit OwnershipTransferred(address(0), msgSender);
        }
    
        function owner() public view returns (address) {
            return _owner;
        }
    
        modifier onlyOwner() {
            require(_owner == _msgSender(), "Ownable: caller is not the owner");
            _;
        }
    
        function renounceOwnership() public virtual onlyOwner {
            emit OwnershipTransferred(_owner, address(0));
            _owner = address(0);
        }
    
        function transferOwnership(address newOwner) public virtual onlyOwner {
            require(newOwner != address(0), "Ownable: new owner is the zero address");
            emit OwnershipTransferred(_owner, newOwner);
            _owner = newOwner;
        }
    
        function getUnlockTime() public view returns (uint256) {
            return _lockTime;
        }
    
        function lock(uint256 time) public virtual onlyOwner {
            _previousOwner = _owner;
            _owner = address(0);
            _lockTime = block.timestamp + time;
            emit OwnershipTransferred(_owner, address(0));
        }
    
        function unlock() public virtual {
            require(_previousOwner == msg.sender, "You don't have permission to unlock");
            require(block.timestamp > _lockTime , "Contract is locked until 7 days");
            emit OwnershipTransferred(_owner, _previousOwner);
            _owner = _previousOwner;
        }
    }
    
    library Address {
    
        function isContract(address account) internal view returns (bool) {
            bytes32 codehash;
            bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
            // solhint-disable-next-line no-inline-assembly
            assembly { codehash := extcodehash(account) }
            return (codehash != accountHash && codehash != 0x0);
        }
    
        function sendValue(address payable recipient, uint256 amount) internal {
            require(address(this).balance >= amount, "Address: insufficient balance");
    
            // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
            (bool success, ) = recipient.call{ value: amount }("");
            require(success, "Address: unable to send value, recipient may have reverted");
        }
    
            function functionCall(address target, bytes memory data) internal returns (bytes memory) {
          return functionCall(target, data, "Address: low-level call failed");
        }
    
        function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
            return _functionCallWithValue(target, data, 0, errorMessage);
        }
    
        function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
            return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
        }
    
        function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
            require(address(this).balance >= value, "Address: insufficient balance for call");
            return _functionCallWithValue(target, data, value, errorMessage);
        }
    
        function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
            require(isContract(target), "Address: call to non-contract");
    
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
            if (success) {
                return returndata;
            } else {
                // Look for revert reason and bubble it up if present
                if (returndata.length > 0) {
                    // The easiest way to bubble the revert reason is using memory via assembly
    
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert(errorMessage);
                }
            }
        }
    }
    
    interface IERC20 {
        function totalSupply() external view returns (uint256);
        function balanceOf(address account) external view returns (uint256);
        function transfer(address recipient, uint256 amount) external returns (bool);
        function allowance(address owner, address spender) external view returns (uint256);
        function approve(address spender, uint256 amount) external returns (bool);
        function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
        event Transfer(address indexed from, address indexed to, uint256 value);
        event Approval(address indexed owner, address indexed spender, uint256 value);
    }
    
    
    contract ethTCGCoin20 is Context, IERC20, Ownable {
        using Address for address;
        using SafeMath for uint256;
    
        mapping (address => uint256) private _reflectOwned;
        mapping (address => uint256) private _takeOwned;
        mapping (address => mapping (address => uint256)) private _allowances;
    
        mapping (address => bool) private _isExcludedFromFee;
        mapping (address => bool) private _isExcluded;
        mapping (address => bool) private _isBot;
        address[] private _excluded;
    
        mapping (address => bool) private _isDEXBuyFee;
        mapping (address => bool) private _isDEXSellFee;
    
        uint256 private constant MAX = ~uint256(0);
        uint256 private _takeTotal = 280 * 10**6 * 10**9;
        uint256 private _reflectTotal = (MAX - (MAX % _takeTotal));
        uint256 private _takeFeeTotal;
    
        string private constant _name = "TCG 2.0 ETH";
        string private constant _symbol = "ethTCG2";
        uint8 private constant _decimals = 9;
    
        bool public _taxFeeFlag = false;
    
        uint256 public _taxFee = 0;
        uint256 private _previousTaxFee = _taxFee;
    
        uint256 public _liquidityFee = 10;
        uint256 private _previousLiquidityFee = _liquidityFee;
    
        uint256 public _liquiditySellFee = 10;
        uint256 private _previousLiquiditySellFee = _liquiditySellFee;
    
    
        IUniswapV2Router02 public uniswapRouter;
        address public uniswapPair;
    
        bool public isIntoLiquifySwap;
        bool public swapAndLiquifyEnabled = true;
    
        uint256 private _maxLoopCount = 100;
    
    
        uint256 public _maximumValueOfTransaction = 280 * 10**6 * 10**9 ;
        uint256 public numTokensSellToAddToLiquidity = 10 * 10**9 ;
    
        event SwapAndLiquifyEvent(
            uint256 coinsForSwapping,
            uint256 bnbIsReceived,
            uint256 coinsThatWasAddedIntoLiquidity
        );
    
        event LiquifySwapUpdatedEnabled(bool enabled);
        event SetTaxFeePercent(uint value);
        event SetTaxFeeFlag(bool flag);
        event SetMaxLoopCount(uint value);
        event SetMaxTxPercent(uint value);
        event SetLiquidityFeePercent(uint value);
        event SetSellFeeLiquidity(uint value);
        event ExcludedFromFee(address _address);
        event IncludeInFee(address _address);
        event ETHReceived(address _address);
        event Delivery(address _address,  uint256 amount);
        event AddLiquidity(uint256 coin_amount, uint256 bnb_amount);
        event SwapAndLiquifyEnabled(bool flag);
        event RouterSet(address indexed router);
    
    
        modifier lockSwaping {
            isIntoLiquifySwap = true;
            _;
            isIntoLiquifySwap = false;
        }
    
        constructor () {
            _reflectOwned[_msgSender()] = _reflectTotal;
    	    _setRouterAddress(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D,0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f);	
            
            _isExcludedFromFee[owner()] = true;
            _isExcludedFromFee[address(this)] = true;
            emit Transfer(address(0), _msgSender(), _takeTotal);
        }
        
        function _setRouterAddressByOwner(address router, address factory) external onlyOwner() {
            _setRouterAddress(router, factory);
        }
    
        function _setRouterAddress(address router, address factory) private {
    
            IUniswapV2Router02 _uniswapRouter = IUniswapV2Router02(router);
    
            uniswapPair = IUniswapV2Factory(_uniswapRouter.factory())
                .createPair(address(this), _uniswapRouter.WETH());
    
            uniswapRouter = _uniswapRouter;
            
            address payable _pancakeFactory = payable(factory);
            _isExcludedFromFee[_pancakeFactory] = true;
            
            emit RouterSet(router);
        }
        
        function _isV2Pair(address account) internal view returns(bool){
            return (account == uniswapPair);
        }
    
    
    
        // \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ BEP20 functions \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
    
        function name() external pure returns (string memory) {
            return _name;
        }
    
        function symbol() external pure returns (string memory) {
            return _symbol;
        }
    
        function decimals() public pure returns (uint8) {
            return _decimals;
        }
    
        function totalSupply() external view override returns (uint256) {
            return _takeTotal;
        }
    
        function balanceOf(address account) public view override returns (uint256) {
            if (_isExcluded[account]) return _takeOwned[account];
            return tokenFromReflection(_reflectOwned[account]);
        }
    
        function transfer(address recipient, uint256 amount) external override returns (bool) {
            _transfer(_msgSender(), recipient, amount);
            return true;
        }
    
        function allowance(address owner, address spender) external view override returns (uint256) {
            return _allowances[owner][spender];
        }
    
        function approve(address spender, uint256 amount) external override returns (bool) {
            _approve(_msgSender(), spender, amount);
    
            return true;
        }
    
        function transferFrom(address sender, address recipient, uint256 amount) external override returns (bool) {
            _transfer(sender, recipient, amount);
            _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "BEP20: transfer amount exceeds allowance"));
    
            return true;
        }
    
        function increaseAllowance(address spender, uint256 addedValue) external virtual returns (bool) {
            _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
    
            return true;
        }
    
        function decreaseAllowance(address spender, uint256 subtractedValue) external virtual returns (bool) {
            _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "BEP20: decreased allowance below zero"));
    
            return true;
        }
    
    
        function _getCurrentSupply() private view returns(uint256, uint256) {
            require(_excluded.length <= _maxLoopCount, "The number of loop iterations in _getCurrentSupply is greater than the allowed value.");
    
            uint256 rSupply = _reflectTotal;
            uint256 tSupply = _takeTotal;
            for (uint256 i = 0; i < _excluded.length; i++) {
                if (_reflectOwned[_excluded[i]] > rSupply || _takeOwned[_excluded[i]] > tSupply) return (_reflectTotal, _takeTotal);
                rSupply = rSupply.sub(_reflectOwned[_excluded[i]]);
                tSupply = tSupply.sub(_takeOwned[_excluded[i]]);
            }
            if (rSupply < _reflectTotal.div(_takeTotal)) return (_reflectTotal, _takeTotal);
    
            return (rSupply, tSupply);
        }
    
        function _approve(address owner, address spender, uint256 amount) private {
            require(owner != address(0), "BEP20: approve from the zero address");
            require(spender != address(0), "BEP20: approve to the zero address");
    
            _allowances[owner][spender] = amount;
            emit Approval(owner, spender, amount);
        }
    
        // \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Setter functions \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
    
        function setTaxFeePercent(uint256 taxFee) external onlyOwner() {
            emit SetTaxFeePercent(taxFee);
            _taxFee = taxFee;
        }
    
        function setTaxFeeFlag(bool flag) external onlyOwner() {
            emit SetTaxFeeFlag(flag);
            _taxFeeFlag = flag;
        }
    
        function setLiquidityFeePercent(uint256 liquidityFee) external onlyOwner() {
            emit SetLiquidityFeePercent(liquidityFee);
            _liquidityFee = liquidityFee;
        }
    
        function setMaxLoopCount(uint256 maxLoopCount) external onlyOwner() {
            emit SetMaxLoopCount(maxLoopCount);
            _maxLoopCount = maxLoopCount;
        }
    
        function setMaxTxPercent(uint256 maxTxPercent) external onlyOwner() {
            emit SetMaxTxPercent(maxTxPercent);
            _maximumValueOfTransaction = _takeTotal.mul(maxTxPercent).div(
                10**2
            );
        }
    
        function setNumTokensSellToAddToLiquidity(uint256 amount) external onlyOwner() {
            numTokensSellToAddToLiquidity = amount;
        }
    
        function setLiquiditySellFeePercent(uint256 liquiditySellFee) external onlyOwner() {
            emit SetTaxFeePercent(liquiditySellFee);
            _liquiditySellFee = liquiditySellFee;
        }
    
        // \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Fees calculate functions \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
    
        function totalFees() external view returns (uint256) {
            return _takeFeeTotal;
        }
    
        function calculateTaxFee(uint256 _amount) private view returns (uint256) {
            return _amount.mul(_taxFee).div(
                10**2
            );
        }
    
        function calculateLiquidityFee(uint256 _amount) private view returns (uint256) {
            return _amount.mul(_liquidityFee).div(
                10**2
            );
        }
    
        function _getValues(uint256 tAmount) private view returns (uint256, uint256, uint256, uint256, uint256, uint256) {
            (uint256 takeAmountToTransfer, uint256 tFee, uint256 tLiquidity) = _getTValues(tAmount);
            (uint256 reflectAmount, uint256 reflectAmountToTransfer, uint256 rFee) = _getRValues(tAmount, tFee, tLiquidity, _getRate());
    
            return (reflectAmount, reflectAmountToTransfer, rFee, takeAmountToTransfer, tFee, tLiquidity);
        }
    
        function _getTValues(uint256 tAmount) private view returns (uint256, uint256, uint256) {
            uint256 tFee = calculateTaxFee(tAmount);
            uint256 tLiquidity = calculateLiquidityFee(tAmount);
            uint256 takeAmountToTransfer = tAmount.sub(tFee).sub(tLiquidity);
    
            return (takeAmountToTransfer, tFee, tLiquidity);
        }
    
        function _getRValues(uint256 tAmount, uint256 tFee, uint256 tLiquidity, uint256 currentRate) private pure returns (uint256, uint256, uint256) {
            uint256 reflectAmount = tAmount.mul(currentRate);
            uint256 rFee = tFee.mul(currentRate);
            uint256 rLiquidity = tLiquidity.mul(currentRate);
            uint256 reflectAmountToTransfer = reflectAmount.sub(rFee).sub(rLiquidity);
    
            return (reflectAmount, reflectAmountToTransfer, rFee);
        }
    
        function _getRate() private view returns(uint256) {
            (uint256 rSupply, uint256 tSupply) = _getCurrentSupply();
    
            return rSupply.div(tSupply);
        }
    
        // \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Withdraw function \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
    
        /// This will allow to rescue ETH sent by mistake directly to the contract
        function rescueTokensFromContract(uint256 amount) external onlyOwner {
            if(amount == 0 ){ // ETH
                payable(owner()).transfer(address(this).balance);
            }else{ // TCG2
                _tokenTransfer(address(this), owner(), amount, false);
            }
        }
    
        // \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Fees managing functions \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
    
        function removeAllFee() private {
            if(_taxFee == 0 && _liquidityFee == 0) return;
    
            _previousTaxFee = _taxFee;
            _previousLiquidityFee = _liquidityFee;
    
            _taxFee = 0;
            _liquidityFee = 0;
        }
    
        function restoreAllFee() private {
            _taxFee = _previousTaxFee;
            _liquidityFee = _previousLiquidityFee;
        }
    
        // \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Fees group mebership functions \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
    
        function setupBot(address account, bool value) external onlyOwner {
            _isBot[account] = value;
        }
    
        function excludeFromFee(address account) external onlyOwner {
            emit ExcludedFromFee(account);
            _isExcludedFromFee[account] = true;
        }
    
        function includeInFee(address account) external onlyOwner {
            emit IncludeInFee(account);
            _isExcludedFromFee[account] = false;
        }
    
        function isExcludedFromFee(address account) public view returns(bool) {
            return _isExcludedFromFee[account];
        }
    
        function setDexWithSellFee(address account, bool value) external onlyOwner {
            _isDEXSellFee[account] = value;
        }
    
    
        function isDexWithSellFee(address account) public view returns(bool) {
            return _isDEXSellFee[account];
        }
    
        function setDexWithBuyFee(address account, bool value) external onlyOwner {
            _isDEXBuyFee[account] = value;
        }
    
        function isDexWithBuyFee(address account) public view returns(bool) {
            return _isDEXBuyFee[account];
        }
    
    
        // \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ LP functions \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
    
        function setSwapAndLiquifyEnabled(bool _enabled) external onlyOwner {
            emit SwapAndLiquifyEnabled(_enabled);
            swapAndLiquifyEnabled = _enabled;
    
            emit LiquifySwapUpdatedEnabled(_enabled);
        }
    
        //to receive ETH from uniswapRouter when swapping
        receive() external payable {}
    
        function _takeLiquidity(uint256 tLiquidity) private {
            uint256 currentRate =  _getRate();
            uint256 rLiquidity = tLiquidity.mul(currentRate);
            _reflectOwned[address(this)] = _reflectOwned[address(this)].add(rLiquidity);
            if(_isExcluded[address(this)])
                _takeOwned[address(this)] = _takeOwned[address(this)].add(tLiquidity);
        }
    
        function swapAndLiquifyByOwner(uint256 amount) external onlyOwner {
            swapAndLiquify(amount);
        }
    
        function swapAndLiquify(uint256 contractTokenBalance) private lockSwaping {
            // split the contract balance into halves
            uint256 half = contractTokenBalance.div(2);
            uint256 otherHalf = contractTokenBalance.sub(half);
    
            // capture the contract's current ETH balance.
            // this is so that we can capture exactly the amount of ETH that the
            // swap creates, and not make the liquidity event include any ETH that
            // has been manually sent to the contract
            uint256 initialBalance = address(this).balance;
    
            // swap tokens for ETH
            swapTokensForETH(half); // <- this breaks the ETH -> HATE swap when swap+liquify is triggered
    
            // how much ETH did we just swap into?
            uint256 newBalance = address(this).balance.sub(initialBalance);
    
            // add liquidity to pancakswap
            addLiquidity(otherHalf, newBalance);
    
            emit SwapAndLiquifyEvent(half, newBalance, otherHalf);
        }
    
        function swapTokensForETH(uint256 tokenAmount) private {
            // generate the uniswap pair path of token -> weth
            address[] memory path = new address[](2);
            path[0] = address(this);
            path[1] = uniswapRouter.WETH();
    
            _approve(address(this), address(uniswapRouter), tokenAmount);
    
            // make the swap
            uniswapRouter.swapExactTokensForETHSupportingFeeOnTransferTokens(
                tokenAmount,
                0, // accept any amount of ETH
                path,
                address(this),
                block.timestamp
            );
        }
    
        function addLiquidity(uint256 tokenAmount, uint256 ethAmount) private {
            emit AddLiquidity(tokenAmount, ethAmount);
            // approve token transfer to cover all possible scenarios
            _approve(address(this), address(uniswapRouter), tokenAmount);
    
            // add the liquidity
            uniswapRouter.addLiquidityETH{value: ethAmount}(
                address(this),
                tokenAmount,
                0, // slippage is unavoidable
                0, // slippage is unavoidable
                owner(),
                block.timestamp
            );
        }
    
        // \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Reflection functions \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
    
    
        function tokenFromReflection(uint256 reflectAmount) public view returns(uint256) {
            require(reflectAmount <= _reflectTotal, "Amount must be less than total reflections");
            uint256 currentRate =  _getRate();
    
            return reflectAmount.div(currentRate);
        }
    
        // \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Custom transfer functions \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
    
        function _transfer(
            address from,
            address to,
            uint256 amount
        ) private {
            require( !_isBot[to], "BEP20: transfer to the bot address");
            require( !_isBot[from], "BEP20: transfer from the bot address");
            require(from != address(0), "BEP20: transfer from the zero address");
            require(to != address(0), "BEP20: transfer to the zero address");
            require(amount > 0, "Transfer amount must be greater than zero");
            if(from != owner() && to != owner())
                require(amount <= _maximumValueOfTransaction, "Transfer amount exceeds the maxTxAmount.");
    
    
            uint256 contractTokenBalance = balanceOf(address(this));
    
            if(contractTokenBalance >= _maximumValueOfTransaction){contractTokenBalance = _maximumValueOfTransaction;}
    
            bool overMinimumCoinBalance = contractTokenBalance >= numTokensSellToAddToLiquidity;
            if (
                overMinimumCoinBalance &&
                !isIntoLiquifySwap &&
                from != uniswapPair &&
                swapAndLiquifyEnabled
            ) {
                contractTokenBalance = numTokensSellToAddToLiquidity;
                //add liquidity
                swapAndLiquify(contractTokenBalance);
            }
    
            //indicates if fee should be deducted from transfer
            bool takeFee = _taxFeeFlag;
    
            if(_isDEXSellFee[to] && !_isExcludedFromFee[from]){
                takeFee = true;
                _previousLiquidityFee = _liquidityFee;
                _liquidityFee = _liquiditySellFee;
            } else if(_isDEXBuyFee[from] && !_isExcludedFromFee[to]){
                takeFee = true;
            }
    
            //transfer amount, it will take liquidity fee
            _tokenTransfer(from,to,amount,takeFee);
    
            if(takeFee = true){
                _liquidityFee = _previousLiquidityFee;
            }
    
        }
    
        //this method is responsible for taking all fee, if takeFee is true
        function _tokenTransfer(address sender, address recipient, uint256 amount,bool takeFee) private {
    
            if(!takeFee){removeAllFee();}
    
            (uint256 reflectAmount, uint256 reflectAmountToTransfer, uint256 rFee, uint256 takeAmountToTransfer, uint256 tFee, uint256 tLiquidity) = _getValues(amount);
    
            _reflectOwned[sender] = _reflectOwned[sender].sub(reflectAmount);
            _reflectOwned[recipient] = _reflectOwned[recipient].add(reflectAmountToTransfer);
    
    
            _takeLiquidity(tLiquidity);
            
            emit Transfer(sender, recipient, takeAmountToTransfer);
    
            if(!takeFee){restoreAllFee();}
        }
    }