false
true
0

Contract Address Details

0xd5A96B6ACa28302CF1B0F860673851705D25667e

Token
Janus (JNS)
Creator
0x1217a0–7af401 at 0x5a61d2–84016e
Balance
1,824.360573108080662081 PLS ( )
Tokens
Fetching tokens...
Transactions
1,344 Transactions
Transfers
0 Transfers
Gas Used
0
Last Balance Update
25964963
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
Janus




Optimization enabled
true
Compiler version
v0.8.20+commit.a1b79de6




Optimization runs
20000
EVM Version
paris




Verified at
2024-05-02T19:38:09.415846Z

Constructor Arguments

0x000000000000000000000000aadb63c2cdb9b07761adc41b52436aee8296cebb000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000165c3410fc91ef562c50559f7d2289febed552d9000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000012c0000000000000000000000000000000000000000000000000000000000000ce40000000000000000000000000000000000000000000000000000000000000ce4000000000000000000000000000000000000000000000000000000000000094c00000000000000000000000000000000000000000000000000000000000003fc00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000e0730cef84fb49ff8d8d514f0ffe1124f999f1b00000000000000000000000061d857bd9554765d73058c93f9b2fa10c7c268da
              

contracts/Janus.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "./TaxableToken.sol";

/** @title Janus - ERC20 Token with DeFi functionality and transaction fees applied to DEX interactions
 * @dev This contract extends OpenZeppelin's ERC20 and Ownable contracts.
 *      It includes transaction fee mechanisms and the ability to mint new tokens.
 */
contract Janus is ERC20, Ownable, TaxableToken {
    /// @notice The Investment Pool percentage enforceable, also expressed in basis points.
    uint256 public investmentPoolPercentage = 7000;

    /// @notice Total PLS tokens collected as fees and not yet redistributed.
    uint256 public undistributedPls;

    /// @notice The HLX token address which is involved in mint transactions as fees.
    address public hlxAddress;

    /// @notice Conversion rate from payment in native currency (like ETH) to HLX token fees.
    uint256 public plsRate;

    /// @notice Custom error to indicate insufficient payment in PLS for the operations required.
    error insufficientPLS();

    /**  @notice Constructs the Janus ERC20 Token
     * @param _hlxAddress The address of the HLX token used for fee mechanisms.
     * @param _plsRate The rate used to convert payment in native currency to HLX token fees.
     */
    constructor(
        address _hlxAddress,
        uint256 _plsRate,
        address swapRouter_,
        FeeConfiguration memory feeConfiguration_,
        uint256 numTokensToSwap,
        address _investmentPoolAddress,
        address _teamAddress
    )
        ERC20("Janus", "JNS")
        TaxableToken(
            true,
            numTokensToSwap * 10 ** decimals(),
            swapRouter_,
            feeConfiguration_,
            _investmentPoolAddress,
            _teamAddress
        )
    {
        hlxAddress = _hlxAddress;
        plsRate = _plsRate;
        _mint(msg.sender, 420000000000 * 10 ** decimals());
    }

    /**  @notice Mints new tokens to a specified address after collecting protocol fees in HLX tokens.
     * @param to The address to receive the newly minted tokens.
     * @param amount The amount of tokens to mint.
     */
    function mint(address to, uint256 amount) public payable {
        _protocolFees(amount);
        _mint(to, amount);
        if (autoProcessFees) distributeFees();
    }

    /** @notice Sets the address of the HLX Token.
     * @param _hlxAddress The new Token address.
     */
    function setHLXAddress(address _hlxAddress) public onlyOwner {
        if (_hlxAddress == address(0)) revert Janus_ZeroAddress();
        hlxAddress = _hlxAddress;
    }

    /** @notice Sets the distribution percentages for the investment pool.
     * @param _percentage New percentage for the investment pool.
     */
    function setInvestmentPoolPercentage(uint256 _percentage) public onlyOwner {
        if (!(_percentage > 0 && _percentage <= 10000))
            revert Janus_InvalidValue();
        investmentPoolPercentage = _percentage;
    }

    /** @notice Updates the PLS rate for fee calculations.
     * @param _plsRate The new rate for converting payment in native currency to HLX token fees.
     */
    function setPLSRate(uint256 _plsRate) public onlyOwner {
        if (!(_plsRate > 0)) revert Janus_InvalidValue();
        plsRate = _plsRate;
    }

    /**
     * @dev process fees
     * only callable by `owner()`
     */
    function processFees(address pair) external override onlyOwner {
        _processFees(pair);
    }

    /**
     * @dev add/remove a LP
     * only callable by `owner()`
     */
    function setIsLpPool(
        address pairAddress,
        bool isLp
    ) external override onlyOwner {
        _setIsLpPool(pairAddress, isLp);
    }

    /**
     * @dev add LP Pool RouterAddress
     * only callable by `owner()`
     */
    function setLpPoolRouter(
        address routerAddress,
        address pairAddress
    ) external override onlyOwner {
        _setLpPoolRouter(routerAddress, pairAddress);
    }

    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal override(ERC20, TaxableToken) {
        super._transfer(from, to, amount);
    }

    /** @notice Transfers tokens between two addresses on behalf of a third party, with fee deductions if interacting through a DEX.
     * @param sender The address sending the tokens.
     * @param recipient The address receiving the tokens.
     * @param amount The total amount of tokens to be transferred.
     * @return bool Returns true if the transfer was successful.
     */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) public override returns (bool) {
        _spendAllowance(sender, _msgSender(), amount);
        super._transfer(sender, recipient, amount);
        return true;
    }

    /** @notice Collects protocol fees in HLX tokens, adds to the undistributed HLX pool.
     * @param amount The amount of HLX tokens to collect as fees.
     * @dev Reverts if the value sent is less than the required amount converted at `plsRate`.
     */
    function _protocolFees(uint256 amount) private {
        if (msg.value < (amount * plsRate) / 1 ether) {
            revert insufficientPLS();
        }
        // Transfer HLX From user to contract
        IERC20(hlxAddress).transferFrom(_msgSender(), address(this), amount);

        //Burns recieved HLX
        ERC20Burnable(hlxAddress).burn(amount);

        undistributedPls += msg.value;
    }

    /** @notice Distributes collected PLS to the investment pool and team address.
     */
    function distributeFees() public {
        if (undistributedPls == 0) {
            _distribute(0, 0);
            return;
        }
        uint256 investmentPoolShare = (undistributedPls *
            investmentPoolPercentage) / FEE_PRECISION;
        uint256 teamShare = undistributedPls - investmentPoolShare;

        undistributedPls = 0; // Reset the undistributed PLS after distribution

        if (investmentPoolAddress != address(0) && teamAddress != address(0)) {
            _distribute(investmentPoolShare, teamShare);
        } else {
            revert Janus_AddressesNoSet();
        }
    }

    /**
     * @dev Enable/Disable autoProcessFees on transfer
     * only callable by `owner()`
     */
    function setAutoprocessFees(bool autoProcess) external override onlyOwner {
        if (autoProcessFees == autoProcess) revert Janus_AlreadySet();
        autoProcessFees = autoProcess;
    }

    /**
     * @dev add/remove an address to the tax exclusion list
     * only callable by `owner()`
     */
    function setIsExcludedFromFees(
        address account,
        bool excluded
    ) external override onlyOwner {
        _setIsExcludedFromFees(account, excluded);
    }

    /**
     * @dev set the liquidity owner
     * only callable by `owner()`
     */
    function setLiquidityOwner(address newOwner) external override onlyOwner {
        liquidityOwner = newOwner;
    }

    /**
     * @dev set the number of tokens to swap
     * only callable by `owner()`
     */
    function setNumTokensToSwap(uint256 amount) external override onlyOwner {
        numTokensToSwap = amount;
    }

    /**
     * @dev update the fee configurations
     * only callable by `owner()`
     */
    function setFeeConfiguration(
        FeeConfiguration calldata configuration
    ) external override onlyOwner {
        _setFeeConfiguration(configuration);
    }

    /**
     * @dev update the swap router
     * only callable by `owner()`
     */
    function setSwapRouter(address newRouter) external override onlyOwner {
        _setSwapRouter(newRouter);
    }
}
        

contracts/PulseX/IPulseXRouter01.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;

interface IPulseXRouter01 {
    function factory() external pure returns (address);
    function WPLS() external pure returns (address);

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint amountADesired,
        uint amountBDesired,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB, uint liquidity);
    function addLiquidityETH(
        address token,
        uint amountTokenDesired,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    )
        external
        payable
        returns (uint amountToken, uint amountETH, uint liquidity);
    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETH(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountToken, uint amountETH);
    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETHWithPermit(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint amountToken, uint amountETH);
    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapTokensForExactTokens(
        uint amountOut,
        uint amountInMax,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapExactETHForTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable returns (uint[] memory amounts);
    function swapTokensForExactETH(
        uint amountOut,
        uint amountInMax,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapExactTokensForETH(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapETHForExactTokens(
        uint amountOut,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable returns (uint[] memory amounts);

    function quote(
        uint amountA,
        uint reserveA,
        uint reserveB
    ) external pure returns (uint amountB);
    function getAmountOut(
        uint amountIn,
        uint reserveIn,
        uint reserveOut
    ) external pure returns (uint amountOut);
    function getAmountIn(
        uint amountOut,
        uint reserveIn,
        uint reserveOut
    ) external pure returns (uint amountIn);
    function getAmountsOut(
        uint amountIn,
        address[] calldata path
    ) external view returns (uint[] memory amounts);
    function getAmountsIn(
        uint amountOut,
        address[] calldata path
    ) external view returns (uint[] memory amounts);
}
          

@openzeppelin/contracts/access/Ownable.sol

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

pragma solidity ^0.8.0;

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

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

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

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

@openzeppelin/contracts/token/ERC20/ERC20.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * The default value of {decimals} is 18. To change this, you should override
 * this function so it returns a different value.
 *
 * 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}.
     *
     * 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 default value returned by this function, unless
     * it's 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 `from` to `to`.
     *
     * 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;
            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
            // decrementing then incrementing.
            _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;
        unchecked {
            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
            _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;
            // Overflow not possible: amount <= accountBalance <= totalSupply.
            _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 {}
}
          

@openzeppelin/contracts/token/ERC20/IERC20.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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);
}
          

@openzeppelin/contracts/token/ERC20/extensions/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);
    }
}
          

@openzeppelin/contracts/token/ERC20/extensions/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);
}
          

@openzeppelin/contracts/utils/Context.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (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;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}
          

contracts/PulseX/IPulseXFactory.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;

interface IPulseXFactory {
    event PairCreated(
        address indexed token0,
        address indexed token1,
        address pair,
        uint
    );

    function feeTo() external view returns (address);
    function feeToSetter() external view returns (address);

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

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

    function setFeeTo(address) external;
    function setFeeToSetter(address) external;
}
          

contracts/PulseX/IPulseXPair.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;

interface IPulseXPair {
    event Approval(address indexed owner, address indexed spender, uint value);
    event Transfer(address indexed from, address indexed to, uint value);

    function name() external pure returns (string memory);
    function symbol() external pure returns (string memory);
    function decimals() external pure returns (uint8);
    function totalSupply() external view returns (uint);
    function balanceOf(address owner) external view returns (uint);
    function allowance(
        address owner,
        address spender
    ) external view returns (uint);

    function approve(address spender, uint value) external returns (bool);
    function transfer(address to, uint value) external returns (bool);
    function transferFrom(
        address from,
        address to,
        uint value
    ) external returns (bool);

    function DOMAIN_SEPARATOR() external view returns (bytes32);
    function PERMIT_TYPEHASH() external pure returns (bytes32);
    function nonces(address owner) external view returns (uint);

    function permit(
        address owner,
        address spender,
        uint value,
        uint deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    event Mint(
        address indexed sender,
        uint amount0,
        uint amount1,
        address indexed senderOrigin
    );
    event Burn(
        address indexed sender,
        uint amount0,
        uint amount1,
        address indexed to,
        address indexed senderOrigin
    );
    event Swap(
        address indexed sender,
        uint amount0In,
        uint amount1In,
        uint amount0Out,
        uint amount1Out,
        address indexed to
    );
    event Sync(uint112 reserve0, uint112 reserve1);

    function MINIMUM_LIQUIDITY() external pure returns (uint);
    function factory() external view returns (address);
    function token0() external view returns (address);
    function token1() external view returns (address);
    function getReserves()
        external
        view
        returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
    function price0CumulativeLast() external view returns (uint);
    function price1CumulativeLast() external view returns (uint);
    function kLast() external view returns (uint);

    function mint(
        address to,
        address senderOrigin
    ) external returns (uint liquidity);
    function burn(
        address to,
        address senderOrigin
    ) external returns (uint amount0, uint amount1);
    function swap(
        uint amount0Out,
        uint amount1Out,
        address to,
        bytes calldata data
    ) external;
    function skim(address to) external;
    function sync() external;

    function initialize(address, address) external;
}
          

contracts/PulseX/IPulseXRouter02.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;
import "./IPulseXRouter01.sol";

interface IPulseXRouter02 is IPulseXRouter01 {
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountETH);
    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint amountETH);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable;
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
}
          

contracts/TaxableToken.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./PulseX/IPulseXRouter02.sol";
import "./PulseX/IPulseXFactory.sol";
import "./PulseX/IPulseXPair.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

error Janus_ZeroAddress();
error Janus_AlreadySet();
error Janus_InvalidRouter();
error Janus_InvalidFactory();
error Janus_InvalidPair();
error Janus_InvalidBuyFee();
error Janus_InvalidSellFee();
error Janus_InvalidFeeShare();
error Janus_TransferAmountZero();
error Janus_InvalidValue();
error Janus_AddressesNoSet();
/*
 * TaxableToken: Add a tax on buy, sell or transfer
 */
abstract contract TaxableToken is ERC20, Ownable {
    struct FeeConfiguration {
        uint16 buyFees; // fees applied during buys, from 0 to 2000 (ie, 100 = 1%)
        uint16 sellFees; // fees applied during sells, from 0 to 2000 (ie, 100 = 1%)
        uint16 burnFeeRatio; // from 0 to 10000 (ie 8000 = 80% of the fee collected are burned)
        uint16 liquidityFeeRatio; // from 0 to 10000 (ie 8000 = 80% of the fee collected are added back to liquidity)
        uint16 daoFeeRatio; // from 0 to 10000 (ie 8000 = 80% of the fee collected are sent to DAO)
        uint16 devFeeRatio; // from 0 to 10000 (ie 8000 = 80% of the fee collected are sent to DEV)
    }

    address public constant BURN_ADDRESS =
        address(0x000000000000000000000000000000000000dEaD);
    uint16 public constant MAX_FEE = 2000; // max 20% fees
    uint16 public constant FEE_PRECISION = 10000;

    /// @notice Address of the investment pool where collected fees could be sent.
    address public investmentPoolAddress;

    /// @notice Address of the team where another portion of the collected fees will be sent.
    address public teamAddress;

    /// @notice Stores amount of tokens collected as tax for distribution
    uint256 public undistributedJNS;

    // swap config
    IPulseXRouter02 public swapRouter;
    address public swapPair;
    address public liquidityOwner;

    // fees
    bool private _processingFees;
    bool public autoProcessFees;
    uint256 public numTokensToSwap; // amount of tokens to collect before processing fees (default to 0.05% of supply)
    FeeConfiguration public feeConfiguration;

    mapping(address => bool) private _excludedFromFees;
    mapping(address => bool) private _lpPools;
    mapping(address => uint256) private _tokenAmountForLp;
    mapping(address => IPulseXRouter02) private _lpPoolsSwapRouter;

    event FeeConfigurationUpdated(FeeConfiguration configuration);
    event SwapRouterUpdated(address indexed router, address indexed pair);
    event ExcludedFromFees(address indexed account, bool excluded);
    event SetLpPool(address indexed pairAddress, bool isLp);
    event SetLpPoolRouter(
        address indexed routerAddress,
        address indexed pairAddress
    );
    event InvestmentPoolAddressUpdated(address indexed _investmentPoolAddress);
    event TeamAddressUpdated(address indexed _teamAddress);

    modifier lockTheSwap() {
        _processingFees = true;
        _;
        _processingFees = false;
    }

    constructor(
        bool autoProcessFees_,
        uint256 numTokensToSwap_,
        address swapRouter_,
        FeeConfiguration memory feeConfiguration_,
        address _investmentPoolAddress,
        address _teamAddress
    ) {
        numTokensToSwap = numTokensToSwap_;
        autoProcessFees = autoProcessFees_;

        liquidityOwner = _msgSender();

        // Create a uniswap pair for this new token
        swapRouter = IPulseXRouter02(swapRouter_);
        swapPair = _pairFor(
            swapRouter.factory(),
            address(this),
            swapRouter.WPLS()
        );
        _lpPools[swapPair] = true;
        _lpPoolsSwapRouter[swapPair] = swapRouter;

        // configure addresses excluded from fee
        _setIsExcludedFromFees(_msgSender(), true);
        _setIsExcludedFromFees(address(this), true);

        // configure fees
        _setFeeConfiguration(feeConfiguration_);
        _setInvestmentPoolAddress(_investmentPoolAddress);
        _setTeamAddress(_teamAddress);
    }

    // receive ETH when swaping
    receive() external payable {}

    function isExcludedFromFees(address account) public view returns (bool) {
        return _excludedFromFees[account];
    }

    function setInvestmentPoolAddress(
        address _InvestmentPoolAddress
    ) external onlyOwner {
        _setInvestmentPoolAddress(_InvestmentPoolAddress);
    }

    function setTeamAddress(address _teamAddress) external onlyOwner {
        _setTeamAddress(_teamAddress);
    }

    function _setIsExcludedFromFees(address account, bool excluded) internal {
        if (_excludedFromFees[account] == excluded) revert Janus_AlreadySet();
        _excludedFromFees[account] = excluded;
        emit ExcludedFromFees(account, excluded);
    }

    function _setInvestmentPoolAddress(
        address _investmentPoolAddress
    ) internal {
        if (_investmentPoolAddress == address(0)) revert Janus_ZeroAddress();
        investmentPoolAddress = _investmentPoolAddress;
    }

    function _setTeamAddress(address _teamAddress) internal {
        if (_teamAddress == address(0)) revert Janus_ZeroAddress();
        teamAddress = _teamAddress;
    }

    function _setIsLpPool(address pairAddress, bool isLp) internal {
        if (_lpPools[pairAddress] == isLp) revert Janus_AlreadySet();
        _lpPools[pairAddress] = isLp;
        emit SetLpPool(pairAddress, isLp);
    }

    function _setLpPoolRouter(
        address _routerAddress,
        address _pairAddress
    ) internal {
        if (_routerAddress == address(0)) revert Janus_ZeroAddress();
        _lpPoolsSwapRouter[_pairAddress] = IPulseXRouter02(_routerAddress);
        emit SetLpPoolRouter(_routerAddress, _pairAddress);
    }

    function isLpPool(address pairAddress) public view returns (bool) {
        return _lpPools[pairAddress];
    }

    function lpPoolRouter(address pairAddress) public view returns (address) {
        return address(_lpPoolsSwapRouter[pairAddress]);
    }

    function tokenForLpPool(address pairAddress) public view returns (uint256) {
        return _tokenAmountForLp[pairAddress];
    }

    function _setSwapRouter(address _newRouter) internal {
        if (_newRouter == address(0)) revert Janus_InvalidRouter();

        swapRouter = IPulseXRouter02(_newRouter);
        IPulseXFactory factory = IPulseXFactory(swapRouter.factory());
        if (address(factory) == address(0)) revert Janus_InvalidFactory();

        address weth = swapRouter.WPLS();
        swapPair = factory.getPair(address(this), weth);
        if (swapPair == address(0)) {
            swapPair = factory.createPair(address(this), weth);
        }

        if (swapPair == address(0)) revert Janus_InvalidPair();
        emit SwapRouterUpdated(address(swapRouter), swapPair);
    }

    function _setFeeConfiguration(
        FeeConfiguration memory configuration
    ) internal {
        if (!(configuration.buyFees <= MAX_FEE)) revert Janus_InvalidBuyFee();
        if (!(configuration.sellFees <= MAX_FEE)) revert Janus_InvalidSellFee();

        uint16 totalShare = configuration.burnFeeRatio +
            configuration.liquidityFeeRatio +
            configuration.daoFeeRatio +
            configuration.devFeeRatio;
        if (!(totalShare == 0 || totalShare == FEE_PRECISION))
            revert Janus_InvalidFeeShare();

        feeConfiguration = configuration;
        emit FeeConfigurationUpdated(configuration);
    }

    function _processFees(address pair) internal lockTheSwap {
        uint256 tokenAmount = _tokenAmountForLp[pair];
        uint256 contractTokenBalance = balanceOf(address(this));
        IPulseXRouter02 pairRouter = _lpPoolsSwapRouter[pair];
        if (contractTokenBalance >= tokenAmount) {
            uint256 liquidityAmount = (tokenAmount * // taxAmount is 67% here  lets say 67 tokens  out of 100 after burn amount was subtracted and burned
                feeConfiguration.liquidityFeeRatio) / // 33% for liquidity 33 tokens for liqudity
                (FEE_PRECISION - feeConfiguration.burnFeeRatio); // FEE_PRECISION is for 100% but this subtracts 33% from 100% from FEE_PRECISION making it 67% so (67 * 33) / (100 - 33) = 33
            undistributedJNS += tokenAmount - liquidityAmount; // now the remaining amount after liquidity 33% is 34%. this 34% is then divided to team/DAO 67-33 = 34 left

            (uint256 reserve0, uint256 reserve1, ) = IPulseXPair(pair)
                .getReserves();

            uint256 swapAmount;
            address tokenOut;
            if (IPulseXPair(pair).token0() == address(this)) {
                // swap from token0 to token1
                swapAmount = getSwapAmount(reserve0, liquidityAmount);
                tokenOut = IPulseXPair(pair).token1();
            } else {
                // swap from token1 to token0
                swapAmount = getSwapAmount(reserve1, liquidityAmount);
                tokenOut = IPulseXPair(pair).token0();
            }

            // swap tokens
            if (swapAmount > 0 && balanceOf(swapPair) != 0) {
                bool swapForETH;

                if (tokenOut == swapRouter.WPLS()) {
                    swapForETH = true;
                }

                // capture the contract's current balance of token
                uint256 initialBalanceTokenOut;
                if (swapForETH) {
                    initialBalanceTokenOut = address(this).balance;
                } else {
                    initialBalanceTokenOut = IERC20(tokenOut).balanceOf(
                        address(this)
                    );
                }

                uint256 liquidityTokenAmount = liquidityAmount - swapAmount;

                _swapTokens(tokenOut, swapAmount, 0, swapForETH, pairRouter);

                // how much did we just swap into?
                uint256 tokensOutReceived;
                if (swapForETH) {
                    tokensOutReceived =
                        address(this).balance -
                        initialBalanceTokenOut;
                } else {
                    tokensOutReceived =
                        IERC20(tokenOut).balanceOf(address(this)) -
                        initialBalanceTokenOut;
                }
                if (tokensOutReceived > 0) {
                    _addLiquidity(
                        liquidityTokenAmount,
                        tokensOutReceived,
                        tokenOut,
                        swapForETH,
                        pairRouter
                    );
                }
            }
            _tokenAmountForLp[pair] -= tokenAmount;
        }
    }

    function sqrt(uint256 y) private pure returns (uint256 z) {
        if (y > 3) {
            z = y;
            uint256 x = y / 2 + 1;
            while (x < z) {
                z = x;
                x = (y / x + x) / 2;
            }
        } else if (y != 0) {
            z = 1;
        }
    }

    /*
    s = optimal swap amount
    r = amount of reserve for token a
    a = amount of token a the user currently has (not added to reserve yet)
    f = swap fee percent
    s = (sqrt(((2 - f)r)^2 + 4(1 - f)ar) - (2 - f)r) / (2(1 - f))
    */
    function getSwapAmount(uint256 r, uint256 a) public pure returns (uint256) {
        return (sqrt(r * (r * 3988009 + a * 3988000)) - r * 1997) / 1994;
    }

    /// @dev Swap tokens for eth
    function _swapTokens(
        address to,
        uint256 tokenAmount,
        uint256 minAmountOut,
        bool swapForETH,
        IPulseXRouter02 pairRouter
    ) private {
        // generate the swap pair path of token -> weth
        address[] memory path = new address[](2);
        path[0] = address(this);
        path[1] = to;

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

        if (swapForETH) {
            // make the swap
            pairRouter.swapExactTokensForETHSupportingFeeOnTransferTokens(
                tokenAmount,
                minAmountOut,
                path,
                address(this),
                block.timestamp + 600
            );
        } else {
            uint[] memory amounts = pairRouter.swapExactTokensForTokens(
                tokenAmount,
                minAmountOut,
                path,
                liquidityOwner,
                block.timestamp + 600
            );
            IERC20(to).transferFrom(liquidityOwner, address(this), amounts[1]);
        }
    }

    /// @dev Add liquidity
    function _addLiquidity(
        uint256 tokenAmount,
        uint256 ethAmount,
        address _token,
        bool addETH,
        IPulseXRouter02 pairRouter
    ) private {
        // approve token transfer to cover all possible scenarios
        _approve(address(this), address(pairRouter), tokenAmount);
        IERC20(_token).approve(address(pairRouter), ethAmount);
        if (addETH) {
            // add the liquidity
            pairRouter.addLiquidityETH{value: ethAmount}(
                address(this),
                tokenAmount,
                0, // slippage is unavoidable
                0, // slippage is unavoidable
                liquidityOwner,
                block.timestamp
            );
        } else {
            pairRouter.addLiquidity(
                address(this),
                _token,
                tokenAmount,
                ethAmount,
                0,
                0,
                liquidityOwner,
                block.timestamp
            );
        }
    }

    // calculates the CREATE2 address for a pair without making any external calls
    function _pairFor(
        address factory,
        address tokenA,
        address tokenB
    ) internal pure returns (address pair) {
        (address token0, address token1) = tokenA < tokenB
            ? (tokenA, tokenB)
            : (tokenB, tokenA);
        pair = address(
            uint160(
                uint(
                    keccak256(
                        abi.encodePacked(
                            hex"ff",
                            factory,
                            keccak256(abi.encodePacked(token0, token1)),
                            hex"5dff1ac2d132f5ac2841294c6e9fc0ebafae8d447fac7996ef21c21112f411f1" // init code hash
                        )
                    )
                )
            )
        );
    }

    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual override {
        if (!(amount > 0)) revert Janus_TransferAmountZero();

        uint256 taxFee = 0;
        bool processFee = !_processingFees && autoProcessFees;

        if (!_processingFees) {
            bool fromExcluded = isExcludedFromFees(from);
            bool toExcluded = isExcludedFromFees(to);

            bool fromLP = isLpPool(from);
            bool toLP = isLpPool(to);

            if (fromLP && !toLP && !toExcluded && to != address(swapRouter)) {
                // buy fee
                taxFee = feeConfiguration.buyFees;
            } else if (toLP && !fromExcluded && !toExcluded) {
                // sell fee
                taxFee = feeConfiguration.sellFees;
            }
        }

        // // process fees
        if (processFee && taxFee > 0 && !_lpPools[from]) {
            uint256 contractTokenBalanceForPool = _tokenAmountForLp[to];
            if (contractTokenBalanceForPool >= numTokensToSwap) {
                _processFees(to);
            }
        }

        if (taxFee > 0) {
            uint256 taxAmount = (amount * taxFee) / FEE_PRECISION;
            uint256 sendAmount = amount - taxAmount;
            uint256 burnAmount = (taxAmount * feeConfiguration.burnFeeRatio) /
                FEE_PRECISION;

            if (burnAmount > 0) {
                taxAmount -= burnAmount;
                super._transfer(from, BURN_ADDRESS, burnAmount);
            }

            if (taxAmount > 0) {
                super._transfer(from, address(this), taxAmount);
                if (isLpPool(to)) {
                    _tokenAmountForLp[to] += taxAmount;
                } else {
                    _tokenAmountForLp[from] += taxAmount;
                }
            }

            if (sendAmount > 0) {
                super._transfer(from, to, sendAmount);
            }
        } else {
            super._transfer(from, to, amount);
        }
    }

    function _distribute(
        uint256 _investmentPoolShare,
        uint256 _teamShare
    ) internal {
        uint256 amount = undistributedJNS;
        if (amount >= numTokensToSwap) {
            uint256 initialBalance = address(this).balance;

            _swapTokens(swapRouter.WPLS(), amount, 0, true, swapRouter);

            amount = (address(this).balance - initialBalance);

            uint256 investmentPoolShare = (amount *
                feeConfiguration.daoFeeRatio) /
                (FEE_PRECISION -
                    (feeConfiguration.burnFeeRatio +
                        feeConfiguration.liquidityFeeRatio));

            uint256 teamShare = amount - investmentPoolShare;

            undistributedJNS = 0; // Reset the undistributed JNS before distribution

            payable(investmentPoolAddress).transfer(
                investmentPoolShare + _investmentPoolShare
            );
            payable(teamAddress).transfer(teamShare + _teamShare);
        } else if (_investmentPoolShare != 0) {
            payable(investmentPoolAddress).transfer(_investmentPoolShare);
            payable(teamAddress).transfer(_teamShare);
        }
    }

    function setAutoprocessFees(bool autoProcess) external virtual;

    function setIsLpPool(address pairAddress, bool isLp) external virtual;

    function setLpPoolRouter(
        address routerAddress,
        address pairAddress
    ) external virtual;

    function setIsExcludedFromFees(
        address account,
        bool excluded
    ) external virtual;

    function processFees(address pair) external virtual;

    function setLiquidityOwner(address newOwner) external virtual;

    function setNumTokensToSwap(uint256 amount) external virtual;

    function setFeeConfiguration(
        FeeConfiguration calldata configuration
    ) external virtual;

    function setSwapRouter(address newRouter) external virtual;
}

// Lp swap Router public function
          

Compiler Settings

{"outputSelection":{"*":{"*":["*"],"":["*"]}},"optimizer":{"runs":20000,"enabled":true},"libraries":{},"evmVersion":"paris"}
              

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_hlxAddress","internalType":"address"},{"type":"uint256","name":"_plsRate","internalType":"uint256"},{"type":"address","name":"swapRouter_","internalType":"address"},{"type":"tuple","name":"feeConfiguration_","internalType":"struct TaxableToken.FeeConfiguration","components":[{"type":"uint16","name":"buyFees","internalType":"uint16"},{"type":"uint16","name":"sellFees","internalType":"uint16"},{"type":"uint16","name":"burnFeeRatio","internalType":"uint16"},{"type":"uint16","name":"liquidityFeeRatio","internalType":"uint16"},{"type":"uint16","name":"daoFeeRatio","internalType":"uint16"},{"type":"uint16","name":"devFeeRatio","internalType":"uint16"}]},{"type":"uint256","name":"numTokensToSwap","internalType":"uint256"},{"type":"address","name":"_investmentPoolAddress","internalType":"address"},{"type":"address","name":"_teamAddress","internalType":"address"}]},{"type":"error","name":"Janus_AddressesNoSet","inputs":[]},{"type":"error","name":"Janus_AlreadySet","inputs":[]},{"type":"error","name":"Janus_InvalidBuyFee","inputs":[]},{"type":"error","name":"Janus_InvalidFactory","inputs":[]},{"type":"error","name":"Janus_InvalidFeeShare","inputs":[]},{"type":"error","name":"Janus_InvalidPair","inputs":[]},{"type":"error","name":"Janus_InvalidRouter","inputs":[]},{"type":"error","name":"Janus_InvalidSellFee","inputs":[]},{"type":"error","name":"Janus_InvalidValue","inputs":[]},{"type":"error","name":"Janus_TransferAmountZero","inputs":[]},{"type":"error","name":"Janus_ZeroAddress","inputs":[]},{"type":"error","name":"insufficientPLS","inputs":[]},{"type":"event","name":"Approval","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"address","name":"spender","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ExcludedFromFees","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"bool","name":"excluded","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"FeeConfigurationUpdated","inputs":[{"type":"tuple","name":"configuration","internalType":"struct TaxableToken.FeeConfiguration","indexed":false,"components":[{"type":"uint16","name":"buyFees","internalType":"uint16"},{"type":"uint16","name":"sellFees","internalType":"uint16"},{"type":"uint16","name":"burnFeeRatio","internalType":"uint16"},{"type":"uint16","name":"liquidityFeeRatio","internalType":"uint16"},{"type":"uint16","name":"daoFeeRatio","internalType":"uint16"},{"type":"uint16","name":"devFeeRatio","internalType":"uint16"}]}],"anonymous":false},{"type":"event","name":"InvestmentPoolAddressUpdated","inputs":[{"type":"address","name":"_investmentPoolAddress","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"SetLpPool","inputs":[{"type":"address","name":"pairAddress","internalType":"address","indexed":true},{"type":"bool","name":"isLp","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"SetLpPoolRouter","inputs":[{"type":"address","name":"routerAddress","internalType":"address","indexed":true},{"type":"address","name":"pairAddress","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"SwapRouterUpdated","inputs":[{"type":"address","name":"router","internalType":"address","indexed":true},{"type":"address","name":"pair","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"TeamAddressUpdated","inputs":[{"type":"address","name":"_teamAddress","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"BURN_ADDRESS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint16","name":"","internalType":"uint16"}],"name":"FEE_PRECISION","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint16","name":"","internalType":"uint16"}],"name":"MAX_FEE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allowance","inputs":[{"type":"address","name":"owner","internalType":"address"},{"type":"address","name":"spender","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"approve","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"autoProcessFees","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"decimals","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"decreaseAllowance","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"subtractedValue","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"distributeFees","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint16","name":"buyFees","internalType":"uint16"},{"type":"uint16","name":"sellFees","internalType":"uint16"},{"type":"uint16","name":"burnFeeRatio","internalType":"uint16"},{"type":"uint16","name":"liquidityFeeRatio","internalType":"uint16"},{"type":"uint16","name":"daoFeeRatio","internalType":"uint16"},{"type":"uint16","name":"devFeeRatio","internalType":"uint16"}],"name":"feeConfiguration","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getSwapAmount","inputs":[{"type":"uint256","name":"r","internalType":"uint256"},{"type":"uint256","name":"a","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"hlxAddress","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"increaseAllowance","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"addedValue","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"investmentPoolAddress","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"investmentPoolPercentage","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isExcludedFromFees","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isLpPool","inputs":[{"type":"address","name":"pairAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"liquidityOwner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"lpPoolRouter","inputs":[{"type":"address","name":"pairAddress","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"mint","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"numTokensToSwap","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"plsRate","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"processFees","inputs":[{"type":"address","name":"pair","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setAutoprocessFees","inputs":[{"type":"bool","name":"autoProcess","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFeeConfiguration","inputs":[{"type":"tuple","name":"configuration","internalType":"struct TaxableToken.FeeConfiguration","components":[{"type":"uint16","name":"buyFees","internalType":"uint16"},{"type":"uint16","name":"sellFees","internalType":"uint16"},{"type":"uint16","name":"burnFeeRatio","internalType":"uint16"},{"type":"uint16","name":"liquidityFeeRatio","internalType":"uint16"},{"type":"uint16","name":"daoFeeRatio","internalType":"uint16"},{"type":"uint16","name":"devFeeRatio","internalType":"uint16"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setHLXAddress","inputs":[{"type":"address","name":"_hlxAddress","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setInvestmentPoolAddress","inputs":[{"type":"address","name":"_InvestmentPoolAddress","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setInvestmentPoolPercentage","inputs":[{"type":"uint256","name":"_percentage","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setIsExcludedFromFees","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"bool","name":"excluded","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setIsLpPool","inputs":[{"type":"address","name":"pairAddress","internalType":"address"},{"type":"bool","name":"isLp","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setLiquidityOwner","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setLpPoolRouter","inputs":[{"type":"address","name":"routerAddress","internalType":"address"},{"type":"address","name":"pairAddress","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setNumTokensToSwap","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setPLSRate","inputs":[{"type":"uint256","name":"_plsRate","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setSwapRouter","inputs":[{"type":"address","name":"newRouter","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setTeamAddress","inputs":[{"type":"address","name":"_teamAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"swapPair","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IPulseXRouter02"}],"name":"swapRouter","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"symbol","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"teamAddress","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"tokenForLpPool","inputs":[{"type":"address","name":"pairAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSupply","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transfer","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transferFrom","inputs":[{"type":"address","name":"sender","internalType":"address"},{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"undistributedJNS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"undistributedPls","inputs":[]},{"type":"receive","stateMutability":"payable"}]
              

Contract Creation Code

0x6080604052611b586012553480156200001757600080fd5b506040516200467c3803806200467c8339810160408190526200003a916200089c565b60016200004a6012600a62000ad8565b62000056908562000af0565b86868585604051806040016040528060058152602001644a616e757360d81b815250604051806040016040528060038152602001624a4e5360e81b8152508160039081620000a5919062000b98565b506004620000b4828262000b98565b505050620000d1620000cb620002f760201b60201c565b620002fb565b600c859055600b805460ff60a81b1916600160a81b88151502179055620000f53390565b600b80546001600160a01b039283166001600160a01b0319918216179091556009805492871692909116821790556040805163c45a015560e01b8152905162000200929163c45a01559160048083019260209291908290030181865afa15801562000164573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200018a919062000c64565b6009546040805163ef8ef56f60e01b8152905130926001600160a01b03169163ef8ef56f9160048083019260209291908290030181865afa158015620001d4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001fa919062000c64565b6200034d565b600a80546001600160a01b03199081166001600160a01b0393841690811783556000908152600f60209081526040808320805460ff191660011790556009549454861683526011909152902080549290931691161790556200026433600162000450565b6200027130600162000450565b6200027c83620004f1565b6200028782620006f7565b620002928162000741565b5050601480546001600160a01b0319166001600160a01b038d16179055505050601587905550620002ea33620002c6601290565b620002d390600a62000ad8565b620002e4906461c9f3680062000af0565b6200078b565b5050505050505062000cbd565b3390565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000806000836001600160a01b0316856001600160a01b0316106200037457838562000377565b84845b6040516001600160601b0319606084811b8216602084015283901b16603482015291935091508690604801604051602081830303815290604052805190602001206040516020016200042e9291907fff00000000000000000000000000000000000000000000000000000000000000815260609290921b6001600160601b031916600183015260158201527f5dff1ac2d132f5ac2841294c6e9fc0ebafae8d447fac7996ef21c21112f411f1603582015260550190565b60408051601f1981840301815291905280516020909101209695505050505050565b6001600160a01b0382166000908152600e602052604090205481151560ff90911615150362000492576040516347d1eec560e01b815260040160405180910390fd5b6001600160a01b0382166000818152600e6020908152604091829020805460ff191685151590811790915591519182527f3499bfcf9673677ba552f3fe2ea274ec7e6246da31c3c87e115b45a9b0db2efb910160405180910390a25050565b80516107d061ffff90911611156200051c5760405163715be89160e01b815260040160405180910390fd5b6107d061ffff16816020015161ffff1611156200054c5760405163eff20f8760e01b815260040160405180910390fd5b60008160a001518260800151836060015184604001516200056e919062000c82565b6200057a919062000c82565b62000586919062000c82565b905061ffff811615806200059f575061ffff8116612710145b620005bd5760405163261e4bd360e21b815260040160405180910390fd5b8151600d805460208501516040808701516060880151608089015160a08a015161ffff9081166a01000000000000000000000261ffff60501b1992821668010000000000000000029290921663ffffffff60401b1993821666010000000000000261ffff60301b19958316640100000000029590951663ffffffff60201b19978316620100000263ffffffff1990991692909a1691909117969096179490941696909617179490941691909117179055517fc9632f3cf45264c46361b5340b78f8ef11e561d580a40379a966e3aa8f1f6d7c90620006eb908490600060c08201905061ffff8084511683528060208501511660208401528060408501511660408401528060608501511660608401528060808501511660808401528060a08501511660a08401525092915050565b60405180910390a15050565b6001600160a01b0381166200071f576040516344c9a53160e01b815260040160405180910390fd5b600680546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b03811662000769576040516344c9a53160e01b815260040160405180910390fd5b600780546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b038216620007e65760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640160405180910390fd5b8060026000828254620007fa919062000ca7565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b505050565b80516001600160a01b03811681146200086e57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b805161ffff811681146200086e57600080fd5b6000806000806000806000878903610180811215620008ba57600080fd5b620008c58962000856565b975060208901519650620008dc60408a0162000856565b955060c0605f1982011215620008f157600080fd5b5060405160c081016001600160401b038111828210171562000917576200091762000873565b6040526200092860608a0162000889565b81526200093860808a0162000889565b60208201526200094b60a08a0162000889565b60408201526200095e60c08a0162000889565b60608201526200097160e08a0162000889565b6080820152620009856101008a0162000889565b60a08201526101208901519094509250620009a4610140890162000856565b9150620009b5610160890162000856565b905092959891949750929550565b634e487b7160e01b600052601160045260246000fd5b600181815b8085111562000a1a578160001904821115620009fe57620009fe620009c3565b8085161562000a0c57918102915b93841c9390800290620009de565b509250929050565b60008262000a335750600162000ad2565b8162000a425750600062000ad2565b816001811462000a5b576002811462000a665762000a86565b600191505062000ad2565b60ff84111562000a7a5762000a7a620009c3565b50506001821b62000ad2565b5060208310610133831016604e8410600b841016171562000aab575081810a62000ad2565b62000ab78383620009d9565b806000190482111562000ace5762000ace620009c3565b0290505b92915050565b600062000ae960ff84168362000a22565b9392505050565b808202811582820484141762000ad25762000ad2620009c3565b600181811c9082168062000b1f57607f821691505b60208210810362000b4057634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200085157600081815260208120601f850160051c8101602086101562000b6f5750805b601f850160051c820191505b8181101562000b905782815560010162000b7b565b505050505050565b81516001600160401b0381111562000bb45762000bb462000873565b62000bcc8162000bc5845462000b0a565b8462000b46565b602080601f83116001811462000c04576000841562000beb5750858301515b600019600386901b1c1916600185901b17855562000b90565b600085815260208120601f198616915b8281101562000c355788860151825594840194600190910190840162000c14565b508582101562000c545787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60006020828403121562000c7757600080fd5b62000ae98262000856565b61ffff81811683821601908082111562000ca05762000ca0620009c3565b5092915050565b8082018082111562000ad25762000ad2620009c3565b6139af8062000ccd6000396000f3fe6080604052600436106103385760003560e01c806370a08231116101b0578063bb57ad20116100ec578063e55096b011610095578063ee2912631161006f578063ee29126314610a25578063f2d9b35314610a3b578063f2fde38b14610a5b578063fccc281314610a7b57600080fd5b8063e55096b0146109cf578063e63a391f146109ef578063e893c37014610a0557600080fd5b8063caea1e69116100c6578063caea1e691461093a578063dd62ed3e14610950578063df64c87f1461099657600080fd5b8063bb57ad20146108dc578063bc063e1a146108f1578063c31c9c071461091a57600080fd5b806395d89b41116101595780639b61f1d0116101335780639b61f1d014610849578063a457c2d71461087c578063a9059cbb1461089c578063adf18693146108bc57600080fd5b806395d89b411461077a57806398c47e8c1461078f57806398dd215a1461082957600080fd5b80637994606d1161018a5780637994606d1461071c5780637f5bbb2c1461073c5780638da5cb5b1461075c57600080fd5b806370a08231146106b1578063715018a6146106e757806372bc5583146106fc57600080fd5b806326991cc81161027f578063412736571161022857806361582eaa1161020257806361582eaa146106225780636690864e146106425780636f741f2a146106625780636fcb97261461069b57600080fd5b806341273657146105a957806348c043af146105c95780634fbee193146105e957600080fd5b80633935ebf9116102595780633935ebf914610556578063395093511461057657806340c10f191461059657600080fd5b806326991cc8146104fa578063313ce5671461051a578063368519f31461053657600080fd5b80630ccf4c05116102e15780631a82094b116102bb5780631a82094b146104825780631c75f085146104a257806323b872dd146104da57600080fd5b80630ccf4c05146104175780630f569dad1461044d57806318160ddd1461046d57600080fd5b8063073a665511610312578063073a6655146103b1578063095ea7b3146103c75780630a99f2e8146103f757600080fd5b806301a6c43b1461034457806302da38871461036d57806306fdde031461038f57600080fd5b3661033f57005b600080fd5b34801561035057600080fd5b5061035a600c5481565b6040519081526020015b60405180910390f35b34801561037957600080fd5b5061038d6103883660046132fa565b610a91565b005b34801561039b57600080fd5b506103a4610ad8565b6040516103649190613313565b3480156103bd57600080fd5b5061035a60125481565b3480156103d357600080fd5b506103e76103e2366004613394565b610b6a565b6040519015158152602001610364565b34801561040357600080fd5b5061038d6104123660046133c0565b610b84565b34801561042357600080fd5b5061035a6104323660046133f9565b6001600160a01b031660009081526010602052604090205490565b34801561045957600080fd5b5061038d6104683660046132fa565b610b9a565b34801561047957600080fd5b5060025461035a565b34801561048e57600080fd5b5061038d61049d3660046132fa565b610ba7565b3480156104ae57600080fd5b506007546104c2906001600160a01b031681565b6040516001600160a01b039091168152602001610364565b3480156104e657600080fd5b506103e76104f5366004613416565b610bfc565b34801561050657600080fd5b50600a546104c2906001600160a01b031681565b34801561052657600080fd5b5060405160128152602001610364565b34801561054257600080fd5b5061035a610551366004613457565b610c1e565b34801561056257600080fd5b50600b546104c2906001600160a01b031681565b34801561058257600080fd5b506103e7610591366004613394565b610c80565b61038d6105a4366004613394565b610cbf565b3480156105b557600080fd5b5061038d6105c43660046133f9565b610cfe565b3480156105d557600080fd5b506006546104c2906001600160a01b031681565b3480156105f557600080fd5b506103e76106043660046133f9565b6001600160a01b03166000908152600e602052604090205460ff1690565b34801561062e57600080fd5b5061038d61063d3660046133f9565b610d12565b34801561064e57600080fd5b5061038d61065d3660046133f9565b610d23565b34801561066e57600080fd5b506103e761067d3660046133f9565b6001600160a01b03166000908152600f602052604090205460ff1690565b3480156106a757600080fd5b5061035a60085481565b3480156106bd57600080fd5b5061035a6106cc3660046133f9565b6001600160a01b031660009081526020819052604090205490565b3480156106f357600080fd5b5061038d610d34565b34801561070857600080fd5b5061038d6107173660046133f9565b610d48565b34801561072857600080fd5b5061038d610737366004613479565b610d8a565b34801561074857600080fd5b5061038d610757366004613499565b610da9565b34801561076857600080fd5b506005546001600160a01b03166104c2565b34801561078657600080fd5b506103a4610e48565b34801561079b57600080fd5b50600d546107ec9061ffff808216916201000081048216916401000000008204811691660100000000000081048216916801000000000000000082048116916a010000000000000000000090041686565b6040805161ffff978816815295871660208701529386169385019390935290841660608401528316608083015290911660a082015260c001610364565b34801561083557600080fd5b506014546104c2906001600160a01b031681565b34801561085557600080fd5b50600b546103e7907501000000000000000000000000000000000000000000900460ff1681565b34801561088857600080fd5b506103e7610897366004613394565b610e57565b3480156108a857600080fd5b506103e76108b7366004613394565b610f2b565b3480156108c857600080fd5b5061038d6108d73660046134b6565b610f39565b3480156108e857600080fd5b5061038d610f4b565b3480156108fd57600080fd5b506109076107d081565b60405161ffff9091168152602001610364565b34801561092657600080fd5b506009546104c2906001600160a01b031681565b34801561094657600080fd5b5061035a60135481565b34801561095c57600080fd5b5061035a61096b3660046133c0565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b3480156109a257600080fd5b506104c26109b13660046133f9565b6001600160a01b039081166000908152601160205260409020541690565b3480156109db57600080fd5b5061038d6109ea3660046134b6565b611002565b3480156109fb57600080fd5b5061090761271081565b348015610a1157600080fd5b5061038d610a203660046133f9565b611014565b348015610a3157600080fd5b5061035a60155481565b348015610a4757600080fd5b5061038d610a563660046133f9565b611025565b348015610a6757600080fd5b5061038d610a763660046133f9565b6110a7565b348015610a8757600080fd5b506104c261dead81565b610a9961114e565b60008111610ad3576040517f071308ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601555565b606060038054610ae7906134e4565b80601f0160208091040260200160405190810160405280929190818152602001828054610b13906134e4565b8015610b605780601f10610b3557610100808354040283529160200191610b60565b820191906000526020600020905b815481529060010190602001808311610b4357829003601f168201915b5050505050905090565b600033610b788185856111c2565b60019150505b92915050565b610b8c61114e565b610b96828261134e565b5050565b610ba261114e565b600c55565b610baf61114e565b600081118015610bc157506127108111155b610bf7576040517f071308ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601255565b6000610c09843384611400565b610c148484846114ca565b5060019392505050565b60006107ca610c2f846107cd613560565b610c65610c3f85623cda20613560565b610c4c87623cda29613560565b610c569190613577565b610c609087613560565b6117cb565b610c6f919061358a565b610c79919061359d565b9392505050565b3360008181526001602090815260408083206001600160a01b0387168452909152812054909190610b789082908690610cba908790613577565b6111c2565b610cc88161183b565b610cd282826119c8565b600b547501000000000000000000000000000000000000000000900460ff1615610b9657610b96610f4b565b610d0661114e565b610d0f81611aa1565b50565b610d1a61114e565b610d0f81611e6d565b610d2b61114e565b610d0f81612404565b610d3c61114e565b610d46600061247e565b565b610d5061114e565b600b80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b610d9261114e565b610d0f610da436839003830183613668565b6124e8565b610db161114e565b801515600b60159054906101000a900460ff16151503610dfd576040517f47d1eec500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b80549115157501000000000000000000000000000000000000000000027fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff909216919091179055565b606060048054610ae7906134e4565b3360008181526001602090815260408083206001600160a01b038716845290915281205490919083811015610f13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f00000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b610f2082868684036111c2565b506001949350505050565b600033610b788185856127ad565b610f4161114e565b610b9682826127bd565b601354600003610f6057610d46600080612895565b600061271061ffff16601254601354610f799190613560565b610f83919061359d565b9050600081601354610f95919061358a565b60006013556006549091506001600160a01b031615801590610fc157506007546001600160a01b031615155b15610fd057610b968282612895565b6040517f0b518a1700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61100a61114e565b610b968282612ad0565b61101c61114e565b610d0f81612ba0565b61102d61114e565b6001600160a01b03811661106d576040517f44c9a53100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601480547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6110af61114e565b6001600160a01b038116611145576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610f0a565b610d0f8161247e565b6005546001600160a01b03163314610d46576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610f0a565b6001600160a01b038316611257576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610f0a565b6001600160a01b0382166112ed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610f0a565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6001600160a01b03821661138e576040517f44c9a53100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0381811660008181526011602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169487169485179055519192917f67a3d1ca2003f80cceae34de5190ec082c3edf031890bd3bc449f906b5d5b79e9190a35050565b6001600160a01b038381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146114c457818110156114b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610f0a565b6114c484848484036111c2565b50505050565b60008111611504576040517fd761674700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b54600090819074010000000000000000000000000000000000000000900460ff1615801561154f5750600b547501000000000000000000000000000000000000000000900460ff165b600b5490915074010000000000000000000000000000000000000000900460ff1661162e576001600160a01b038581166000818152600e602090815260408083205494891680845281842054948452600f909252808320549183529091205460ff938416939283169291821691168180156115c8575080155b80156115d2575082155b80156115ec57506009546001600160a01b03898116911614155b156115ff57600d5461ffff169550611629565b80801561160a575083155b8015611614575082155b1561162957600d5462010000900461ffff1695505b505050505b80801561163b5750600082115b801561166057506001600160a01b0385166000908152600f602052604090205460ff16155b15611692576001600160a01b038416600090815260106020526040902054600c5481106116905761169085611e6d565b505b81156117b95760006127106116a78486613560565b6116b1919061359d565b905060006116bf828661358a565b600d54909150600090612710906116e290640100000000900461ffff1685613560565b6116ec919061359d565b9050801561170d576116fe818461358a565b925061170d8861dead83612c1a565b82156117a05761171e883085612c1a565b6001600160a01b0387166000908152600f602052604090205460ff1615611772576001600160a01b03871660009081526010602052604081208054859290611767908490613577565b909155506117a09050565b6001600160a01b0388166000908152601060205260408120805485929061179a908490613577565b90915550505b81156117b1576117b1888884612c1a565b5050506117c4565b6117c4858585612c1a565b5050505050565b6000600382111561182c57508060006117e560028361359d565b6117f0906001613577565b90505b818110156118265790508060028161180b818661359d565b6118159190613577565b61181f919061359d565b90506117f3565b50919050565b8115611836575060015b919050565b670de0b6b3a7640000601554826118529190613560565b61185c919061359d565b341015611895576040517f33be342e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6014546001600160a01b03166323b872dd336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152306024820152604481018490526064016020604051808303816000875af1158015611912573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119369190613707565b506014546040517f42966c68000000000000000000000000000000000000000000000000000000008152600481018390526001600160a01b03909116906342966c6890602401600060405180830381600087803b15801561199657600080fd5b505af11580156119aa573d6000803e3d6000fd5b5050505034601360008282546119c09190613577565b909155505050565b6001600160a01b038216611a38576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610f0a565b8060026000828254611a4a9190613577565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b6001600160a01b038116611ae1576040517f9299312300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600980547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316908117909155604080517fc45a015500000000000000000000000000000000000000000000000000000000815290516000929163c45a01559160048083019260209291908290030181865afa158015611b6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b929190613724565b90506001600160a01b038116611bd4576040517f4d22e3f200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600954604080517fef8ef56f00000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163ef8ef56f9160048083019260209291908290030181865afa158015611c37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c5b9190613724565b6040517fe6a439050000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0380831660248301529192509083169063e6a4390590604401602060405180830381865afa158015611cc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ce89190613724565b600a80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03929092169182179055611de7576040517fc9c653960000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03828116602483015283169063c9c65396906044016020604051808303816000875af1158015611d8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dae9190613724565b600a80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03929092169190911790555b600a546001600160a01b0316611e29576040517fc3aed2de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a546009546040516001600160a01b0392831692909116907fca394f95d8dbf1e8b2e76b9a8da90cacce1da85181a65508dab13212dc1df53b90600090a3505050565b600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790556001600160a01b03811660009081526010602052604081205490611ee5306001600160a01b031660009081526020819052604090205490565b6001600160a01b03808516600090815260116020526040902054919250168282106123d657600d54600090611f2890640100000000900461ffff16612710613741565b600d5461ffff91821691611f4791660100000000000090041686613560565b611f51919061359d565b9050611f5d818561358a565b60086000828254611f6e9190613577565b92505081905550600080866001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015611fb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fda9190613781565b506dffffffffffffffffffffffffffff1691506dffffffffffffffffffffffffffff169150600080306001600160a01b0316896001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa15801561204a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061206e9190613724565b6001600160a01b0316036120f1576120868486610c1e565b9150886001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120ea9190613724565b9050612162565b6120fb8386610c1e565b9150886001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa15801561213b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061215f9190613724565b90505b60008211801561218b5750600a546001600160a01b031660009081526020819052604090205415155b156123a357600954604080517fef8ef56f00000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163ef8ef56f9160048083019260209291908290030181865afa1580156121f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122179190613724565b6001600160a01b0316826001600160a01b031603612233575060015b600081156122425750476122c6565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa15801561229f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122c391906137d1565b90505b60006122d2858961358a565b90506122e284866000868d612e55565b600083156122fb576122f4834761358a565b905061238b565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015283906001600160a01b038716906370a0823190602401602060405180830381865afa15801561235a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061237e91906137d1565b612388919061358a565b90505b801561239e5761239e828287878e6130f6565b505050505b6001600160a01b038916600090815260106020526040812080548a92906123cb90849061358a565b909155505050505050505b5050600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690555050565b6001600160a01b038116612444576040517f44c9a53100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b600580546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516107d061ffff909116111561252b576040517f715be89100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107d061ffff16816020015161ffff161115612573576040517feff20f8700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008160a0015182608001518360600151846040015161259391906137ea565b61259d91906137ea565b6125a791906137ea565b905061ffff811615806125bf575061ffff8116612710145b6125f5576040517f98792f4c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8151600d805460208501516040808701516060880151608089015160a08a015161ffff9081166a0100000000000000000000027fffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffff9282166801000000000000000002929092167fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff9382166601000000000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffff95831664010000000002959095167fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff97831662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000090991692909a1691909117969096179490941696909617179490941691909117179055517fc9632f3cf45264c46361b5340b78f8ef11e561d580a40379a966e3aa8f1f6d7c906127a1908490600060c08201905061ffff8084511683528060208501511660208401528060408501511660408401528060608501511660608401528060808501511660808401528060a08501511660a08401525092915050565b60405180910390a15050565b6127b88383836114ca565b505050565b6001600160a01b0382166000908152600e602052604090205481151560ff909116151503612817576040517f47d1eec500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0382166000818152600e602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182527f3499bfcf9673677ba552f3fe2ea274ec7e6246da31c3c87e115b45a9b0db2efb91015b60405180910390a25050565b600854600c548110612a5557600954604080517fef8ef56f00000000000000000000000000000000000000000000000000000000815290514792612947926001600160a01b039091169163ef8ef56f916004808201926020929091908290030181865afa15801561290a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061292e9190613724565b60095484906000906001906001600160a01b0316612e55565b612951814761358a565b600d5490925060009061297c9061ffff660100000000000082048116916401000000009004166137ea565b61298890612710613741565b600d5461ffff918216916129a9916801000000000000000090041685613560565b6129b3919061359d565b905060006129c1828561358a565b60006008556006549091506001600160a01b03166108fc6129e28885613577565b6040518115909202916000818181858888f19350505050158015612a0a573d6000803e3d6000fd5b506007546001600160a01b03166108fc612a248784613577565b6040518115909202916000818181858888f19350505050158015612a4c573d6000803e3d6000fd5b50505050505050565b82156127b8576006546040516001600160a01b039091169084156108fc029085906000818181858888f19350505050158015612a95573d6000803e3d6000fd5b506007546040516001600160a01b039091169083156108fc029084906000818181858888f193505050501580156114c4573d6000803e3d6000fd5b6001600160a01b0382166000908152600f602052604090205481151560ff909116151503612b2a576040517f47d1eec500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0382166000818152600f602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182527f902b2ea0acdec5a260e398590d055fe29bd61ef5dd41e45db54a4cd98d5569e09101612889565b6001600160a01b038116612be0576040517f44c9a53100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600680547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6001600160a01b038316612cb0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610f0a565b6001600160a01b038216612d46576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610f0a565b6001600160a01b03831660009081526020819052604090205481811015612def576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610f0a565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36114c4565b6040805160028082526060820183526000926020830190803683370190505090503081600081518110612e8a57612e8a613805565b60200260200101906001600160a01b031690816001600160a01b0316815250508581600181518110612ebe57612ebe613805565b60200260200101906001600160a01b031690816001600160a01b031681525050612ee93083876111c2565b8215612f65576001600160a01b03821663791ac94786868430612f0e42610258613577565b6040518663ffffffff1660e01b8152600401612f2e959493929190613834565b600060405180830381600087803b158015612f4857600080fd5b505af1158015612f5c573d6000803e3d6000fd5b505050506130ee565b600b546000906001600160a01b03808516916338ed17399189918991879116612f9042610258613577565b6040518663ffffffff1660e01b8152600401612fb0959493929190613834565b6000604051808303816000875af1158015612fcf573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261301591908101906138a5565b9050866001600160a01b03166323b872dd600b60009054906101000a90046001600160a01b0316308460018151811061305057613050613805565b60209081029190910101516040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064016020604051808303816000875af11580156130c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130eb9190613707565b50505b505050505050565b6131013082876111c2565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301526024820186905284169063095ea7b3906044016020604051808303816000875af1158015613169573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061318d9190613707565b50811561324057600b546040517ff305d7190000000000000000000000000000000000000000000000000000000081523060048201526024810187905260006044820181905260648201526001600160a01b0391821660848201524260a48201529082169063f305d71990869060c40160606040518083038185885af115801561321b573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906117b1919061394b565b600b546040517fe8e337000000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038581166024830152604482018890526064820187905260006084830181905260a483015291821660c48201524260e48201529082169063e8e3370090610104016060604051808303816000875af11580156132d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130eb919061394b565b60006020828403121561330c57600080fd5b5035919050565b600060208083528351808285015260005b8181101561334057858101830151858201604001528201613324565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b6001600160a01b0381168114610d0f57600080fd5b600080604083850312156133a757600080fd5b82356133b28161337f565b946020939093013593505050565b600080604083850312156133d357600080fd5b82356133de8161337f565b915060208301356133ee8161337f565b809150509250929050565b60006020828403121561340b57600080fd5b8135610c798161337f565b60008060006060848603121561342b57600080fd5b83356134368161337f565b925060208401356134468161337f565b929592945050506040919091013590565b6000806040838503121561346a57600080fd5b50508035926020909101359150565b600060c0828403121561182657600080fd5b8015158114610d0f57600080fd5b6000602082840312156134ab57600080fd5b8135610c798161348b565b600080604083850312156134c957600080fd5b82356134d48161337f565b915060208301356133ee8161348b565b600181811c908216806134f857607f821691505b602082108103611826577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417610b7e57610b7e613531565b80820180821115610b7e57610b7e613531565b81810381811115610b7e57610b7e613531565b6000826135d3577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561364e5761364e6135d8565b604052919050565b803561ffff8116811461183657600080fd5b600060c0828403121561367a57600080fd5b60405160c0810181811067ffffffffffffffff8211171561369d5761369d6135d8565b6040526136a983613656565b81526136b760208401613656565b60208201526136c860408401613656565b60408201526136d960608401613656565b60608201526136ea60808401613656565b60808201526136fb60a08401613656565b60a08201529392505050565b60006020828403121561371957600080fd5b8151610c798161348b565b60006020828403121561373657600080fd5b8151610c798161337f565b61ffff82811682821603908082111561375c5761375c613531565b5092915050565b80516dffffffffffffffffffffffffffff8116811461183657600080fd5b60008060006060848603121561379657600080fd5b61379f84613763565b92506137ad60208501613763565b9150604084015163ffffffff811681146137c657600080fd5b809150509250925092565b6000602082840312156137e357600080fd5b5051919050565b61ffff81811683821601908082111561375c5761375c613531565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060a082018783526020878185015260a0604085015281875180845260c086019150828901935060005b818110156138845784516001600160a01b03168352938301939183019160010161385f565b50506001600160a01b03969096166060850152505050608001529392505050565b600060208083850312156138b857600080fd5b825167ffffffffffffffff808211156138d057600080fd5b818501915085601f8301126138e457600080fd5b8151818111156138f6576138f66135d8565b8060051b9150613907848301613607565b818152918301840191848101908884111561392157600080fd5b938501935b8385101561393f57845182529385019390850190613926565b98975050505050505050565b60008060006060848603121561396057600080fd5b835192506020840151915060408401519050925092509256fea26469706673582212201e4087c73a0446fa08c47f751152a4ca88e3f6cc823e4e214499b8a75499f9d564736f6c63430008140033000000000000000000000000aadb63c2cdb9b07761adc41b52436aee8296cebb000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000165c3410fc91ef562c50559f7d2289febed552d9000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000012c0000000000000000000000000000000000000000000000000000000000000ce40000000000000000000000000000000000000000000000000000000000000ce4000000000000000000000000000000000000000000000000000000000000094c00000000000000000000000000000000000000000000000000000000000003fc00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000e0730cef84fb49ff8d8d514f0ffe1124f999f1b00000000000000000000000061d857bd9554765d73058c93f9b2fa10c7c268da

Deployed ByteCode

0x6080604052600436106103385760003560e01c806370a08231116101b0578063bb57ad20116100ec578063e55096b011610095578063ee2912631161006f578063ee29126314610a25578063f2d9b35314610a3b578063f2fde38b14610a5b578063fccc281314610a7b57600080fd5b8063e55096b0146109cf578063e63a391f146109ef578063e893c37014610a0557600080fd5b8063caea1e69116100c6578063caea1e691461093a578063dd62ed3e14610950578063df64c87f1461099657600080fd5b8063bb57ad20146108dc578063bc063e1a146108f1578063c31c9c071461091a57600080fd5b806395d89b41116101595780639b61f1d0116101335780639b61f1d014610849578063a457c2d71461087c578063a9059cbb1461089c578063adf18693146108bc57600080fd5b806395d89b411461077a57806398c47e8c1461078f57806398dd215a1461082957600080fd5b80637994606d1161018a5780637994606d1461071c5780637f5bbb2c1461073c5780638da5cb5b1461075c57600080fd5b806370a08231146106b1578063715018a6146106e757806372bc5583146106fc57600080fd5b806326991cc81161027f578063412736571161022857806361582eaa1161020257806361582eaa146106225780636690864e146106425780636f741f2a146106625780636fcb97261461069b57600080fd5b806341273657146105a957806348c043af146105c95780634fbee193146105e957600080fd5b80633935ebf9116102595780633935ebf914610556578063395093511461057657806340c10f191461059657600080fd5b806326991cc8146104fa578063313ce5671461051a578063368519f31461053657600080fd5b80630ccf4c05116102e15780631a82094b116102bb5780631a82094b146104825780631c75f085146104a257806323b872dd146104da57600080fd5b80630ccf4c05146104175780630f569dad1461044d57806318160ddd1461046d57600080fd5b8063073a665511610312578063073a6655146103b1578063095ea7b3146103c75780630a99f2e8146103f757600080fd5b806301a6c43b1461034457806302da38871461036d57806306fdde031461038f57600080fd5b3661033f57005b600080fd5b34801561035057600080fd5b5061035a600c5481565b6040519081526020015b60405180910390f35b34801561037957600080fd5b5061038d6103883660046132fa565b610a91565b005b34801561039b57600080fd5b506103a4610ad8565b6040516103649190613313565b3480156103bd57600080fd5b5061035a60125481565b3480156103d357600080fd5b506103e76103e2366004613394565b610b6a565b6040519015158152602001610364565b34801561040357600080fd5b5061038d6104123660046133c0565b610b84565b34801561042357600080fd5b5061035a6104323660046133f9565b6001600160a01b031660009081526010602052604090205490565b34801561045957600080fd5b5061038d6104683660046132fa565b610b9a565b34801561047957600080fd5b5060025461035a565b34801561048e57600080fd5b5061038d61049d3660046132fa565b610ba7565b3480156104ae57600080fd5b506007546104c2906001600160a01b031681565b6040516001600160a01b039091168152602001610364565b3480156104e657600080fd5b506103e76104f5366004613416565b610bfc565b34801561050657600080fd5b50600a546104c2906001600160a01b031681565b34801561052657600080fd5b5060405160128152602001610364565b34801561054257600080fd5b5061035a610551366004613457565b610c1e565b34801561056257600080fd5b50600b546104c2906001600160a01b031681565b34801561058257600080fd5b506103e7610591366004613394565b610c80565b61038d6105a4366004613394565b610cbf565b3480156105b557600080fd5b5061038d6105c43660046133f9565b610cfe565b3480156105d557600080fd5b506006546104c2906001600160a01b031681565b3480156105f557600080fd5b506103e76106043660046133f9565b6001600160a01b03166000908152600e602052604090205460ff1690565b34801561062e57600080fd5b5061038d61063d3660046133f9565b610d12565b34801561064e57600080fd5b5061038d61065d3660046133f9565b610d23565b34801561066e57600080fd5b506103e761067d3660046133f9565b6001600160a01b03166000908152600f602052604090205460ff1690565b3480156106a757600080fd5b5061035a60085481565b3480156106bd57600080fd5b5061035a6106cc3660046133f9565b6001600160a01b031660009081526020819052604090205490565b3480156106f357600080fd5b5061038d610d34565b34801561070857600080fd5b5061038d6107173660046133f9565b610d48565b34801561072857600080fd5b5061038d610737366004613479565b610d8a565b34801561074857600080fd5b5061038d610757366004613499565b610da9565b34801561076857600080fd5b506005546001600160a01b03166104c2565b34801561078657600080fd5b506103a4610e48565b34801561079b57600080fd5b50600d546107ec9061ffff808216916201000081048216916401000000008204811691660100000000000081048216916801000000000000000082048116916a010000000000000000000090041686565b6040805161ffff978816815295871660208701529386169385019390935290841660608401528316608083015290911660a082015260c001610364565b34801561083557600080fd5b506014546104c2906001600160a01b031681565b34801561085557600080fd5b50600b546103e7907501000000000000000000000000000000000000000000900460ff1681565b34801561088857600080fd5b506103e7610897366004613394565b610e57565b3480156108a857600080fd5b506103e76108b7366004613394565b610f2b565b3480156108c857600080fd5b5061038d6108d73660046134b6565b610f39565b3480156108e857600080fd5b5061038d610f4b565b3480156108fd57600080fd5b506109076107d081565b60405161ffff9091168152602001610364565b34801561092657600080fd5b506009546104c2906001600160a01b031681565b34801561094657600080fd5b5061035a60135481565b34801561095c57600080fd5b5061035a61096b3660046133c0565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b3480156109a257600080fd5b506104c26109b13660046133f9565b6001600160a01b039081166000908152601160205260409020541690565b3480156109db57600080fd5b5061038d6109ea3660046134b6565b611002565b3480156109fb57600080fd5b5061090761271081565b348015610a1157600080fd5b5061038d610a203660046133f9565b611014565b348015610a3157600080fd5b5061035a60155481565b348015610a4757600080fd5b5061038d610a563660046133f9565b611025565b348015610a6757600080fd5b5061038d610a763660046133f9565b6110a7565b348015610a8757600080fd5b506104c261dead81565b610a9961114e565b60008111610ad3576040517f071308ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601555565b606060038054610ae7906134e4565b80601f0160208091040260200160405190810160405280929190818152602001828054610b13906134e4565b8015610b605780601f10610b3557610100808354040283529160200191610b60565b820191906000526020600020905b815481529060010190602001808311610b4357829003601f168201915b5050505050905090565b600033610b788185856111c2565b60019150505b92915050565b610b8c61114e565b610b96828261134e565b5050565b610ba261114e565b600c55565b610baf61114e565b600081118015610bc157506127108111155b610bf7576040517f071308ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601255565b6000610c09843384611400565b610c148484846114ca565b5060019392505050565b60006107ca610c2f846107cd613560565b610c65610c3f85623cda20613560565b610c4c87623cda29613560565b610c569190613577565b610c609087613560565b6117cb565b610c6f919061358a565b610c79919061359d565b9392505050565b3360008181526001602090815260408083206001600160a01b0387168452909152812054909190610b789082908690610cba908790613577565b6111c2565b610cc88161183b565b610cd282826119c8565b600b547501000000000000000000000000000000000000000000900460ff1615610b9657610b96610f4b565b610d0661114e565b610d0f81611aa1565b50565b610d1a61114e565b610d0f81611e6d565b610d2b61114e565b610d0f81612404565b610d3c61114e565b610d46600061247e565b565b610d5061114e565b600b80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b610d9261114e565b610d0f610da436839003830183613668565b6124e8565b610db161114e565b801515600b60159054906101000a900460ff16151503610dfd576040517f47d1eec500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b80549115157501000000000000000000000000000000000000000000027fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff909216919091179055565b606060048054610ae7906134e4565b3360008181526001602090815260408083206001600160a01b038716845290915281205490919083811015610f13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f00000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b610f2082868684036111c2565b506001949350505050565b600033610b788185856127ad565b610f4161114e565b610b9682826127bd565b601354600003610f6057610d46600080612895565b600061271061ffff16601254601354610f799190613560565b610f83919061359d565b9050600081601354610f95919061358a565b60006013556006549091506001600160a01b031615801590610fc157506007546001600160a01b031615155b15610fd057610b968282612895565b6040517f0b518a1700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61100a61114e565b610b968282612ad0565b61101c61114e565b610d0f81612ba0565b61102d61114e565b6001600160a01b03811661106d576040517f44c9a53100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601480547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6110af61114e565b6001600160a01b038116611145576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610f0a565b610d0f8161247e565b6005546001600160a01b03163314610d46576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610f0a565b6001600160a01b038316611257576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610f0a565b6001600160a01b0382166112ed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610f0a565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6001600160a01b03821661138e576040517f44c9a53100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0381811660008181526011602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169487169485179055519192917f67a3d1ca2003f80cceae34de5190ec082c3edf031890bd3bc449f906b5d5b79e9190a35050565b6001600160a01b038381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146114c457818110156114b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610f0a565b6114c484848484036111c2565b50505050565b60008111611504576040517fd761674700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b54600090819074010000000000000000000000000000000000000000900460ff1615801561154f5750600b547501000000000000000000000000000000000000000000900460ff165b600b5490915074010000000000000000000000000000000000000000900460ff1661162e576001600160a01b038581166000818152600e602090815260408083205494891680845281842054948452600f909252808320549183529091205460ff938416939283169291821691168180156115c8575080155b80156115d2575082155b80156115ec57506009546001600160a01b03898116911614155b156115ff57600d5461ffff169550611629565b80801561160a575083155b8015611614575082155b1561162957600d5462010000900461ffff1695505b505050505b80801561163b5750600082115b801561166057506001600160a01b0385166000908152600f602052604090205460ff16155b15611692576001600160a01b038416600090815260106020526040902054600c5481106116905761169085611e6d565b505b81156117b95760006127106116a78486613560565b6116b1919061359d565b905060006116bf828661358a565b600d54909150600090612710906116e290640100000000900461ffff1685613560565b6116ec919061359d565b9050801561170d576116fe818461358a565b925061170d8861dead83612c1a565b82156117a05761171e883085612c1a565b6001600160a01b0387166000908152600f602052604090205460ff1615611772576001600160a01b03871660009081526010602052604081208054859290611767908490613577565b909155506117a09050565b6001600160a01b0388166000908152601060205260408120805485929061179a908490613577565b90915550505b81156117b1576117b1888884612c1a565b5050506117c4565b6117c4858585612c1a565b5050505050565b6000600382111561182c57508060006117e560028361359d565b6117f0906001613577565b90505b818110156118265790508060028161180b818661359d565b6118159190613577565b61181f919061359d565b90506117f3565b50919050565b8115611836575060015b919050565b670de0b6b3a7640000601554826118529190613560565b61185c919061359d565b341015611895576040517f33be342e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6014546001600160a01b03166323b872dd336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152306024820152604481018490526064016020604051808303816000875af1158015611912573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119369190613707565b506014546040517f42966c68000000000000000000000000000000000000000000000000000000008152600481018390526001600160a01b03909116906342966c6890602401600060405180830381600087803b15801561199657600080fd5b505af11580156119aa573d6000803e3d6000fd5b5050505034601360008282546119c09190613577565b909155505050565b6001600160a01b038216611a38576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610f0a565b8060026000828254611a4a9190613577565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b6001600160a01b038116611ae1576040517f9299312300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600980547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316908117909155604080517fc45a015500000000000000000000000000000000000000000000000000000000815290516000929163c45a01559160048083019260209291908290030181865afa158015611b6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b929190613724565b90506001600160a01b038116611bd4576040517f4d22e3f200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600954604080517fef8ef56f00000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163ef8ef56f9160048083019260209291908290030181865afa158015611c37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c5b9190613724565b6040517fe6a439050000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0380831660248301529192509083169063e6a4390590604401602060405180830381865afa158015611cc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ce89190613724565b600a80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03929092169182179055611de7576040517fc9c653960000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03828116602483015283169063c9c65396906044016020604051808303816000875af1158015611d8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dae9190613724565b600a80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03929092169190911790555b600a546001600160a01b0316611e29576040517fc3aed2de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a546009546040516001600160a01b0392831692909116907fca394f95d8dbf1e8b2e76b9a8da90cacce1da85181a65508dab13212dc1df53b90600090a3505050565b600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790556001600160a01b03811660009081526010602052604081205490611ee5306001600160a01b031660009081526020819052604090205490565b6001600160a01b03808516600090815260116020526040902054919250168282106123d657600d54600090611f2890640100000000900461ffff16612710613741565b600d5461ffff91821691611f4791660100000000000090041686613560565b611f51919061359d565b9050611f5d818561358a565b60086000828254611f6e9190613577565b92505081905550600080866001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015611fb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fda9190613781565b506dffffffffffffffffffffffffffff1691506dffffffffffffffffffffffffffff169150600080306001600160a01b0316896001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa15801561204a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061206e9190613724565b6001600160a01b0316036120f1576120868486610c1e565b9150886001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120ea9190613724565b9050612162565b6120fb8386610c1e565b9150886001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa15801561213b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061215f9190613724565b90505b60008211801561218b5750600a546001600160a01b031660009081526020819052604090205415155b156123a357600954604080517fef8ef56f00000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163ef8ef56f9160048083019260209291908290030181865afa1580156121f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122179190613724565b6001600160a01b0316826001600160a01b031603612233575060015b600081156122425750476122c6565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa15801561229f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122c391906137d1565b90505b60006122d2858961358a565b90506122e284866000868d612e55565b600083156122fb576122f4834761358a565b905061238b565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015283906001600160a01b038716906370a0823190602401602060405180830381865afa15801561235a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061237e91906137d1565b612388919061358a565b90505b801561239e5761239e828287878e6130f6565b505050505b6001600160a01b038916600090815260106020526040812080548a92906123cb90849061358a565b909155505050505050505b5050600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690555050565b6001600160a01b038116612444576040517f44c9a53100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b600580546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516107d061ffff909116111561252b576040517f715be89100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107d061ffff16816020015161ffff161115612573576040517feff20f8700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008160a0015182608001518360600151846040015161259391906137ea565b61259d91906137ea565b6125a791906137ea565b905061ffff811615806125bf575061ffff8116612710145b6125f5576040517f98792f4c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8151600d805460208501516040808701516060880151608089015160a08a015161ffff9081166a0100000000000000000000027fffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffff9282166801000000000000000002929092167fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff9382166601000000000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffff95831664010000000002959095167fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff97831662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000090991692909a1691909117969096179490941696909617179490941691909117179055517fc9632f3cf45264c46361b5340b78f8ef11e561d580a40379a966e3aa8f1f6d7c906127a1908490600060c08201905061ffff8084511683528060208501511660208401528060408501511660408401528060608501511660608401528060808501511660808401528060a08501511660a08401525092915050565b60405180910390a15050565b6127b88383836114ca565b505050565b6001600160a01b0382166000908152600e602052604090205481151560ff909116151503612817576040517f47d1eec500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0382166000818152600e602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182527f3499bfcf9673677ba552f3fe2ea274ec7e6246da31c3c87e115b45a9b0db2efb91015b60405180910390a25050565b600854600c548110612a5557600954604080517fef8ef56f00000000000000000000000000000000000000000000000000000000815290514792612947926001600160a01b039091169163ef8ef56f916004808201926020929091908290030181865afa15801561290a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061292e9190613724565b60095484906000906001906001600160a01b0316612e55565b612951814761358a565b600d5490925060009061297c9061ffff660100000000000082048116916401000000009004166137ea565b61298890612710613741565b600d5461ffff918216916129a9916801000000000000000090041685613560565b6129b3919061359d565b905060006129c1828561358a565b60006008556006549091506001600160a01b03166108fc6129e28885613577565b6040518115909202916000818181858888f19350505050158015612a0a573d6000803e3d6000fd5b506007546001600160a01b03166108fc612a248784613577565b6040518115909202916000818181858888f19350505050158015612a4c573d6000803e3d6000fd5b50505050505050565b82156127b8576006546040516001600160a01b039091169084156108fc029085906000818181858888f19350505050158015612a95573d6000803e3d6000fd5b506007546040516001600160a01b039091169083156108fc029084906000818181858888f193505050501580156114c4573d6000803e3d6000fd5b6001600160a01b0382166000908152600f602052604090205481151560ff909116151503612b2a576040517f47d1eec500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0382166000818152600f602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182527f902b2ea0acdec5a260e398590d055fe29bd61ef5dd41e45db54a4cd98d5569e09101612889565b6001600160a01b038116612be0576040517f44c9a53100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600680547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6001600160a01b038316612cb0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610f0a565b6001600160a01b038216612d46576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610f0a565b6001600160a01b03831660009081526020819052604090205481811015612def576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610f0a565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36114c4565b6040805160028082526060820183526000926020830190803683370190505090503081600081518110612e8a57612e8a613805565b60200260200101906001600160a01b031690816001600160a01b0316815250508581600181518110612ebe57612ebe613805565b60200260200101906001600160a01b031690816001600160a01b031681525050612ee93083876111c2565b8215612f65576001600160a01b03821663791ac94786868430612f0e42610258613577565b6040518663ffffffff1660e01b8152600401612f2e959493929190613834565b600060405180830381600087803b158015612f4857600080fd5b505af1158015612f5c573d6000803e3d6000fd5b505050506130ee565b600b546000906001600160a01b03808516916338ed17399189918991879116612f9042610258613577565b6040518663ffffffff1660e01b8152600401612fb0959493929190613834565b6000604051808303816000875af1158015612fcf573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261301591908101906138a5565b9050866001600160a01b03166323b872dd600b60009054906101000a90046001600160a01b0316308460018151811061305057613050613805565b60209081029190910101516040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064016020604051808303816000875af11580156130c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130eb9190613707565b50505b505050505050565b6131013082876111c2565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301526024820186905284169063095ea7b3906044016020604051808303816000875af1158015613169573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061318d9190613707565b50811561324057600b546040517ff305d7190000000000000000000000000000000000000000000000000000000081523060048201526024810187905260006044820181905260648201526001600160a01b0391821660848201524260a48201529082169063f305d71990869060c40160606040518083038185885af115801561321b573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906117b1919061394b565b600b546040517fe8e337000000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038581166024830152604482018890526064820187905260006084830181905260a483015291821660c48201524260e48201529082169063e8e3370090610104016060604051808303816000875af11580156132d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130eb919061394b565b60006020828403121561330c57600080fd5b5035919050565b600060208083528351808285015260005b8181101561334057858101830151858201604001528201613324565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b6001600160a01b0381168114610d0f57600080fd5b600080604083850312156133a757600080fd5b82356133b28161337f565b946020939093013593505050565b600080604083850312156133d357600080fd5b82356133de8161337f565b915060208301356133ee8161337f565b809150509250929050565b60006020828403121561340b57600080fd5b8135610c798161337f565b60008060006060848603121561342b57600080fd5b83356134368161337f565b925060208401356134468161337f565b929592945050506040919091013590565b6000806040838503121561346a57600080fd5b50508035926020909101359150565b600060c0828403121561182657600080fd5b8015158114610d0f57600080fd5b6000602082840312156134ab57600080fd5b8135610c798161348b565b600080604083850312156134c957600080fd5b82356134d48161337f565b915060208301356133ee8161348b565b600181811c908216806134f857607f821691505b602082108103611826577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417610b7e57610b7e613531565b80820180821115610b7e57610b7e613531565b81810381811115610b7e57610b7e613531565b6000826135d3577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561364e5761364e6135d8565b604052919050565b803561ffff8116811461183657600080fd5b600060c0828403121561367a57600080fd5b60405160c0810181811067ffffffffffffffff8211171561369d5761369d6135d8565b6040526136a983613656565b81526136b760208401613656565b60208201526136c860408401613656565b60408201526136d960608401613656565b60608201526136ea60808401613656565b60808201526136fb60a08401613656565b60a08201529392505050565b60006020828403121561371957600080fd5b8151610c798161348b565b60006020828403121561373657600080fd5b8151610c798161337f565b61ffff82811682821603908082111561375c5761375c613531565b5092915050565b80516dffffffffffffffffffffffffffff8116811461183657600080fd5b60008060006060848603121561379657600080fd5b61379f84613763565b92506137ad60208501613763565b9150604084015163ffffffff811681146137c657600080fd5b809150509250925092565b6000602082840312156137e357600080fd5b5051919050565b61ffff81811683821601908082111561375c5761375c613531565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060a082018783526020878185015260a0604085015281875180845260c086019150828901935060005b818110156138845784516001600160a01b03168352938301939183019160010161385f565b50506001600160a01b03969096166060850152505050608001529392505050565b600060208083850312156138b857600080fd5b825167ffffffffffffffff808211156138d057600080fd5b818501915085601f8301126138e457600080fd5b8151818111156138f6576138f66135d8565b8060051b9150613907848301613607565b818152918301840191848101908884111561392157600080fd5b938501935b8385101561393f57845182529385019390850190613926565b98975050505050505050565b60008060006060848603121561396057600080fd5b835192506020840151915060408401519050925092509256fea26469706673582212201e4087c73a0446fa08c47f751152a4ca88e3f6cc823e4e214499b8a75499f9d564736f6c63430008140033