ETH Price: $3,456.17 (-0.78%)
Gas: 2 Gwei

Contract

0xc9E6c3B7B7C256BE5EEae0987CBA7a9cC57A68DA
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Initialize173720942023-05-30 13:38:59398 days ago1685453939IN
0xc9E6c3B7...cC57A68DA
0 ETH0.0092227449.79532724
0x60c06040172950692023-05-19 17:38:59409 days ago1684517939IN
 Create: FeeCollector
0 ETH0.1078208539.62680674

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
FeeCollector

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 17 : FeeCollector.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "./interfaces/IUniswapV2Router.sol";
import "./interfaces/IFeeCollector.sol";
import "./interfaces/IStaking.sol";
import "./tokens/InQubeta.sol";

contract FeeCollector is IFeeCollector, AccessControl {
    using SafeERC20 for IERC20;

    struct Fee {
        uint256 Rewards; // The percentage of the total transaction amount that will be allocated to rewards
        uint256 Liquidity; // The percentage of the total transaction amount that will be allocated to liquidity
        uint256 Marketing; // The percentage of the total transaction amount that will be allocated to marketing
        uint256 Burn; // The percentage of the total transaction amount that will be burned
    }

    /// @notice Access Control InQubeta token ERC20 role hash
    bytes32 public constant INQUBETA_ROLE = keccak256("INQUBETA_ROLE");
    /// @notice Access Control InQubeta token ERC20 role hash
    bytes32 public constant ADMIN_UPDATER_ROLE =
        keccak256("ADMIN_UPDATER_ROLE");
    /// @notice Precision for mathematical calculations with percentages. 100% is equivalent to 1e21
    uint256 private constant PRECISION = 1e21;
    /// @notice Variable indicates whether the contract has been initialized
    bool public isInitialized;

    /// @notice The address of the InQubeta token
    address public immutable inQubetaToken;
    /// @notice The address of the Uniswap router contract
    address public immutable swapRouter;
    /// @notice The address where the marketing fees will be sent
    address public marketingRecipient;
    /// @notice The address of the contract responsible for staking
    address public stakingContract;
    /// @notice The value of the distribution of rewards
    uint256 public rewardsAmount;
    /// @notice The value of the liquidity distribution
    uint256 public liquidityAmount;
    /// @notice The value for transfer to marketing wallet
    uint256 public marketingAmount;
    /// @notice The value that will be burned by the token
    uint256 public burnAmount;
    /// @notice The minimum value at which liquidity percentages are within the allowed range
    uint256 public minLiquidity;
    /// @notice timestamp indicating when the current reward period ends
    uint256 public periodFinish;
    /// @notice The duration of each reward period
    uint256 public periodDuration;
    /// @notice The path to the pair token on the Uniswap exchange
    address[] public pathToPairToken;
    /// @notice Record structure before purchases
    Fee public buyFeeInfo;
    /// @notice Record structure before sell
    Fee public sellFeeInfo;

    /// ================================ Errors ================================ ///

    /// @notice An error thrown when an address doesn't have the required access level to execute a function
    error AccessIsDenied(string err);
    /// @notice An error thrown when a given address is not used for a specific operation
    error AddressNotUsed(string err);
    /// @notice An error thrown when a non-contract address is provided where a contract address is expected
    error IsNotContract(string err);
    ///@notice An error thrown when a function is passed a zero address
    error ZeroAddress(string err);
    ///@notice An error thrown when a function is passed an amount of zero
    error ZeroAmount(string err);
    /// @notice An error thrown when a function is passed a value higher than the maximum allowed
    error HighValue(string err);
    /// @notice An error thrown when a function is passed an address that is already in use
    error ExistsAddress(string err);
    /// @notice An error thrown when indicating an invalid timestamp value
    error TimeError(string err);
    //// @notice An error thrown when an attempt is made to initialize a contract that has already been initialized
    error ContractIsAlreadyInitialized(string err);
    /// @notice An error thrown when the path array has an invalid length.
    error InvalidPathLength(string err);
    /// @notice An error thrown when ETH transfer failed
    error TransferFailed(string err);

    /// ================================ Events ================================ ///

    /// Emitted when after rewards are distributed to various addresses
    event Distribute(
        uint256 rewardsAmount,
        uint256 liquidityAmount,
        uint256 marketingAmount,
        uint256 burnAmount,
        uint256 indexed timestamp
    );
    /// Emitted when after successfully updating the fee distribution
    event UpdateDistAmounts(
        bool indexed isBuyFee,
        uint256 rewardsAmount,
        uint256 liquidityAmount,
        uint256 marketingAmount,
        uint256 burnAmount,
        uint256 indexed timestamp
    );
    /// Emitted when after successfully updating the path of the token pair
    event UpdatePathToPairToken(
        address[] indexed pathToPairToken,
        uint256 indexed timestamp
    );
    /// Emitted when after successfully updating the minimum number of tokens required to collect the fee
    event UpdateMinLiquidity(uint256 minLiquidity, uint256 indexed timestamp);
    /// Emitted when after successfully updating the end time of the current period to collect the fee
    event UpdatePeriodFinish(
        uint256 newPerionFinish,
        uint256 indexed timestamp
    );
    /// Emitted when after successfully updating the duration of the commission collection period
    event UpdatePeriodDuration(
        uint256 newPerionDuration,
        uint256 indexed timestamp
    );
    /// Emitted when after successfully updating the staking contract address
    event UpdateStakingContract(
        address indexed stakingContract,
        uint256 indexed timestamp
    );
    /// Emitted when after successfully updating the marketing recipient address
    event UpdateMarketingRecipient(
        address indexed marketingRecipient,
        uint256 indexed timestamp
    );
    /// Emitted when after successfully updating the address of the contract owner
    event UpdateOwner(address newOwner, uint256 indexed timestamp);
    /// @notice Emitted when certain tokens mistakenly sent to the contract
    event RecoverERC20(
        address indexed tokenAddress,
        uint256 tokenAmount,
        address indexed recipient,
        uint256 indexed timestamp
    );
    /// @notice Emitted when transferring funds from the wallet еther of the selected token contract to the specified wallet
    event Recover(
        address indexed to,
        uint256 amount,
        uint256 indexed timestamp
    );

    constructor(
        address _owner, /// The address of the contract owner
        Fee memory _buyFeeAllocations, // The allocation of fees to various purposes for buy transactions
        Fee memory _sellFeeAccocations, // The allocation of fees to various purposes for sell transactions
        address _inqubetaToken, // The address of the InQubeta token contract
        address _uniRouter, // The address of the Uniswap router contract that will be used for swapping tokens
        address _marketingRecipient, // The address to which the marketing fees will be sent
        uint256 _minLiquidity // The minimum value at which liquidity percentages are within the allowed range
    )
        checkMaxFeeAllocations(_buyFeeAllocations)
        checkMaxFeeAllocations(_sellFeeAccocations)
    {
        if (
            !Address.isContract(_inqubetaToken) ||
            !Address.isContract(_uniRouter)
        ) {
            revert IsNotContract("Address is not a contract");
        }
        if (_owner == address(0) || _marketingRecipient == address(0)) {
            revert ZeroAddress("Zero address");
        }

        marketingRecipient = _marketingRecipient;
        buyFeeInfo = _buyFeeAllocations;
        sellFeeInfo = _sellFeeAccocations;
        inQubetaToken = _inqubetaToken;
        swapRouter = _uniRouter;
        minLiquidity = _minLiquidity;
        periodDuration = 1 days;

        _grantRole(ADMIN_UPDATER_ROLE, _owner);
        _grantRole(DEFAULT_ADMIN_ROLE, _owner);
        _grantRole(INQUBETA_ROLE, _inqubetaToken);
        _makeApprove(IERC20(inQubetaToken), swapRouter);
    }

    receive() external payable {}

    /**
     * @notice The modifier checks if the sum of the four values in a Fee struct exceeds a certain precision value
     * @param _fees The sum of the four values Fee
     */
    modifier checkMaxFeeAllocations(Fee memory _fees) {
        if (
            _fees.Rewards + _fees.Liquidity + _fees.Marketing + _fees.Burn !=
            PRECISION
        ) {
            revert HighValue("Percents sum should equal precision");
        }
        _;
    }

    /**
     * @notice The modifier сhecks whether the given path of tokens is valid for swaps
     * @param path The path of tokens to be used for swaps
     */
    modifier isCheckPathToToken(address[] memory path) {
        if (path.length <= 1) {
            revert("Path must contain at least two elements");
        }
        for (uint256 i; i < path.length; i++) {
            if (!Address.isContract(path[i])) {
                revert IsNotContract("Address is not a contract");
            }
        }
        _;
    }

    /**
     * @notice The modifier checks whether the contract has been initialized
     * Prevents reinitialization
     */
    modifier isInited() {
        if (isInitialized) {
            revert ContractIsAlreadyInitialized("Already initialized");
        }
        _;
    }

    /// ================================ External functions ================================ ///

    /**
     * @notice The function initializes some contracts may not exist at the time of deploying this contract
     * @param _stakingContract The address of the staking contract
     * @param _path An array of addresses representing the path to the pair token
     */
    function initialize(
        address _stakingContract,
        address[] memory _path
    ) external onlyRole(DEFAULT_ADMIN_ROLE) isInited isCheckPathToToken(_path) {
        if (!Address.isContract(_stakingContract)) {
            revert IsNotContract("Address is not a contract");
        }

        stakingContract = _stakingContract;
        pathToPairToken = _path;
        periodFinish = block.timestamp + periodDuration;

        _makeApprove(
            IERC20(pathToPairToken[pathToPairToken.length - 1]),
            swapRouter
        );
        isInitialized = true;
    }

    /**
     * @notice External function the buy fees for the distribution period
     * @param amount Value to write
     */
    function recordBuyFee(
        uint256 amount
    ) external override onlyRole(INQUBETA_ROLE) {
        _updateDistAmounts(amount, buyFeeInfo, true);
    }

    /**
     * @notice External function the sell fees for the distribution period
     * @param amount Value to write
     */
    function recordSellFee(
        uint256 amount
    ) external override onlyRole(INQUBETA_ROLE) {
        _updateDistAmounts(amount, sellFeeInfo, false);
    }

    /**
    * @notice External function is used to distribute the collected fees,
    rewards and liquidity to the respective parties if the distribution period has ended
     */
    function distributeIfNeeded() external override {
        if (block.timestamp >= periodFinish) {
            (
                uint256 rewards,
                uint256 marketing,
                uint256 burn,
                uint256 liquidity
            ) = _distribute();

            periodFinish = block.timestamp + periodDuration;
            emit Distribute(
                rewards,
                liquidity,
                marketing,
                burn,
                block.timestamp
            );
        }
    }

    /**
     * @notice An external function that performs the approval of ERC20 tokens for Swap Router
     */
    function approveErc20ForRouter(
        address token
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (token == address(0)) {
            revert ZeroAddress("Zero address");
        }
        _makeApprove(IERC20(token), swapRouter);
    }

    /**
     * @notice External function for certain tokens mistakenly sent to the contract
     * @param tokenAddress The address of the token to be rescued
     * @param tokenAmount The amount of tokens to be rescued
     * @param recipient The address to which the tokens will be sent
     */
    function recoverERC20(
        address tokenAddress,
        uint256 tokenAmount,
        address recipient
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (tokenAddress == inQubetaToken) {
            revert AddressNotUsed("Sending InQubeta token not allowed");
        }
        if (recipient == address(0) || tokenAddress == address(0)) {
            revert ZeroAddress("Zero address");
        }
        if (tokenAmount == 0) {
            revert ZeroAmount("Cannot rescue 0");
        }
        IERC20(tokenAddress).safeTransfer(recipient, tokenAmount);
        emit RecoverERC20(
            tokenAddress,
            tokenAmount,
            recipient,
            block.timestamp
        );
    }

    /**
     * @notice External function for tokens mistakenly sent to the contract
     * @param to The address to which the tokens will be sent
     * @param amount The amount of tokens to be rescued
     */
    function recover(
        address to,
        uint256 amount
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (to == address(0)) {
            revert ZeroAddress("Zero address");
        }
        if (amount == 0) {
            revert ZeroAmount("Cannot rescue 0");
        }

        (bool success, ) = to.call{value: amount}("");
        if (!success) {
            revert TransferFailed("ETH transfer failed");
        }
        emit Recover(to, amount, block.timestamp);
    }

    /**
     * @notice External function update the pair token path using the specified addresses
     * @param newPath The array of token addresses forming a pair of trades is specified in the correct order
     */
    function updatePathToPairToken(
        address[] memory newPath
    ) external onlyRole(DEFAULT_ADMIN_ROLE) isCheckPathToToken(newPath) {
        pathToPairToken = newPath;
        _makeApprove(IERC20(newPath[newPath.length - 1]), swapRouter);
        emit UpdatePathToPairToken(newPath, block.timestamp);
    }

    /**
     * @notice External function update minimum value at which liquidity percentages are within the allowed range
     * @param newMinLiquidity New value at which liquidity percentages are within the allowed range
     */
    function updateMinLiquidity(
        uint256 newMinLiquidity
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        minLiquidity = newMinLiquidity;
        emit UpdateMinLiquidity(newMinLiquidity, block.timestamp);
    }

    /**
     * @notice External function update the end time of the current distribution period
     * @param newPeriodFinish The new end time for the distribution period, in Unix time
     */
    function updatePeriodFinish(
        uint256 newPeriodFinish
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (newPeriodFinish < block.timestamp) {
            revert TimeError("Finish period cannot be in the past");
        }
        periodFinish = newPeriodFinish;
        emit UpdatePeriodFinish(newPeriodFinish, block.timestamp);
    }

    /**
     * @notice External function updates the duration of the distribution period for rewards and fees
     * @param newPeriodDuration The duration time for the distribution period, in Unix time
     */
    function updatePeriodDuration(
        uint256 newPeriodDuration
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (newPeriodDuration == 0) {
            revert ZeroAmount("Duration cannot that zero");
        }
        periodDuration = newPeriodDuration;
        emit UpdatePeriodDuration(newPeriodDuration, block.timestamp);
    }

    /**
     * @notice External function updates the address of the marketing recipient
     * @param newMarketingRecipient The new address of the marketing recipient
     */
    function updateMarketingRecipient(
        address newMarketingRecipient
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (newMarketingRecipient == address(0)) {
            revert ZeroAddress("Zero address");
        }
        if (newMarketingRecipient == marketingRecipient) {
            revert ExistsAddress("No new address specified");
        }

        marketingRecipient = newMarketingRecipient;
        emit UpdateMarketingRecipient(newMarketingRecipient, block.timestamp);
    }

    /**
     * @notice External function updates the address the staking contract
     that is used to distribute rewards to stakers
     * @param newStakingContract The address of the new staking contract
     */
    function updateStakingContract(
        address newStakingContract
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (!Address.isContract(newStakingContract)) {
            revert IsNotContract("Address is not a contract");
        }
        if (newStakingContract == stakingContract) {
            revert ExistsAddress("No new address specified");
        }

        stakingContract = newStakingContract;
        emit UpdateStakingContract(newStakingContract, block.timestamp);
    }

    /**
     * @notice External function update the contract owner
     * @param newOwner Address of the new contract owner
     */
    function updateOwner(
        address newOwner
    ) external onlyRole(ADMIN_UPDATER_ROLE) {
        if (newOwner == address(0)) {
            revert ZeroAddress("Zero address");
        }

        _revokeRole(DEFAULT_ADMIN_ROLE, msg.sender);
        _grantRole(DEFAULT_ADMIN_ROLE, newOwner);
        emit UpdateOwner(newOwner, block.timestamp);
    }

    /// ================================ Internal functions ================================ ///

    /**
    * @notice Internal function is used to distribute the collected fees,
    rewards and liquidity to the respective parties if the distribution period has ended
     */
    function _distribute()
        internal
        returns (
            uint256 rewards,
            uint256 marketing,
            uint256 burn,
            uint256 liquidity
        )
    {
        if (rewardsAmount > 0) {
            IERC20(inQubetaToken).transfer(stakingContract, rewardsAmount);
            IStaking(stakingContract).notifyRewardAmount(rewardsAmount);
            rewards = rewardsAmount;
            rewardsAmount = 0;
        }
        if (marketingAmount > 0) {
            IERC20(inQubetaToken).transfer(marketingRecipient, marketingAmount);
            marketing = marketingAmount;
            marketingAmount = 0;
        }
        if (burnAmount > 0) {
            InQubeta(inQubetaToken).burn(burnAmount);
            burn = burnAmount;
            burnAmount = 0;
        }
        if (liquidityAmount > minLiquidity) {
            uint256 processAmount = _swapAndAddLiquidity(liquidityAmount);
            liquidity = liquidityAmount - processAmount;
            liquidityAmount = processAmount;
        }
    }

    /**
    * @notice The function is intended for the distribution of fee amounts between different roles
    (the distribution of the fee is carried out according to the transferred Fee object)
    * @param amount The amount of remuneration to be distributed between different roles
     */
    function _updateDistAmounts(
        uint256 amount,
        Fee memory _fees,
        bool isBuyFee
    ) internal {
        rewardsAmount += (amount * _fees.Rewards) / PRECISION;
        liquidityAmount += (amount * _fees.Liquidity) / PRECISION;
        marketingAmount += (amount * _fees.Marketing) / PRECISION;
        burnAmount += (amount * _fees.Burn) / PRECISION;
        emit UpdateDistAmounts(
            isBuyFee,
            rewardsAmount,
            liquidityAmount,
            marketingAmount,
            burnAmount,
            block.timestamp
        );
    }

    /**
     * @notice Internal function is designed to exchange half of the transferred amount
     for a pair of tokens and add the received liquidity to the UniswapV2 pair
     * @param amount The amount of tokens to be exchanged and added to the pair
     */
    function _swapAndAddLiquidity(uint256 amount) internal returns (uint256) {
        InQubeta(inQubetaToken).disableFees();

        uint256 processAmount = amount;

        uint256[] memory amounts = IUniswapV2Router(swapRouter)
            .swapExactTokensForTokens(
                amount / 2,
                0,
                pathToPairToken,
                address(this),
                block.timestamp
            );

        processAmount -= amounts[0];

        (uint256 amountA, , ) = IUniswapV2Router(swapRouter).addLiquidity(
            pathToPairToken[0],
            pathToPairToken[pathToPairToken.length - 1],
            amounts[0],
            amounts[amounts.length - 1],
            1,
            1,
            address(this),
            block.timestamp
        );

        processAmount -= amountA;

        InQubeta(inQubetaToken).enableFees();

        return processAmount;
    }

    /**
     * @notice Internal function is intended to grant permission to spend tokens
     of the specified token to the specified manager of funds
     * @param token The interface of the ERC20 token to be authorized
     * @param spender The address to be granted
     */
    function _makeApprove(IERC20 token, address spender) internal {
        uint256 allowance = token.allowance(address(this), spender);
        if (allowance < type(uint256).max) {
            token.safeIncreaseAllowance(spender, type(uint256).max - allowance);
        }
    }
}

File 2 of 17 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.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

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 3 of 17 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, 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 `from` to `to` 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 from,
        address to,
        uint256 amount
    ) external returns (bool);
}

File 4 of 17 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 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 SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 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
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20 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'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _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(IERC20 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, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 5 of 17 : AccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (access/AccessControl.sol)

pragma solidity ^0.8.0;

import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     *
     * _Available since v4.1._
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `_msgSender()` is missing `role`.
     * Overriding this function changes the behavior of the {onlyRole} modifier.
     *
     * Format of the revert message is described in {_checkRole}.
     *
     * _Available since v4.6._
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        Strings.toHexString(uint160(account), 20),
                        " is missing role ",
                        Strings.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) public virtual override {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     *
     * NOTE: This function is deprecated in favor of {_grantRole}.
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * Internal function without access restriction.
     */
    function _grantRole(bytes32 role, address account) internal virtual {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * Internal function without access restriction.
     */
    function _revokeRole(bytes32 role, address account) internal virtual {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}

File 6 of 17 : IUniswapV2Router.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

interface IUniswapV2Router {
    function factory() external pure returns (address);

    function WETH() external pure returns (address);

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);

    function addLiquidityETH(
        address token,
        uint256 amountTokenDesired,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    )
        external
        payable
        returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);

    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountA, uint256 amountB);

    function removeLiquidityETH(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountToken, uint256 amountETH);

    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountA, uint256 amountB);

    function removeLiquidityETHWithPermit(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountToken, uint256 amountETH);

    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapTokensForExactTokens(
        uint256 amountOut,
        uint256 amountInMax,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapExactETHForTokens(
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable returns (uint256[] memory amounts);

    function swapTokensForExactETH(
        uint256 amountOut,
        uint256 amountInMax,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapExactTokensForETH(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapETHForExactTokens(
        uint256 amountOut,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable returns (uint256[] memory amounts);

    function quote(
        uint256 amountA,
        uint256 reserveA,
        uint256 reserveB
    ) external pure returns (uint256 amountB);

    function getAmountOut(
        uint256 amountIn,
        uint256 reserveIn,
        uint256 reserveOut
    ) external pure returns (uint256 amountOut);

    function getAmountIn(
        uint256 amountOut,
        uint256 reserveIn,
        uint256 reserveOut
    ) external pure returns (uint256 amountIn);

    function getAmountsOut(
        uint256 amountIn,
        address[] calldata path
    ) external view returns (uint256[] memory amounts);

    function getAmountsIn(
        uint256 amountOut,
        address[] calldata path
    ) external view returns (uint256[] memory amounts);
}

File 7 of 17 : IFeeCollector.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

interface IFeeCollector {
    function recordBuyFee(uint amount) external;

    function recordSellFee(uint amount) external;

    function distributeIfNeeded() external;
}

File 8 of 17 : IStaking.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

interface IStaking {
    function notifyRewardAmount(uint256 reward) external;
}

File 9 of 17 : InQubeta.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "../interfaces/IFeeCollector.sol";

contract InQubeta is ERC20, ERC20Burnable, AccessControl {
    /// @notice Precision for mathematical calculations with percents. 100% === 10000
    uint256 private constant PRECISION = 100_00;
    /// @notice Access Control fee collector role hash
    bytes32 public constant FEE_DISTRIBUTION_ROLE =
        keccak256("FEE_DISTRIBUTION_ROLE");
    /// @notice fee collector address
    address public feeCollector;
    /// @notice the percentage of the fee charged for the purchase of the token
    uint256 public buyFee;
    /// @notice the percentage of the fee charged for the selling of the token
    uint256 public sellFee;
    /// @notice bool value, if true, fees is enabled, if false, disabled
    bool public isEnabledFees;
    /// @notice pair mapping, if true the pair is added and fees are charged,
    /// if false, no fees are charged
    mapping(address => bool) public pairs;

    /// ================================ Errors ================================ ///

    /// @dev - address is not a contract;
    error IsNotContract(string err);
    ///@dev returned if passed zero address
    error ZeroAddress(string err);
    ///@dev returned if passed zero amount
    error ZeroAmount(string err);
    ///@dev returned if the set percentage is equal to or greater than PRECISION
    error HighValue(string err);
    ///@dev returned if the pair address already exists
    error ExistsAddress(string err);
    ///@dev returned if the value already assigned
    error ExistsValue(string err);
    ///@dev returned if the pair address has not been added
    error NotFoundAddress(string err);
    ///@dev returned if the caller dont have access to function
    error AccessIsDenied(string err);

    /// ================================ Events ================================ ///

    ///@dev emitted when owner add new pair
    event AddPair(
        address indexed addressPair,
        bool enabled,
        uint256 indexed timestamp
    );
    ///@dev emitted when owner set fee percents
    event SetFees(uint256 buyFee, uint256 sellFee, uint256 indexed timestamp);
    ///@dev emitted when owner update fee collector address
    event UpdateFeeCollector(
        address indexed feeCollector,
        uint256 indexed timestamp
    );
    ///@dev emitted when fees enabled
    event EnableFees(bool indexed enabled, uint256 indexed timestamp);
    ///@dev emitted when fees disabled
    event DisableFees(bool indexed enabled, uint256 indexed timestamp);
    ///@dev emitted when owner disable pair address
    event RemovePair(
        address indexed addressPair,
        bool disable,
        uint256 indexed timestamp
    );
    ///@dev emitted when buy fee is updated for all pairs
    event UpdateBuyFee(uint256 buyFee, uint256 indexed timestamp);
    ///@dev emitted when sell fee is updated for all pairs
    event UpdateSellFee(uint256 buyFee, uint256 indexed timestamp);

    constructor(
        address _admin, /// contract owner
        uint256 _initialSupply, /// total supply of tokens
        uint256 _buyFee, /// buy fee percent. 5% * 100 = 500
        uint256 _sellFee, /// buy fee percent. 10% * 100 = 1000
        address _feeCollector /// fee collector contract addrees
    ) ERC20("InQubeta", "QUBE") checkMaxFee(_buyFee, _sellFee) {
        if (_feeCollector == address(0) || _admin == address(0)) {
            revert ZeroAddress("InQubeta: Zero address");
        }
        if (!Address.isContract(_feeCollector)) {
            revert IsNotContract("InQubeta: Fee collector is not a contract");
        }

        _mint(_admin, _initialSupply);
        feeCollector = _feeCollector;

        _grantRole(DEFAULT_ADMIN_ROLE, _admin);
        _grantRole(FEE_DISTRIBUTION_ROLE, _admin);
        _grantRole(FEE_DISTRIBUTION_ROLE, _feeCollector);

        buyFee = _buyFee;
        sellFee = _sellFee;
        isEnabledFees = true;
    }

    /**
    @dev the modifier checks whether the commission percentages 
    are within the allowed range
    */
    modifier checkMaxFee(uint256 _buyFee, uint256 _sellFee) {
        if (_buyFee >= PRECISION || _sellFee >= PRECISION) {
            revert HighValue("InQubeta: Fee value is too high");
        }
        _;
    }

    /**
     * @notice The function performs an ERC20 transfer, but with some modifications. In the event
     *  that the token will be sent to the pool that is added to our contract, the sell commission
     *  will be charged from the number of tokens sent. If the token will
     *  be sent from the pool, the buy fee will be charged from the number of tokens sent.
     * If it is a normal transfer that is not sent to or from the pool,
     * it will work as a standard ERC20 transfer
     */
    function transfer(
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        return _transferFrom(msg.sender, to, amount);
    }

    /**
     * @notice The function performs an ERC20 transferFrom, but with some modifications. In the event
     *  that the token will be sent to the pool that is added to our contract, the sell commission
     *  will be charged from the number of tokens sent. If the token will
     *  be sent from the pool, the buy fee will be charged from the number of tokens sent.
     *  If it is a normal transferFrom that is not sent to or from the pool,
     *  it will work as a standard ERC20 transferFrom.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        _spendAllowance(from, msg.sender, amount);
        return _transferFrom(from, to, amount);
    }

    /**
     * @notice The function adds a new pair from which commissions will be charged
     * for the purchase and sale of our token. Only the owner can call.
     * @param addressPair - pair address
     */
    function addPair(
        address addressPair
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (addressPair == address(0)) {
            revert ZeroAddress("InQubeta: Zero address");
        }

        if (pairs[addressPair]) {
            revert ExistsAddress("InQubeta: Address already exists");
        }

        pairs[addressPair] = true;
        emit AddPair(addressPair, true, block.timestamp);
    }

    /**
     * @notice The function performs disabling pool.
     * Only the owner can call.
     * @param addressPair - pair address
     */
    function removePair(
        address addressPair
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (addressPair == address(0)) {
            revert ZeroAddress("InQubeta: Zero address");
        }

        pairs[addressPair] = false;
        emit RemovePair(addressPair, false, block.timestamp);
    }

    /**
     * @notice The function performs disabling buy and sell fees.
     * Only the default admin or fee collector can call it.
     */
    function disableFees() external onlyRole(FEE_DISTRIBUTION_ROLE) {
        isEnabledFees = false;
        emit DisableFees(false, block.timestamp);
    }

    /**
     * @notice The function performs enabling buy and sell fees.
     * Only the default admin or fee collector can call it.
     */
    function enableFees() external onlyRole(FEE_DISTRIBUTION_ROLE) {
        isEnabledFees = true;
        emit EnableFees(true, block.timestamp);
    }

    /**
     * @notice The function updates the buy fee percentage.
     * Only the owner can call.
     * @param _buyFee - sell fee percent
     */
    function updateBuyFee(
        uint256 _buyFee
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (_buyFee >= PRECISION) {
            revert HighValue("InQubeta: Fee value is too high");
        }

        buyFee = _buyFee;
        emit UpdateBuyFee(_buyFee, block.timestamp);
    }

    /**
     * @notice The function updates the sell fee percentage.
     * Only the owner can call.
     * @param _sellFee - sell fee percent
     */
    function updateSellFee(
        uint256 _sellFee
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (_sellFee >= PRECISION) {
            revert HighValue("InQubeta: Fee value is too high");
        }

        sellFee = _sellFee;
        emit UpdateSellFee(_sellFee, block.timestamp);
    }

    /**
     * @notice The function updates the settings of commission percentages
     * for buying and selling. Only the owner can call.
     * @param _buyFee - buy fee percent
     * @param _sellFee - sell fee percent
     */
    function updateFeesPercents(
        uint256 _buyFee,
        uint256 _sellFee
    ) external onlyRole(DEFAULT_ADMIN_ROLE) checkMaxFee(_buyFee, _sellFee) {
        buyFee = _buyFee;
        sellFee = _sellFee;

        emit SetFees(_buyFee, _sellFee, block.timestamp);
    }

    /**
     * @notice The function updates the address that receives all commissions.
     * Only the owner can call.
     * @param newFeeCollector - new fee collector address
     */
    function updateFeeCollector(
        address newFeeCollector
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (newFeeCollector == address(0)) {
            revert ZeroAddress("InQubeta: Zero address");
        }
        if (newFeeCollector == feeCollector) {
            revert ExistsAddress("InQubeta: No new address specified");
        }
        if (!Address.isContract(newFeeCollector)) {
            revert IsNotContract("InQubeta: Fee collector is not a contract");
        }
        revokeRole(FEE_DISTRIBUTION_ROLE, feeCollector);
        feeCollector = newFeeCollector;
        grantRole(FEE_DISTRIBUTION_ROLE, newFeeCollector);

        emit UpdateFeeCollector(newFeeCollector, block.timestamp);
    }

    /**
     * @notice Internal function that implements the logic of token transfer and the logic of fee collection.
     */
    function _transferFrom(
        address from,
        address to,
        uint256 amount
    ) internal returns (bool) {
        if (isEnabledFees) {
            if (pairs[to]) {
                uint256 fee = (amount * sellFee) / PRECISION;
                uint256 transferAmount = amount - fee;
                _transfer(from, feeCollector, fee);
                _transfer(from, to, transferAmount);
                IFeeCollector(feeCollector).recordSellFee(fee);
            } else if (pairs[from]) {
                uint256 fee = (amount * buyFee) / PRECISION;
                _transfer(from, to, amount);
                _transfer(to, feeCollector, fee);
                IFeeCollector(feeCollector).recordBuyFee(fee);
            } else {
                _transfer(from, to, amount);
            }
        } else {
            _transfer(from, to, amount);
        }
        return true;
    }
}

File 10 of 17 : IAccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}

File 11 of 17 : Context.sol
// 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 12 of 17 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }
}

File 13 of 17 : ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

File 14 of 17 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 15 of 17 : ERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/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, IERC20, IERC20Metadata {
    mapping(address => uint256) private _balances;

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

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The default value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

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

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless this function is
     * overridden;
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

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

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address to, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _approve(owner, 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}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, 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) {
        address owner = _msgSender();
        _approve(owner, spender, allowance(owner, 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) {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(owner, 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:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     */
    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(from, to, amount);

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[from] = fromBalance - amount;
        }
        _balances[to] += amount;

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

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

        _totalSupply += amount;
        _balances[account] += amount;
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

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

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
        }
        _totalSupply -= amount;

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

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
     *
     * Does not update the allowance amount in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Might emit an {Approval} event.
     */
    function _spendAllowance(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance >= amount, "ERC20: insufficient allowance");
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}
}

File 16 of 17 : ERC20Burnable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol)

pragma solidity ^0.8.0;

import "../ERC20.sol";
import "../../../utils/Context.sol";

/**
 * @dev Extension of {ERC20} that allows token holders to destroy both their own
 * tokens and those that they have an allowance for, in a way that can be
 * recognized off-chain (via event analysis).
 */
abstract contract ERC20Burnable is Context, ERC20 {
    /**
     * @dev Destroys `amount` tokens from the caller.
     *
     * See {ERC20-_burn}.
     */
    function burn(uint256 amount) public virtual {
        _burn(_msgSender(), amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, deducting from the caller's
     * allowance.
     *
     * See {ERC20-_burn} and {ERC20-allowance}.
     *
     * Requirements:
     *
     * - the caller must have allowance for ``accounts``'s tokens of at least
     * `amount`.
     */
    function burnFrom(address account, uint256 amount) public virtual {
        _spendAllowance(account, _msgSender(), amount);
        _burn(account, amount);
    }
}

File 17 of 17 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"components":[{"internalType":"uint256","name":"Rewards","type":"uint256"},{"internalType":"uint256","name":"Liquidity","type":"uint256"},{"internalType":"uint256","name":"Marketing","type":"uint256"},{"internalType":"uint256","name":"Burn","type":"uint256"}],"internalType":"struct FeeCollector.Fee","name":"_buyFeeAllocations","type":"tuple"},{"components":[{"internalType":"uint256","name":"Rewards","type":"uint256"},{"internalType":"uint256","name":"Liquidity","type":"uint256"},{"internalType":"uint256","name":"Marketing","type":"uint256"},{"internalType":"uint256","name":"Burn","type":"uint256"}],"internalType":"struct FeeCollector.Fee","name":"_sellFeeAccocations","type":"tuple"},{"internalType":"address","name":"_inqubetaToken","type":"address"},{"internalType":"address","name":"_uniRouter","type":"address"},{"internalType":"address","name":"_marketingRecipient","type":"address"},{"internalType":"uint256","name":"_minLiquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"string","name":"err","type":"string"}],"name":"AccessIsDenied","type":"error"},{"inputs":[{"internalType":"string","name":"err","type":"string"}],"name":"AddressNotUsed","type":"error"},{"inputs":[{"internalType":"string","name":"err","type":"string"}],"name":"ContractIsAlreadyInitialized","type":"error"},{"inputs":[{"internalType":"string","name":"err","type":"string"}],"name":"ExistsAddress","type":"error"},{"inputs":[{"internalType":"string","name":"err","type":"string"}],"name":"HighValue","type":"error"},{"inputs":[{"internalType":"string","name":"err","type":"string"}],"name":"InvalidPathLength","type":"error"},{"inputs":[{"internalType":"string","name":"err","type":"string"}],"name":"IsNotContract","type":"error"},{"inputs":[{"internalType":"string","name":"err","type":"string"}],"name":"TimeError","type":"error"},{"inputs":[{"internalType":"string","name":"err","type":"string"}],"name":"TransferFailed","type":"error"},{"inputs":[{"internalType":"string","name":"err","type":"string"}],"name":"ZeroAddress","type":"error"},{"inputs":[{"internalType":"string","name":"err","type":"string"}],"name":"ZeroAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"rewardsAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidityAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"marketingAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"burnAmount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"Distribute","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"Recover","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"RecoverERC20","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bool","name":"isBuyFee","type":"bool"},{"indexed":false,"internalType":"uint256","name":"rewardsAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidityAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"marketingAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"burnAmount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"UpdateDistAmounts","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"marketingRecipient","type":"address"},{"indexed":true,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"UpdateMarketingRecipient","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minLiquidity","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"UpdateMinLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"},{"indexed":true,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"UpdateOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address[]","name":"pathToPairToken","type":"address[]"},{"indexed":true,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"UpdatePathToPairToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newPerionDuration","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"UpdatePeriodDuration","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newPerionFinish","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"UpdatePeriodFinish","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stakingContract","type":"address"},{"indexed":true,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"UpdateStakingContract","type":"event"},{"inputs":[],"name":"ADMIN_UPDATER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INQUBETA_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveErc20ForRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"burnAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"buyFeeInfo","outputs":[{"internalType":"uint256","name":"Rewards","type":"uint256"},{"internalType":"uint256","name":"Liquidity","type":"uint256"},{"internalType":"uint256","name":"Marketing","type":"uint256"},{"internalType":"uint256","name":"Burn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"distributeIfNeeded","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"inQubetaToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stakingContract","type":"address"},{"internalType":"address[]","name":"_path","type":"address[]"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidityAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketingAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketingRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"pathToPairToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"periodDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"periodFinish","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"recordBuyFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"recordSellFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"recover","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardsAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sellFeeInfo","outputs":[{"internalType":"uint256","name":"Rewards","type":"uint256"},{"internalType":"uint256","name":"Liquidity","type":"uint256"},{"internalType":"uint256","name":"Marketing","type":"uint256"},{"internalType":"uint256","name":"Burn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapRouter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newMarketingRecipient","type":"address"}],"name":"updateMarketingRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMinLiquidity","type":"uint256"}],"name":"updateMinLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"updateOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"newPath","type":"address[]"}],"name":"updatePathToPairToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPeriodDuration","type":"uint256"}],"name":"updatePeriodDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPeriodFinish","type":"uint256"}],"name":"updatePeriodFinish","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newStakingContract","type":"address"}],"name":"updateStakingContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c06040523480156200001157600080fd5b50604051620033a8380380620033a8833981016040819052620000349162000861565b85683635c9adc5dea0000081606001518260400151836020015184600001516200005f91906200090a565b6200006b91906200090a565b6200007791906200090a565b14620000c65760405163c55530a760e01b815260206004820152602360248201526000805160206200338883398151915260448201526234b7b760e91b60648201526084015b60405180910390fd5b85683635c9adc5dea000008160600151826040015183602001518460000151620000f191906200090a565b620000fd91906200090a565b6200010991906200090a565b14620001545760405163c55530a760e01b815260206004820152602360248201526000805160206200338883398151915260448201526234b7b760e91b6064820152608401620000bd565b6001600160a01b0386163b15806200017457506001600160a01b0385163b155b15620001c4576040516357a4a13960e01b815260206004820152601960248201527f41646472657373206973206e6f74206120636f6e7472616374000000000000006044820152606401620000bd565b6001600160a01b0389161580620001e257506001600160a01b038416155b15620002215760405163eac0d38960e01b815260206004820152600c60248201526b5a65726f206164647265737360a01b6044820152606401620000bd565b600180546001600160a01b0380871661010002610100600160a81b0319909216919091179091558851600b556020808a0151600c556040808b0151600d556060808c0151600e558a51600f55918a0151601055890151601155880151601255868116608052851660a052600783905562015180600955620002c37f5587a6603af31b5ced9f75f0d037b40683a035b85fa87fcdc3e12c7f36270f518a62000321565b620002d060008a62000321565b620002fc7f9fd5b15ed55a8ac36199f77ed1b6f7161f794df8f6d341a7ea74c2f67cbe70638762000321565b6200031260805160a051620003aa60201b60201c565b505050505050505050620009ed565b6200032d828262000458565b620003a6576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620003653390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b604051636eb1769f60e11b81523060048201526001600160a01b0382811660248301526000919084169063dd62ed3e90604401602060405180830381865afa158015620003fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000421919062000920565b90506000198110156200045357620004538262000441836000196200093a565b6001600160a01b038616919062000483565b505050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff165b92915050565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015620004d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004fb919062000920565b6200050791906200090a565b604080516001600160a01b038616602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b1790915291925062000563918691906200056916565b50505050565b6040805180820190915260208082527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656490820152600090620005b8906001600160a01b0385169084906200063a565b805190915015620004535780806020019051810190620005d9919062000950565b620004535760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401620000bd565b60606200064b848460008562000655565b90505b9392505050565b606082471015620006b85760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401620000bd565b6001600160a01b0385163b620007115760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620000bd565b600080866001600160a01b031685876040516200072f91906200099a565b60006040518083038185875af1925050503d80600081146200076e576040519150601f19603f3d011682016040523d82523d6000602084013e62000773565b606091505b5090925090506200078682828662000791565b979650505050505050565b60608315620007a25750816200064e565b825115620007b35782518084602001fd5b8160405162461bcd60e51b8152600401620000bd9190620009b8565b80516001600160a01b0381168114620007e757600080fd5b919050565b600060808284031215620007ff57600080fd5b604051608081016001600160401b03811182821017156200083057634e487b7160e01b600052604160045260246000fd5b8060405250809150825181526020830151602082015260408301516040820152606083015160608201525092915050565b60008060008060008060006101a0888a0312156200087e57600080fd5b6200088988620007cf565b96506200089a8960208a01620007ec565b9550620008ab8960a08a01620007ec565b9450620008bc6101208901620007cf565b9350620008cd6101408901620007cf565b9250620008de6101608901620007cf565b9150610180880151905092959891949750929550565b634e487b7160e01b600052601160045260246000fd5b808201808211156200047d576200047d620008f4565b6000602082840312156200093357600080fd5b5051919050565b818103818111156200047d576200047d620008f4565b6000602082840312156200096357600080fd5b815180151581146200064e57600080fd5b60005b838110156200099157818101518382015260200162000977565b50506000910152565b60008251620009ae81846020870162000974565b9190910192915050565b6020815260008251806020840152620009d981604085016020870162000974565b601f01601f19169190910160400192915050565b60805160a05161292862000a60600039600081816106460152818161089a01528181610dda015281816110f101528181611c3a0152611d050152600081816106ae0152818161117601528181611766015281816118840152818161192001528181611bba0152611e8301526129286000f3fe6080604052600436106102295760003560e01c8063836fcaf211610123578063b51609b4116100ab578063cde38c971161006f578063cde38c97146106d0578063d547741f146106f0578063d95de65614610710578063ebe2b12b14610725578063ee99205c1461073b57600080fd5b8063b51609b4146105fe578063c13d995c1461061e578063c31c9c0714610634578063c41b89ad14610668578063cc30e1621461069c57600080fd5b8063946d9204116100f2578063946d92041461055f578063a217fddf1461057f578063a60cc34414610594578063aa764ab3146105c8578063b470aade146105e857600080fd5b8063836fcaf2146104dc578063880cdc31146104fc578063892c60991461051c57806391d148541461053f57600080fd5b8063386a5d7c116101b15780635705ae43116101755780635705ae43146104235780636bb23bcb1461044357806370baed4314610463578063717cee7d1461047957806373f1edb81461049957600080fd5b8063386a5d7c14610393578063392e53cd146103b3578063486a7e6b146103cd578063547e2dec146103e3578063556f6e6b1461040357600080fd5b806332bed6ee116101f857806332bed6ee146102e05780633347e4d61461030057806335a3a96f14610320578063360bfd541461035d57806336568abe1461037357600080fd5b806301ffc9a714610235578063248a9ca31461026a578063252cf2d2146102a85780632f2ff15d146102be57600080fd5b3661023057005b600080fd5b34801561024157600080fd5b5061025561025036600461229b565b61075b565b60405190151581526020015b60405180910390f35b34801561027657600080fd5b5061029a6102853660046122c5565b60009081526020819052604090206001015490565b604051908152602001610261565b3480156102b457600080fd5b5061029a60075481565b3480156102ca57600080fd5b506102de6102d93660046122fa565b610792565b005b3480156102ec57600080fd5b506102de6102fb366004612403565b6107bc565b34801561030c57600080fd5b506102de61031b366004612438565b610902565b34801561032c57600080fd5b506001546103459061010090046001600160a01b031681565b6040516001600160a01b039091168152602001610261565b34801561036957600080fd5b5061029a60055481565b34801561037f57600080fd5b506102de61038e3660046122fa565b6109dd565b34801561039f57600080fd5b506102de6103ae366004612438565b610a5b565b3480156103bf57600080fd5b506001546102559060ff1681565b3480156103d957600080fd5b5061029a60065481565b3480156103ef57600080fd5b506102de6103fe3660046122c5565b610b42565b34801561040f57600080fd5b506102de61041e3660046122c5565b610ba2565b34801561042f57600080fd5b506102de61043e366004612453565b610c49565b34801561044f57600080fd5b506102de61045e366004612438565b610da2565b34801561046f57600080fd5b5061029a60045481565b34801561048557600080fd5b506102de6104943660046122c5565b610dfe565b3480156104a557600080fd5b50600f546010546011546012546104bc9392919084565b604080519485526020850193909352918301526060820152608001610261565b3480156104e857600080fd5b506103456104f73660046122c5565b610e91565b34801561050857600080fd5b506102de610517366004612438565b610ebb565b34801561052857600080fd5b50600b54600c54600d54600e546104bc9392919084565b34801561054b57600080fd5b5061025561055a3660046122fa565b610f5d565b34801561056b57600080fd5b506102de61057a36600461247d565b610f86565b34801561058b57600080fd5b5061029a600081565b3480156105a057600080fd5b5061029a7f5587a6603af31b5ced9f75f0d037b40683a035b85fa87fcdc3e12c7f36270f5181565b3480156105d457600080fd5b506102de6105e33660046122c5565b611127565b3480156105f457600080fd5b5061029a60095481565b34801561060a57600080fd5b506102de6106193660046124cb565b611169565b34801561062a57600080fd5b5061029a60035481565b34801561064057600080fd5b506103457f000000000000000000000000000000000000000000000000000000000000000081565b34801561067457600080fd5b5061029a7f9fd5b15ed55a8ac36199f77ed1b6f7161f794df8f6d341a7ea74c2f67cbe706381565b3480156106a857600080fd5b506103457f000000000000000000000000000000000000000000000000000000000000000081565b3480156106dc57600080fd5b506102de6106eb3660046122c5565b6112e7565b3480156106fc57600080fd5b506102de61070b3660046122fa565b611347565b34801561071c57600080fd5b506102de61136c565b34801561073157600080fd5b5061029a60085481565b34801561074757600080fd5b50600254610345906001600160a01b031681565b60006001600160e01b03198216637965db0b60e01b148061078c57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000828152602081905260409020600101546107ad816113ed565b6107b783836113fa565b505050565b60006107c7816113ed565b8160018151116107f25760405162461bcd60e51b81526004016107e990612507565b60405180910390fd5b60005b81518110156108595761082a8282815181106108135761081361254e565b60200260200101516001600160a01b03163b151590565b610847576040516357a4a13960e01b81526004016107e990612564565b80610851816125b1565b9150506107f5565b50825161086d90600a906020860190612221565b506108be836001855161088091906125ca565b815181106108905761089061254e565b60200260200101517f000000000000000000000000000000000000000000000000000000000000000061147e565b42836040516108cd91906125dd565b604051908190038120907f4d8980ffc301646731818c846e08e8d8b164c7ca942d2b9268ede3f0190cd89290600090a3505050565b600061090d816113ed565b6001600160a01b0382163b610935576040516357a4a13960e01b81526004016107e990612564565b6002546001600160a01b039081169083160361098f5760405163dfd4246160e01b8152602060048201526018602482015277139bc81b995dc81859191c995cdcc81cdc1958da599a595960421b60448201526064016107e9565b600280546001600160a01b0319166001600160a01b0384169081179091556040514291907fa075678b311aecdee8c20bf597250f938f787c09393aab6c26b67f46c5aba66590600090a35050565b6001600160a01b0381163314610a4d5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084016107e9565b610a57828261151f565b5050565b6000610a66816113ed565b6001600160a01b038216610a8d5760405163eac0d38960e01b81526004016107e99061261c565b6001546001600160a01b03610100909104811690831603610aec5760405163dfd4246160e01b8152602060048201526018602482015277139bc81b995dc81859191c995cdcc81cdc1958da599a595960421b60448201526064016107e9565b60018054610100600160a81b0319166101006001600160a01b038516908102919091179091556040514291907f16aa0ef87f0c1b1ce1ab077f18a9eb132172a24b565d344e3e7bd0c48069393190600090a35050565b7f9fd5b15ed55a8ac36199f77ed1b6f7161f794df8f6d341a7ea74c2f67cbe7063610b6c816113ed565b60408051608081018252600b548152600c546020820152600d5491810191909152600e546060820152610a579083906001611584565b6000610bad816113ed565b42821015610c0a576040516301b9a9ef60e61b815260206004820152602360248201527f46696e69736820706572696f642063616e6e6f7420626520696e207468652070604482015262185cdd60ea1b60648201526084016107e9565b600882905560405182815242907f9b49ecb356d36ff6a353fb45eed7f905f4abb001bad05c2c685260aaba291460906020015b60405180910390a25050565b6000610c54816113ed565b6001600160a01b038316610c7b5760405163eac0d38960e01b81526004016107e99061261c565b81600003610cbe576040516303b3e63560e41b815260206004820152600f60248201526e043616e6e6f7420726573637565203608c1b60448201526064016107e9565b6000836001600160a01b03168360405160006040518083038185875af1925050503d8060008114610d0b576040519150601f19603f3d011682016040523d82523d6000602084013e610d10565b606091505b5050905080610d58576040516312dfddb360e01b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b60448201526064016107e9565b42846001600160a01b03167f1ac265997833c020ed8364500d4e3d68edde9184437e973202459e23facdb52a85604051610d9491815260200190565b60405180910390a350505050565b6000610dad816113ed565b6001600160a01b038216610dd45760405163eac0d38960e01b81526004016107e99061261c565b610a57827f000000000000000000000000000000000000000000000000000000000000000061147e565b6000610e09816113ed565b81600003610e5a576040516303b3e63560e41b815260206004820152601960248201527f4475726174696f6e2063616e6e6f742074686174207a65726f0000000000000060448201526064016107e9565b600982905560405182815242907fd558521a7302c12bbeaedef84509c48a6ef6789b2fe653d08675042a90a5df6990602001610c3d565b600a8181548110610ea157600080fd5b6000918252602090912001546001600160a01b0316905081565b7f5587a6603af31b5ced9f75f0d037b40683a035b85fa87fcdc3e12c7f36270f51610ee5816113ed565b6001600160a01b038216610f0c5760405163eac0d38960e01b81526004016107e99061261c565b610f1760003361151f565b610f226000836113fa565b6040516001600160a01b038316815242907f6006ca690567a999c39d37af5488a81a1a615b7714e78aea3eee8ae232ff1fae90602001610c3d565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6000610f91816113ed565b60015460ff1615610fdb576040516329d8581f60e11b8152602060048201526013602482015272105b1c9958591e481a5b9a5d1a585b1a5e9959606a1b60448201526064016107e9565b816001815111610ffd5760405162461bcd60e51b81526004016107e990612507565b60005b815181101561104d5761101e8282815181106108135761081361254e565b61103b576040516357a4a13960e01b81526004016107e990612564565b80611045816125b1565b915050611000565b506001600160a01b0384163b611076576040516357a4a13960e01b81526004016107e990612564565b600280546001600160a01b0319166001600160a01b03861617905582516110a490600a906020860190612221565b506009546110b29042612642565b600855600a805461111591906110ca906001906125ca565b815481106110da576110da61254e565b6000918252602090912001546001600160a01b03167f000000000000000000000000000000000000000000000000000000000000000061147e565b50506001805460ff1916811790555050565b6000611132816113ed565b600782905560405182815242907f21227b306f688a950b5bc00d0f6a187e8321d704feeca8569e6700d13955644190602001610c3d565b6000611174816113ed565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b03160361120157604051631a604dd160e01b815260206004820152602260248201527f53656e64696e6720496e51756265746120746f6b656e206e6f7420616c6c6f77604482015261195960f21b60648201526084016107e9565b6001600160a01b038216158061121e57506001600160a01b038416155b1561123c5760405163eac0d38960e01b81526004016107e99061261c565b8260000361127f576040516303b3e63560e41b815260206004820152600f60248201526e043616e6e6f7420726573637565203608c1b60448201526064016107e9565b6112936001600160a01b03851683856116c5565b42826001600160a01b0316856001600160a01b03167fb655de23853afe880357a3071d62bac8419cfb3213c08056b6620a47d87a769f866040516112d991815260200190565b60405180910390a450505050565b7f9fd5b15ed55a8ac36199f77ed1b6f7161f794df8f6d341a7ea74c2f67cbe7063611311816113ed565b60408051608081018252600f5481526010546020820152601154918101919091526012546060820152610a579083906000611584565b600082815260208190526040902060010154611362816113ed565b6107b7838361151f565b60085442106113eb57600080600080611383611728565b9350935093509350600954426113999190612642565b60085560408051858152602081018390529081018490526060810183905242907fc1f8b8d90e45c77e153de2bfd33f090d5cd5c4986a3481ab4698c5f2e13741549060800160405180910390a2505050505b565b6113f781336119c8565b50565b6114048282610f5d565b610a57576000828152602081815260408083206001600160a01b03851684529091529020805460ff1916600117905561143a3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b604051636eb1769f60e11b81523060048201526001600160a01b0382811660248301526000919084169063dd62ed3e90604401602060405180830381865afa1580156114ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f29190612655565b90506000198110156107b7576107b78261150e836000196125ca565b6001600160a01b0386169190611a2c565b6115298282610f5d565b15610a57576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b8151683635c9adc5dea000009061159b908561266e565b6115a59190612685565b600360008282546115b69190612642565b90915550506020820151683635c9adc5dea00000906115d5908561266e565b6115df9190612685565b600460008282546115f09190612642565b90915550506040820151683635c9adc5dea000009061160f908561266e565b6116199190612685565b6005600082825461162a9190612642565b90915550506060820151683635c9adc5dea0000090611649908561266e565b6116539190612685565b600660008282546116649190612642565b90915550506003546004546005546006546040805194855260208501939093529183015260608201524290821515907fb66961135fa956a9e503d05a7c18f8c95cc0be77be330a11f193dd161b4f5ac99060800160405180910390a3505050565b6040516001600160a01b0383166024820152604481018290526107b790849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611ae4565b600080600080600060035411156118495760025460035460405163a9059cbb60e01b81526001600160a01b03928316600482015260248101919091527f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af11580156117b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d591906126a7565b50600254600354604051633c6b16ab60e01b81526001600160a01b0390921691633c6b16ab9161180b9160040190815260200190565b600060405180830381600087803b15801561182557600080fd5b505af1158015611839573d6000803e3d6000fd5b5050600380546000909155955050505b600554156118fe5760015460055460405163a9059cbb60e01b81526101009092046001600160a01b03908116600484015260248301919091527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af11580156118cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f191906126a7565b5060058054600090915592505b6006541561199057600654604051630852cd8d60e31b815260048101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906342966c6890602401600060405180830381600087803b15801561196c57600080fd5b505af1158015611980573d6000803e3d6000fd5b5050600680546000909155935050505b60075460045411156119c25760006119a9600454611bb6565b9050806004546119b991906125ca565b60049190915590505b90919293565b6119d28282610f5d565b610a57576119ea816001600160a01b03166014611efd565b6119f5836020611efd565b604051602001611a069291906126ed565b60408051601f198184030181529082905262461bcd60e51b82526107e991600401612762565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015611a7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa19190612655565b611aab9190612642565b6040516001600160a01b038516602482015260448101829052909150611ade90859063095ea7b360e01b906064016116f1565b50505050565b6000611b39826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166120a09092919063ffffffff16565b8051909150156107b75780806020019051810190611b5791906126a7565b6107b75760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016107e9565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ce404b236040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611c1357600080fd5b505af1158015611c27573d6000803e3d6000fd5b5084925060009150506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166338ed1739611c6a600285612685565b6000600a30426040518663ffffffff1660e01b8152600401611c90959493929190612795565b6000604051808303816000875af1158015611caf573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611cd7919081019061280b565b905080600081518110611cec57611cec61254e565b602002602001015182611cff91906125ca565b915060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e8e33700600a600081548110611d4657611d4661254e565b600091825260209091200154600a80546001600160a01b0390921691611d6e906001906125ca565b81548110611d7e57611d7e61254e565b600091825260208220015486516001600160a01b03909116918791611da557611da561254e565b60200260200101518660018851611dbc91906125ca565b81518110611dcc57611dcc61254e565b60209081029190910101516040516001600160e01b031960e087901b1681526001600160a01b0394851660048201529390921660248401526044830152606482015260016084820181905260a48201523060c48201524260e4820152610104016060604051808303816000875af1158015611e4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6f9190612891565b505090508083611e7f91906125ca565b92507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663368f5bd56040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611edc57600080fd5b505af1158015611ef0573d6000803e3d6000fd5b5094979650505050505050565b60606000611f0c83600261266e565b611f17906002612642565b67ffffffffffffffff811115611f2f57611f2f612326565b6040519080825280601f01601f191660200182016040528015611f59576020820181803683370190505b509050600360fc1b81600081518110611f7457611f7461254e565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110611fa357611fa361254e565b60200101906001600160f81b031916908160001a9053506000611fc784600261266e565b611fd2906001612642565b90505b600181111561204a576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106120065761200661254e565b1a60f81b82828151811061201c5761201c61254e565b60200101906001600160f81b031916908160001a90535060049490941c93612043816128bf565b9050611fd5565b5083156120995760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016107e9565b9392505050565b60606120af84846000856120b7565b949350505050565b6060824710156121185760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016107e9565b6001600160a01b0385163b61216f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107e9565b600080866001600160a01b0316858760405161218b91906128d6565b60006040518083038185875af1925050503d80600081146121c8576040519150601f19603f3d011682016040523d82523d6000602084013e6121cd565b606091505b50915091506121dd8282866121e8565b979650505050505050565b606083156121f7575081612099565b8251156122075782518084602001fd5b8160405162461bcd60e51b81526004016107e99190612762565b828054828255906000526020600020908101928215612276579160200282015b8281111561227657825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190612241565b50612282929150612286565b5090565b5b808211156122825760008155600101612287565b6000602082840312156122ad57600080fd5b81356001600160e01b03198116811461209957600080fd5b6000602082840312156122d757600080fd5b5035919050565b80356001600160a01b03811681146122f557600080fd5b919050565b6000806040838503121561230d57600080fd5b8235915061231d602084016122de565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561236557612365612326565b604052919050565b600067ffffffffffffffff82111561238757612387612326565b5060051b60200190565b600082601f8301126123a257600080fd5b813560206123b76123b28361236d565b61233c565b82815260059290921b840181019181810190868411156123d657600080fd5b8286015b848110156123f8576123eb816122de565b83529183019183016123da565b509695505050505050565b60006020828403121561241557600080fd5b813567ffffffffffffffff81111561242c57600080fd5b6120af84828501612391565b60006020828403121561244a57600080fd5b612099826122de565b6000806040838503121561246657600080fd5b61246f836122de565b946020939093013593505050565b6000806040838503121561249057600080fd5b612499836122de565b9150602083013567ffffffffffffffff8111156124b557600080fd5b6124c185828601612391565b9150509250929050565b6000806000606084860312156124e057600080fd5b6124e9846122de565b9250602084013591506124fe604085016122de565b90509250925092565b60208082526027908201527f50617468206d75737420636f6e7461696e206174206c656173742074776f20656040820152666c656d656e747360c81b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b60208082526019908201527f41646472657373206973206e6f74206120636f6e747261637400000000000000604082015260600190565b634e487b7160e01b600052601160045260246000fd5b6000600182016125c3576125c361259b565b5060010190565b8181038181111561078c5761078c61259b565b815160009082906020808601845b838110156126105781516001600160a01b0316855293820193908201906001016125eb565b50929695505050505050565b6020808252600c908201526b5a65726f206164647265737360a01b604082015260600190565b8082018082111561078c5761078c61259b565b60006020828403121561266757600080fd5b5051919050565b808202811582820484141761078c5761078c61259b565b6000826126a257634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156126b957600080fd5b8151801515811461209957600080fd5b60005b838110156126e45781810151838201526020016126cc565b50506000910152565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516127258160178501602088016126c9565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516127568160288401602088016126c9565b01602801949350505050565b60208152600082518060208401526127818160408501602087016126c9565b601f01601f19169190910160400192915050565b600060a082018783526020878185015260a0604085015281875480845260c0860191508860005282600020935060005b818110156127ea5784546001600160a01b0316835260019485019492840192016127c5565b50506001600160a01b03969096166060850152505050608001529392505050565b6000602080838503121561281e57600080fd5b825167ffffffffffffffff81111561283557600080fd5b8301601f8101851361284657600080fd5b80516128546123b28261236d565b81815260059190911b8201830190838101908783111561287357600080fd5b928401925b828410156121dd57835182529284019290840190612878565b6000806000606084860312156128a657600080fd5b8351925060208401519150604084015190509250925092565b6000816128ce576128ce61259b565b506000190190565b600082516128e88184602087016126c9565b919091019291505056fea2646970667358221220246559110923a2b2fd24e92402acf32adfe7b2b0a1e84302b4df0a6c244ea33264736f6c6343000813003350657263656e74732073756d2073686f756c6420657175616c2070726563697300000000000000000000000055e7fe3bc831117ba5a132df147351aabb372393000000000000000000000000000000000000000000000015af1d78b58c40000000000000000000000000000000000000000000000000000ad78ebc5ac620000000000000000000000000000000000000000000000000000ad78ebc5ac620000000000000000000000000000000000000000000000000000ad78ebc5ac620000000000000000000000000000000000000000000000000001b1ae4d6e2ef5000000000000000000000000000000000000000000000000000056bc75e2d6310000000000000000000000000000000000000000000000000000ad78ebc5ac620000000000000000000000000000000000000000000000000000ad78ebc5ac6200000000000000000000000000000e77473c4973ad064e04c80959dd56dd4886efca90000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d00000000000000000000000055e7fe3bc831117ba5a132df147351aabb3723930000000000000000000000000000000000000000000000004563918244f40000

Deployed Bytecode

0x6080604052600436106102295760003560e01c8063836fcaf211610123578063b51609b4116100ab578063cde38c971161006f578063cde38c97146106d0578063d547741f146106f0578063d95de65614610710578063ebe2b12b14610725578063ee99205c1461073b57600080fd5b8063b51609b4146105fe578063c13d995c1461061e578063c31c9c0714610634578063c41b89ad14610668578063cc30e1621461069c57600080fd5b8063946d9204116100f2578063946d92041461055f578063a217fddf1461057f578063a60cc34414610594578063aa764ab3146105c8578063b470aade146105e857600080fd5b8063836fcaf2146104dc578063880cdc31146104fc578063892c60991461051c57806391d148541461053f57600080fd5b8063386a5d7c116101b15780635705ae43116101755780635705ae43146104235780636bb23bcb1461044357806370baed4314610463578063717cee7d1461047957806373f1edb81461049957600080fd5b8063386a5d7c14610393578063392e53cd146103b3578063486a7e6b146103cd578063547e2dec146103e3578063556f6e6b1461040357600080fd5b806332bed6ee116101f857806332bed6ee146102e05780633347e4d61461030057806335a3a96f14610320578063360bfd541461035d57806336568abe1461037357600080fd5b806301ffc9a714610235578063248a9ca31461026a578063252cf2d2146102a85780632f2ff15d146102be57600080fd5b3661023057005b600080fd5b34801561024157600080fd5b5061025561025036600461229b565b61075b565b60405190151581526020015b60405180910390f35b34801561027657600080fd5b5061029a6102853660046122c5565b60009081526020819052604090206001015490565b604051908152602001610261565b3480156102b457600080fd5b5061029a60075481565b3480156102ca57600080fd5b506102de6102d93660046122fa565b610792565b005b3480156102ec57600080fd5b506102de6102fb366004612403565b6107bc565b34801561030c57600080fd5b506102de61031b366004612438565b610902565b34801561032c57600080fd5b506001546103459061010090046001600160a01b031681565b6040516001600160a01b039091168152602001610261565b34801561036957600080fd5b5061029a60055481565b34801561037f57600080fd5b506102de61038e3660046122fa565b6109dd565b34801561039f57600080fd5b506102de6103ae366004612438565b610a5b565b3480156103bf57600080fd5b506001546102559060ff1681565b3480156103d957600080fd5b5061029a60065481565b3480156103ef57600080fd5b506102de6103fe3660046122c5565b610b42565b34801561040f57600080fd5b506102de61041e3660046122c5565b610ba2565b34801561042f57600080fd5b506102de61043e366004612453565b610c49565b34801561044f57600080fd5b506102de61045e366004612438565b610da2565b34801561046f57600080fd5b5061029a60045481565b34801561048557600080fd5b506102de6104943660046122c5565b610dfe565b3480156104a557600080fd5b50600f546010546011546012546104bc9392919084565b604080519485526020850193909352918301526060820152608001610261565b3480156104e857600080fd5b506103456104f73660046122c5565b610e91565b34801561050857600080fd5b506102de610517366004612438565b610ebb565b34801561052857600080fd5b50600b54600c54600d54600e546104bc9392919084565b34801561054b57600080fd5b5061025561055a3660046122fa565b610f5d565b34801561056b57600080fd5b506102de61057a36600461247d565b610f86565b34801561058b57600080fd5b5061029a600081565b3480156105a057600080fd5b5061029a7f5587a6603af31b5ced9f75f0d037b40683a035b85fa87fcdc3e12c7f36270f5181565b3480156105d457600080fd5b506102de6105e33660046122c5565b611127565b3480156105f457600080fd5b5061029a60095481565b34801561060a57600080fd5b506102de6106193660046124cb565b611169565b34801561062a57600080fd5b5061029a60035481565b34801561064057600080fd5b506103457f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d81565b34801561067457600080fd5b5061029a7f9fd5b15ed55a8ac36199f77ed1b6f7161f794df8f6d341a7ea74c2f67cbe706381565b3480156106a857600080fd5b506103457f000000000000000000000000e77473c4973ad064e04c80959dd56dd4886efca981565b3480156106dc57600080fd5b506102de6106eb3660046122c5565b6112e7565b3480156106fc57600080fd5b506102de61070b3660046122fa565b611347565b34801561071c57600080fd5b506102de61136c565b34801561073157600080fd5b5061029a60085481565b34801561074757600080fd5b50600254610345906001600160a01b031681565b60006001600160e01b03198216637965db0b60e01b148061078c57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000828152602081905260409020600101546107ad816113ed565b6107b783836113fa565b505050565b60006107c7816113ed565b8160018151116107f25760405162461bcd60e51b81526004016107e990612507565b60405180910390fd5b60005b81518110156108595761082a8282815181106108135761081361254e565b60200260200101516001600160a01b03163b151590565b610847576040516357a4a13960e01b81526004016107e990612564565b80610851816125b1565b9150506107f5565b50825161086d90600a906020860190612221565b506108be836001855161088091906125ca565b815181106108905761089061254e565b60200260200101517f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d61147e565b42836040516108cd91906125dd565b604051908190038120907f4d8980ffc301646731818c846e08e8d8b164c7ca942d2b9268ede3f0190cd89290600090a3505050565b600061090d816113ed565b6001600160a01b0382163b610935576040516357a4a13960e01b81526004016107e990612564565b6002546001600160a01b039081169083160361098f5760405163dfd4246160e01b8152602060048201526018602482015277139bc81b995dc81859191c995cdcc81cdc1958da599a595960421b60448201526064016107e9565b600280546001600160a01b0319166001600160a01b0384169081179091556040514291907fa075678b311aecdee8c20bf597250f938f787c09393aab6c26b67f46c5aba66590600090a35050565b6001600160a01b0381163314610a4d5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084016107e9565b610a57828261151f565b5050565b6000610a66816113ed565b6001600160a01b038216610a8d5760405163eac0d38960e01b81526004016107e99061261c565b6001546001600160a01b03610100909104811690831603610aec5760405163dfd4246160e01b8152602060048201526018602482015277139bc81b995dc81859191c995cdcc81cdc1958da599a595960421b60448201526064016107e9565b60018054610100600160a81b0319166101006001600160a01b038516908102919091179091556040514291907f16aa0ef87f0c1b1ce1ab077f18a9eb132172a24b565d344e3e7bd0c48069393190600090a35050565b7f9fd5b15ed55a8ac36199f77ed1b6f7161f794df8f6d341a7ea74c2f67cbe7063610b6c816113ed565b60408051608081018252600b548152600c546020820152600d5491810191909152600e546060820152610a579083906001611584565b6000610bad816113ed565b42821015610c0a576040516301b9a9ef60e61b815260206004820152602360248201527f46696e69736820706572696f642063616e6e6f7420626520696e207468652070604482015262185cdd60ea1b60648201526084016107e9565b600882905560405182815242907f9b49ecb356d36ff6a353fb45eed7f905f4abb001bad05c2c685260aaba291460906020015b60405180910390a25050565b6000610c54816113ed565b6001600160a01b038316610c7b5760405163eac0d38960e01b81526004016107e99061261c565b81600003610cbe576040516303b3e63560e41b815260206004820152600f60248201526e043616e6e6f7420726573637565203608c1b60448201526064016107e9565b6000836001600160a01b03168360405160006040518083038185875af1925050503d8060008114610d0b576040519150601f19603f3d011682016040523d82523d6000602084013e610d10565b606091505b5050905080610d58576040516312dfddb360e01b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b60448201526064016107e9565b42846001600160a01b03167f1ac265997833c020ed8364500d4e3d68edde9184437e973202459e23facdb52a85604051610d9491815260200190565b60405180910390a350505050565b6000610dad816113ed565b6001600160a01b038216610dd45760405163eac0d38960e01b81526004016107e99061261c565b610a57827f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d61147e565b6000610e09816113ed565b81600003610e5a576040516303b3e63560e41b815260206004820152601960248201527f4475726174696f6e2063616e6e6f742074686174207a65726f0000000000000060448201526064016107e9565b600982905560405182815242907fd558521a7302c12bbeaedef84509c48a6ef6789b2fe653d08675042a90a5df6990602001610c3d565b600a8181548110610ea157600080fd5b6000918252602090912001546001600160a01b0316905081565b7f5587a6603af31b5ced9f75f0d037b40683a035b85fa87fcdc3e12c7f36270f51610ee5816113ed565b6001600160a01b038216610f0c5760405163eac0d38960e01b81526004016107e99061261c565b610f1760003361151f565b610f226000836113fa565b6040516001600160a01b038316815242907f6006ca690567a999c39d37af5488a81a1a615b7714e78aea3eee8ae232ff1fae90602001610c3d565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6000610f91816113ed565b60015460ff1615610fdb576040516329d8581f60e11b8152602060048201526013602482015272105b1c9958591e481a5b9a5d1a585b1a5e9959606a1b60448201526064016107e9565b816001815111610ffd5760405162461bcd60e51b81526004016107e990612507565b60005b815181101561104d5761101e8282815181106108135761081361254e565b61103b576040516357a4a13960e01b81526004016107e990612564565b80611045816125b1565b915050611000565b506001600160a01b0384163b611076576040516357a4a13960e01b81526004016107e990612564565b600280546001600160a01b0319166001600160a01b03861617905582516110a490600a906020860190612221565b506009546110b29042612642565b600855600a805461111591906110ca906001906125ca565b815481106110da576110da61254e565b6000918252602090912001546001600160a01b03167f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d61147e565b50506001805460ff1916811790555050565b6000611132816113ed565b600782905560405182815242907f21227b306f688a950b5bc00d0f6a187e8321d704feeca8569e6700d13955644190602001610c3d565b6000611174816113ed565b7f000000000000000000000000e77473c4973ad064e04c80959dd56dd4886efca96001600160a01b0316846001600160a01b03160361120157604051631a604dd160e01b815260206004820152602260248201527f53656e64696e6720496e51756265746120746f6b656e206e6f7420616c6c6f77604482015261195960f21b60648201526084016107e9565b6001600160a01b038216158061121e57506001600160a01b038416155b1561123c5760405163eac0d38960e01b81526004016107e99061261c565b8260000361127f576040516303b3e63560e41b815260206004820152600f60248201526e043616e6e6f7420726573637565203608c1b60448201526064016107e9565b6112936001600160a01b03851683856116c5565b42826001600160a01b0316856001600160a01b03167fb655de23853afe880357a3071d62bac8419cfb3213c08056b6620a47d87a769f866040516112d991815260200190565b60405180910390a450505050565b7f9fd5b15ed55a8ac36199f77ed1b6f7161f794df8f6d341a7ea74c2f67cbe7063611311816113ed565b60408051608081018252600f5481526010546020820152601154918101919091526012546060820152610a579083906000611584565b600082815260208190526040902060010154611362816113ed565b6107b7838361151f565b60085442106113eb57600080600080611383611728565b9350935093509350600954426113999190612642565b60085560408051858152602081018390529081018490526060810183905242907fc1f8b8d90e45c77e153de2bfd33f090d5cd5c4986a3481ab4698c5f2e13741549060800160405180910390a2505050505b565b6113f781336119c8565b50565b6114048282610f5d565b610a57576000828152602081815260408083206001600160a01b03851684529091529020805460ff1916600117905561143a3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b604051636eb1769f60e11b81523060048201526001600160a01b0382811660248301526000919084169063dd62ed3e90604401602060405180830381865afa1580156114ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f29190612655565b90506000198110156107b7576107b78261150e836000196125ca565b6001600160a01b0386169190611a2c565b6115298282610f5d565b15610a57576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b8151683635c9adc5dea000009061159b908561266e565b6115a59190612685565b600360008282546115b69190612642565b90915550506020820151683635c9adc5dea00000906115d5908561266e565b6115df9190612685565b600460008282546115f09190612642565b90915550506040820151683635c9adc5dea000009061160f908561266e565b6116199190612685565b6005600082825461162a9190612642565b90915550506060820151683635c9adc5dea0000090611649908561266e565b6116539190612685565b600660008282546116649190612642565b90915550506003546004546005546006546040805194855260208501939093529183015260608201524290821515907fb66961135fa956a9e503d05a7c18f8c95cc0be77be330a11f193dd161b4f5ac99060800160405180910390a3505050565b6040516001600160a01b0383166024820152604481018290526107b790849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611ae4565b600080600080600060035411156118495760025460035460405163a9059cbb60e01b81526001600160a01b03928316600482015260248101919091527f000000000000000000000000e77473c4973ad064e04c80959dd56dd4886efca99091169063a9059cbb906044016020604051808303816000875af11580156117b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d591906126a7565b50600254600354604051633c6b16ab60e01b81526001600160a01b0390921691633c6b16ab9161180b9160040190815260200190565b600060405180830381600087803b15801561182557600080fd5b505af1158015611839573d6000803e3d6000fd5b5050600380546000909155955050505b600554156118fe5760015460055460405163a9059cbb60e01b81526101009092046001600160a01b03908116600484015260248301919091527f000000000000000000000000e77473c4973ad064e04c80959dd56dd4886efca9169063a9059cbb906044016020604051808303816000875af11580156118cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f191906126a7565b5060058054600090915592505b6006541561199057600654604051630852cd8d60e31b815260048101919091527f000000000000000000000000e77473c4973ad064e04c80959dd56dd4886efca96001600160a01b0316906342966c6890602401600060405180830381600087803b15801561196c57600080fd5b505af1158015611980573d6000803e3d6000fd5b5050600680546000909155935050505b60075460045411156119c25760006119a9600454611bb6565b9050806004546119b991906125ca565b60049190915590505b90919293565b6119d28282610f5d565b610a57576119ea816001600160a01b03166014611efd565b6119f5836020611efd565b604051602001611a069291906126ed565b60408051601f198184030181529082905262461bcd60e51b82526107e991600401612762565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015611a7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa19190612655565b611aab9190612642565b6040516001600160a01b038516602482015260448101829052909150611ade90859063095ea7b360e01b906064016116f1565b50505050565b6000611b39826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166120a09092919063ffffffff16565b8051909150156107b75780806020019051810190611b5791906126a7565b6107b75760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016107e9565b60007f000000000000000000000000e77473c4973ad064e04c80959dd56dd4886efca96001600160a01b031663ce404b236040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611c1357600080fd5b505af1158015611c27573d6000803e3d6000fd5b5084925060009150506001600160a01b037f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d166338ed1739611c6a600285612685565b6000600a30426040518663ffffffff1660e01b8152600401611c90959493929190612795565b6000604051808303816000875af1158015611caf573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611cd7919081019061280b565b905080600081518110611cec57611cec61254e565b602002602001015182611cff91906125ca565b915060007f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b031663e8e33700600a600081548110611d4657611d4661254e565b600091825260209091200154600a80546001600160a01b0390921691611d6e906001906125ca565b81548110611d7e57611d7e61254e565b600091825260208220015486516001600160a01b03909116918791611da557611da561254e565b60200260200101518660018851611dbc91906125ca565b81518110611dcc57611dcc61254e565b60209081029190910101516040516001600160e01b031960e087901b1681526001600160a01b0394851660048201529390921660248401526044830152606482015260016084820181905260a48201523060c48201524260e4820152610104016060604051808303816000875af1158015611e4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6f9190612891565b505090508083611e7f91906125ca565b92507f000000000000000000000000e77473c4973ad064e04c80959dd56dd4886efca96001600160a01b031663368f5bd56040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611edc57600080fd5b505af1158015611ef0573d6000803e3d6000fd5b5094979650505050505050565b60606000611f0c83600261266e565b611f17906002612642565b67ffffffffffffffff811115611f2f57611f2f612326565b6040519080825280601f01601f191660200182016040528015611f59576020820181803683370190505b509050600360fc1b81600081518110611f7457611f7461254e565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110611fa357611fa361254e565b60200101906001600160f81b031916908160001a9053506000611fc784600261266e565b611fd2906001612642565b90505b600181111561204a576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106120065761200661254e565b1a60f81b82828151811061201c5761201c61254e565b60200101906001600160f81b031916908160001a90535060049490941c93612043816128bf565b9050611fd5565b5083156120995760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016107e9565b9392505050565b60606120af84846000856120b7565b949350505050565b6060824710156121185760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016107e9565b6001600160a01b0385163b61216f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107e9565b600080866001600160a01b0316858760405161218b91906128d6565b60006040518083038185875af1925050503d80600081146121c8576040519150601f19603f3d011682016040523d82523d6000602084013e6121cd565b606091505b50915091506121dd8282866121e8565b979650505050505050565b606083156121f7575081612099565b8251156122075782518084602001fd5b8160405162461bcd60e51b81526004016107e99190612762565b828054828255906000526020600020908101928215612276579160200282015b8281111561227657825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190612241565b50612282929150612286565b5090565b5b808211156122825760008155600101612287565b6000602082840312156122ad57600080fd5b81356001600160e01b03198116811461209957600080fd5b6000602082840312156122d757600080fd5b5035919050565b80356001600160a01b03811681146122f557600080fd5b919050565b6000806040838503121561230d57600080fd5b8235915061231d602084016122de565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561236557612365612326565b604052919050565b600067ffffffffffffffff82111561238757612387612326565b5060051b60200190565b600082601f8301126123a257600080fd5b813560206123b76123b28361236d565b61233c565b82815260059290921b840181019181810190868411156123d657600080fd5b8286015b848110156123f8576123eb816122de565b83529183019183016123da565b509695505050505050565b60006020828403121561241557600080fd5b813567ffffffffffffffff81111561242c57600080fd5b6120af84828501612391565b60006020828403121561244a57600080fd5b612099826122de565b6000806040838503121561246657600080fd5b61246f836122de565b946020939093013593505050565b6000806040838503121561249057600080fd5b612499836122de565b9150602083013567ffffffffffffffff8111156124b557600080fd5b6124c185828601612391565b9150509250929050565b6000806000606084860312156124e057600080fd5b6124e9846122de565b9250602084013591506124fe604085016122de565b90509250925092565b60208082526027908201527f50617468206d75737420636f6e7461696e206174206c656173742074776f20656040820152666c656d656e747360c81b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b60208082526019908201527f41646472657373206973206e6f74206120636f6e747261637400000000000000604082015260600190565b634e487b7160e01b600052601160045260246000fd5b6000600182016125c3576125c361259b565b5060010190565b8181038181111561078c5761078c61259b565b815160009082906020808601845b838110156126105781516001600160a01b0316855293820193908201906001016125eb565b50929695505050505050565b6020808252600c908201526b5a65726f206164647265737360a01b604082015260600190565b8082018082111561078c5761078c61259b565b60006020828403121561266757600080fd5b5051919050565b808202811582820484141761078c5761078c61259b565b6000826126a257634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156126b957600080fd5b8151801515811461209957600080fd5b60005b838110156126e45781810151838201526020016126cc565b50506000910152565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516127258160178501602088016126c9565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516127568160288401602088016126c9565b01602801949350505050565b60208152600082518060208401526127818160408501602087016126c9565b601f01601f19169190910160400192915050565b600060a082018783526020878185015260a0604085015281875480845260c0860191508860005282600020935060005b818110156127ea5784546001600160a01b0316835260019485019492840192016127c5565b50506001600160a01b03969096166060850152505050608001529392505050565b6000602080838503121561281e57600080fd5b825167ffffffffffffffff81111561283557600080fd5b8301601f8101851361284657600080fd5b80516128546123b28261236d565b81815260059190911b8201830190838101908783111561287357600080fd5b928401925b828410156121dd57835182529284019290840190612878565b6000806000606084860312156128a657600080fd5b8351925060208401519150604084015190509250925092565b6000816128ce576128ce61259b565b506000190190565b600082516128e88184602087016126c9565b919091019291505056fea2646970667358221220246559110923a2b2fd24e92402acf32adfe7b2b0a1e84302b4df0a6c244ea33264736f6c63430008130033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000055e7fe3bc831117ba5a132df147351aabb372393000000000000000000000000000000000000000000000015af1d78b58c40000000000000000000000000000000000000000000000000000ad78ebc5ac620000000000000000000000000000000000000000000000000000ad78ebc5ac620000000000000000000000000000000000000000000000000000ad78ebc5ac620000000000000000000000000000000000000000000000000001b1ae4d6e2ef5000000000000000000000000000000000000000000000000000056bc75e2d6310000000000000000000000000000000000000000000000000000ad78ebc5ac620000000000000000000000000000000000000000000000000000ad78ebc5ac6200000000000000000000000000000e77473c4973ad064e04c80959dd56dd4886efca90000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d00000000000000000000000055e7fe3bc831117ba5a132df147351aabb3723930000000000000000000000000000000000000000000000004563918244f40000

-----Decoded View---------------
Arg [0] : _owner (address): 0x55e7Fe3bc831117BA5a132DF147351aabb372393
Arg [1] : _buyFeeAllocations (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [2] : _sellFeeAccocations (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [3] : _inqubetaToken (address): 0xE77473C4973ad064E04C80959dd56DD4886efcA9
Arg [4] : _uniRouter (address): 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D
Arg [5] : _marketingRecipient (address): 0x55e7Fe3bc831117BA5a132DF147351aabb372393
Arg [6] : _minLiquidity (uint256): 5000000000000000000

-----Encoded View---------------
13 Constructor Arguments found :
Arg [0] : 00000000000000000000000055e7fe3bc831117ba5a132df147351aabb372393
Arg [1] : 000000000000000000000000000000000000000000000015af1d78b58c400000
Arg [2] : 00000000000000000000000000000000000000000000000ad78ebc5ac6200000
Arg [3] : 00000000000000000000000000000000000000000000000ad78ebc5ac6200000
Arg [4] : 00000000000000000000000000000000000000000000000ad78ebc5ac6200000
Arg [5] : 00000000000000000000000000000000000000000000001b1ae4d6e2ef500000
Arg [6] : 0000000000000000000000000000000000000000000000056bc75e2d63100000
Arg [7] : 00000000000000000000000000000000000000000000000ad78ebc5ac6200000
Arg [8] : 00000000000000000000000000000000000000000000000ad78ebc5ac6200000
Arg [9] : 000000000000000000000000e77473c4973ad064e04c80959dd56dd4886efca9
Arg [10] : 0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d
Arg [11] : 00000000000000000000000055e7fe3bc831117ba5a132df147351aabb372393
Arg [12] : 0000000000000000000000000000000000000000000000004563918244f40000


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.