false
false
0

Contract Address Details

0x1c0D0e26862d0660287A6A88E68A7755B2998F2B

Token
Cyberwoman of Flare (CYOF)
Creator
0x97496c–a4f942 at 0x9673e2–047e9a
Balance
0 FLR
Tokens
Fetching tokens...
Transactions
487 Transactions
Transfers
5 Transfers
Gas Used
52,154,197
Last Balance Update
31490677
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
ERC404XENOS




Optimization enabled
true
Compiler version
v0.8.25+commit.b61c2a91




Optimization runs
200
EVM Version
london




Verified at
2024-05-20T21:59:30.788191Z

Constructor Arguments

0x00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000001f400000000000000000000000097496c270e57cd8131bf9a7c23922c771da4f94200000000000000000000000097496c270e57cd8131bf9a7c23922c771da4f942000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000134379626572776f6d616e206f6620466c61726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000443594f4600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004d68747470733a2f2f697066732e696f2f697066732f516d5937515a6875566779664b31586a736b6436785458614b356156635561437678707362586675645748624b732f4d657461646174612f00000000000000000000000000000000000000

Arg [0] (string) : Cyberwoman of Flare
Arg [1] (string) : CYOF
Arg [2] (uint8) : 18
Arg [3] (uint256) : 500
Arg [4] (address) : 0x97496c270e57cd8131bf9a7c23922c771da4f942
Arg [5] (address) : 0x97496c270e57cd8131bf9a7c23922c771da4f942
Arg [6] (string) : https://ipfs.io/ipfs/QmY7QZhuVgyfK1Xjskd6xTXaK5aVcUaCvxpsbXfudWHbKs/Metadata/

              

Contract source code

// File: @uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router01.sol

pragma solidity >=0.6.2;

interface IUniswapV2Router01 {
    function factory() external pure returns (address);
    function WETH() external pure returns (address);

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

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

// File: @uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol

pragma solidity >=0.6.2;


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

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

// File: Xenos ERC404/lib/ERC20Events.sol


pragma solidity ^0.8.20;

library ERC20Events {
  event Approval(address indexed owner, address indexed spender, uint256 value);
  event Transfer(address indexed from, address indexed to, uint256 amount);
}

// File: Xenos ERC404/lib/ERC721Events.sol


pragma solidity ^0.8.20;

library ERC721Events {
  event ApprovalForAll(
    address indexed owner,
    address indexed operator,
    bool approved
  );
  event Approval(
    address indexed owner,
    address indexed spender,
    uint256 indexed id
  );
  event Transfer(address indexed from, address indexed to, uint256 indexed id);
}

// File: Xenos ERC404/lib/DoubleEndedQueue.sol


// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/DoubleEndedQueue.sol)
// Modified by Pandora Labs to support native uint256 operations
pragma solidity ^0.8.20;

/**
 * @dev A sequence of items with the ability to efficiently push and pop items (i.e. insert and remove) on both ends of
 * the sequence (called front and back). Among other access patterns, it can be used to implement efficient LIFO and
 * FIFO queues. Storage use is optimized, and all operations are O(1) constant time. This includes {clear}, given that
 * the existing queue contents are left in storage.
 *
 * The struct is called `Uint256Deque`. This data structure can only be used in storage, and not in memory.
 *
 * ```solidity
 * DoubleEndedQueue.Uint256Deque queue;
 * ```
 */
library DoubleEndedQueue {
  /**
   * @dev An operation (e.g. {front}) couldn't be completed due to the queue being empty.
   */
  error QueueEmpty();

  /**
   * @dev A push operation couldn't be completed due to the queue being full.
   */
  error QueueFull();

  /**
   * @dev An operation (e.g. {at}) couldn't be completed due to an index being out of bounds.
   */
  error QueueOutOfBounds();

  /**
   * @dev Indices are 128 bits so begin and end are packed in a single storage slot for efficient access.
   *
   * Struct members have an underscore prefix indicating that they are "private" and should not be read or written to
   * directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and
   * lead to unexpected behavior.
   *
   * The first item is at data[begin] and the last item is at data[end - 1]. This range can wrap around.
   */
  struct Uint256Deque {
    uint128 _begin;
    uint128 _end;
    mapping(uint128 index => uint256) _data;
  }

  /**
   * @dev Inserts an item at the end of the queue.
   *
   * Reverts with {QueueFull} if the queue is full.
   */
  function pushBack(Uint256Deque storage deque, uint256 value) internal {
    unchecked {
      uint128 backIndex = deque._end;
      if (backIndex + 1 == deque._begin) revert QueueFull();
      deque._data[backIndex] = value;
      deque._end = backIndex + 1;
    }
  }

  /**
   * @dev Removes the item at the end of the queue and returns it.
   *
   * Reverts with {QueueEmpty} if the queue is empty.
   */
  function popBack(
    Uint256Deque storage deque
  ) internal returns (uint256 value) {
    unchecked {
      uint128 backIndex = deque._end;
      if (backIndex == deque._begin) revert QueueEmpty();
      --backIndex;
      value = deque._data[backIndex];
      delete deque._data[backIndex];
      deque._end = backIndex;
    }
  }

  /**
   * @dev Inserts an item at the beginning of the queue.
   *
   * Reverts with {QueueFull} if the queue is full.
   */
  function pushFront(Uint256Deque storage deque, uint256 value) internal {
    unchecked {
      uint128 frontIndex = deque._begin - 1;
      if (frontIndex == deque._end) revert QueueFull();
      deque._data[frontIndex] = value;
      deque._begin = frontIndex;
    }
  }

  /**
   * @dev Removes the item at the beginning of the queue and returns it.
   *
   * Reverts with `QueueEmpty` if the queue is empty.
   */
  function popFront(
    Uint256Deque storage deque
  ) internal returns (uint256 value) {
    unchecked {
      uint128 frontIndex = deque._begin;
      if (frontIndex == deque._end) revert QueueEmpty();
      value = deque._data[frontIndex];
      delete deque._data[frontIndex];
      deque._begin = frontIndex + 1;
    }
  }

  /**
   * @dev Returns the item at the beginning of the queue.
   *
   * Reverts with `QueueEmpty` if the queue is empty.
   */
  function front(
    Uint256Deque storage deque
  ) internal view returns (uint256 value) {
    if (empty(deque)) revert QueueEmpty();
    return deque._data[deque._begin];
  }

  /**
   * @dev Returns the item at the end of the queue.
   *
   * Reverts with `QueueEmpty` if the queue is empty.
   */
  function back(
    Uint256Deque storage deque
  ) internal view returns (uint256 value) {
    if (empty(deque)) revert QueueEmpty();
    unchecked {
      return deque._data[deque._end - 1];
    }
  }

  /**
   * @dev Return the item at a position in the queue given by `index`, with the first item at 0 and last item at
   * `length(deque) - 1`.
   *
   * Reverts with `QueueOutOfBounds` if the index is out of bounds.
   */
  function at(
    Uint256Deque storage deque,
    uint256 index
  ) internal view returns (uint256 value) {
    if (index >= length(deque)) revert QueueOutOfBounds();
    // By construction, length is a uint128, so the check above ensures that index can be safely downcast to uint128
    unchecked {
      return deque._data[deque._begin + uint128(index)];
    }
  }

  /**
   * @dev Resets the queue back to being empty.
   *
   * NOTE: The current items are left behind in storage. This does not affect the functioning of the queue, but misses
   * out on potential gas refunds.
   */
  function clear(Uint256Deque storage deque) internal {
    deque._begin = 0;
    deque._end = 0;
  }

  /**
   * @dev Returns the number of items in the queue.
   */
  function length(Uint256Deque storage deque) internal view returns (uint256) {
    unchecked {
      return uint256(deque._end - deque._begin);
    }
  }

  /**
   * @dev Returns true if the queue is empty.
   */
  function empty(Uint256Deque storage deque) internal view returns (bool) {
    return deque._end == deque._begin;
  }
}

// File: @openzeppelin/contracts/utils/introspection/IERC165.sol


// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

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

// File: @openzeppelin/contracts/interfaces/IERC165.sol


// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)

pragma solidity ^0.8.20;


// File: Xenos ERC404/interfaces/IERC404.sol

pragma solidity ^0.8.20;


interface IERC404 is IERC165 {
  error NotFound();
  error InvalidTokenId();
  error AlreadyExists();
  error InvalidRecipient();
  error InvalidSender();
  error InvalidSpender();
  error InvalidOperator();
  error UnsafeRecipient();
  error RecipientIsERC721TransferExempt();
  error Unauthorized();
  error InsufficientAllowance();
  error DecimalsTooLow();
  error PermitDeadlineExpired();
  error InvalidSigner();
  error InvalidApproval();
  error OwnedIndexOverflow();
  error MintLimitReached();
  error InvalidExemption();

  function name() external view returns (string memory);
  function symbol() external view returns (string memory);
  function decimals() external view returns (uint8);
  function totalSupply() external view returns (uint256);
  function erc20TotalSupply() external view returns (uint256);
  function erc721TotalSupply() external view returns (uint256);
  function balanceOf(address owner_) external view returns (uint256);
  function erc721BalanceOf(address owner_) external view returns (uint256);
  function erc20BalanceOf(address owner_) external view returns (uint256);
  function erc721TransferExempt(address account_) external view returns (bool);
  function isApprovedForAll(
    address owner_,
    address operator_
  ) external view returns (bool);
  function allowance(
    address owner_,
    address spender_
  ) external view returns (uint256);
  function owned(address owner_) external view returns (uint256[] memory);
  function ownerOf(uint256 id_) external view returns (address erc721Owner);
  function tokenURI(uint256 id_) external view returns (string memory);
  function approve(
    address spender_,
    uint256 valueOrId_
  ) external returns (bool);
  function erc20Approve(
    address spender_,
    uint256 value_
  ) external returns (bool);
  function erc721Approve(address spender_, uint256 id_) external;
  function setApprovalForAll(address operator_, bool approved_) external;
  function transferFrom(
    address from_,
    address to_,
    uint256 valueOrId_
  ) external returns (bool);
  function erc20TransferFrom(
    address from_,
    address to_,
    uint256 value_
  ) external returns (bool);
  function erc721TransferFrom(address from_, address to_, uint256 id_) external;
  function transfer(address to_, uint256 amount_) external returns (bool);
  function getERC721QueueLength() external view returns (uint256);
  function getERC721TokensInQueue(
    uint256 start_,
    uint256 count_
  ) external view returns (uint256[] memory);
  function setSelfERC721TransferExempt(bool state_) external;
  function safeTransferFrom(address from_, address to_, uint256 id_) external;
  function safeTransferFrom(
    address from_,
    address to_,
    uint256 id_,
    bytes calldata data_
  ) external;
  function DOMAIN_SEPARATOR() external view returns (bytes32);
  function permit(
    address owner_,
    address spender_,
    uint256 value_,
    uint256 deadline_,
    uint8 v_,
    bytes32 r_,
    bytes32 s_
  ) external;
}

// File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol


// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.20;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be
     * reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

// File: @openzeppelin/contracts/interfaces/IERC721Receiver.sol


// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC721Receiver.sol)

pragma solidity ^0.8.20;


// File: Xenos ERC404/implementation/ERC404.sol


pragma solidity ^0.8.20;







abstract contract ERC404 is IERC404 {
    using DoubleEndedQueue for DoubleEndedQueue.Uint256Deque;

    DoubleEndedQueue.Uint256Deque private _storedERC721Ids;

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    uint256 public immutable units;

    uint256 public totalSupply;

    uint256 public minted;

    uint256 internal immutable _INITIAL_CHAIN_ID;

    bytes32 internal immutable _INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    mapping(uint256 => address) public getApproved;

    mapping(address => mapping(address => bool)) public isApprovedForAll;

    mapping(uint256 => uint256) internal _ownedData;

    mapping(address => uint256[]) internal _owned;

    mapping(address => bool) internal _erc721TransferExempt;

    mapping(address => uint256) public nonces;

    uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;

    uint256 private constant _BITMASK_OWNED_INDEX = ((1 << 96) - 1) << 160;

    uint256 public constant ID_ENCODING_PREFIX = 1 << 255;

    constructor(
        string memory name_,
        string memory symbol_,
        uint8 decimals_
    ) {
        name = name_;
        symbol = symbol_;

        if (decimals_ < 18) {
            revert DecimalsTooLow();
        }

        decimals = decimals_;
        units = 10**decimals;

        // EIP-2612 initialization
        _INITIAL_CHAIN_ID = block.chainid;
        _INITIAL_DOMAIN_SEPARATOR = _computeDomainSeparator();
    }

    function ownerOf(uint256 id_)
        public
        view
        virtual
        returns (address erc721Owner)
    {
        erc721Owner = _getOwnerOf(id_);

        if (!_isValidTokenId(id_)) {
            revert InvalidTokenId();
        }

        if (erc721Owner == address(0)) {
            revert NotFound();
        }
    }

    function owned(address owner_)
        public
        view
        virtual
        returns (uint256[] memory)
    {
        return _owned[owner_];
    }

    function erc721BalanceOf(address owner_)
        public
        view
        virtual
        returns (uint256)
    {
        return _owned[owner_].length;
    }

    function erc20BalanceOf(address owner_)
        public
        view
        virtual
        returns (uint256)
    {
        return balanceOf[owner_];
    }

    function erc20TotalSupply() public view virtual returns (uint256) {
        return totalSupply;
    }

    function erc721TotalSupply() public view virtual returns (uint256) {
        return minted;
    }

    function getERC721QueueLength() public view virtual returns (uint256) {
        return _storedERC721Ids.length();
    }

    function getERC721TokensInQueue(uint256 start_, uint256 count_)
        public
        view
        virtual
        returns (uint256[] memory)
    {
        uint256[] memory tokensInQueue = new uint256[](count_);

        for (uint256 i = start_; i < start_ + count_; ) {
            tokensInQueue[i - start_] = _storedERC721Ids.at(i);

            unchecked {
                ++i;
            }
        }

        return tokensInQueue;
    }

    function approve(address spender_, uint256 valueOrId_)
        public
        virtual
        returns (bool)
    {
        if (_isValidTokenId(valueOrId_)) {
            erc721Approve(spender_, valueOrId_);
        } else {
            return erc20Approve(spender_, valueOrId_);
        }

        return true;
    }

    function erc721Approve(address spender_, uint256 id_) public virtual {
        address erc721Owner = _getOwnerOf(id_);

        if (
            msg.sender != erc721Owner &&
            !isApprovedForAll[erc721Owner][msg.sender]
        ) {
            revert Unauthorized();
        }

        getApproved[id_] = spender_;

        emit ERC721Events.Approval(erc721Owner, spender_, id_);
    }

    function erc20Approve(address spender_, uint256 value_)
        public
        virtual
        returns (bool)
    {
        if (spender_ == address(0)) {
            revert InvalidSpender();
        }

        allowance[msg.sender][spender_] = value_;

        emit ERC20Events.Approval(msg.sender, spender_, value_);

        return true;
    }

    function setApprovalForAll(address operator_, bool approved_)
        public
        virtual
    {
        if (operator_ == address(0)) {
            revert InvalidOperator();
        }
        isApprovedForAll[msg.sender][operator_] = approved_;
        emit ERC721Events.ApprovalForAll(msg.sender, operator_, approved_);
    }

    function transferFrom(
        address from_,
        address to_,
        uint256 valueOrId_
    ) public virtual returns (bool) {
        if (_isValidTokenId(valueOrId_)) {
            erc721TransferFrom(from_, to_, valueOrId_);
        } else {
            return erc20TransferFrom(from_, to_, valueOrId_);
        }

        return true;
    }

    function erc721TransferFrom(
        address from_,
        address to_,
        uint256 id_
    ) public virtual {
        if (from_ == address(0)) {
            revert InvalidSender();
        }

        if (to_ == address(0)) {
            revert InvalidRecipient();
        }

        if (from_ != _getOwnerOf(id_)) {
            revert Unauthorized();
        }

        if (
            msg.sender != from_ &&
            !isApprovedForAll[from_][msg.sender] &&
            msg.sender != getApproved[id_]
        ) {
            revert Unauthorized();
        }

        if (erc721TransferExempt(to_)) {
            revert RecipientIsERC721TransferExempt();
        }
        _transferERC20(from_, to_, units);
        _transferERC721(from_, to_, id_);
    }

    function erc20TransferFrom(
        address from_,
        address to_,
        uint256 value_
    ) public virtual returns (bool) {
        if (from_ == address(0)) {
            revert InvalidSender();
        }

        if (to_ == address(0)) {
            revert InvalidRecipient();
        }

        uint256 allowed = allowance[from_][msg.sender];

        if (allowed != type(uint256).max) {
            allowance[from_][msg.sender] = allowed - value_;
        }

        return _transferERC20WithERC721(from_, to_, value_);
    }

    function transfer(address to_, uint256 value_)
        public
        virtual
        returns (bool)
    {
        if (to_ == address(0)) {
            revert InvalidRecipient();
        }

        return _transferERC20WithERC721(msg.sender, to_, value_);
    }

    function safeTransferFrom(
        address from_,
        address to_,
        uint256 id_
    ) public virtual {
        safeTransferFrom(from_, to_, id_, "");
    }

    function safeTransferFrom(
        address from_,
        address to_,
        uint256 id_,
        bytes memory data_
    ) public virtual {
        if (!_isValidTokenId(id_)) {
            revert InvalidTokenId();
        }

        transferFrom(from_, to_, id_);

        if (
            to_.code.length != 0 &&
            IERC721Receiver(to_).onERC721Received(
                msg.sender,
                from_,
                id_,
                data_
            ) !=
            IERC721Receiver.onERC721Received.selector
        ) {
            revert UnsafeRecipient();
        }
    }

    function permit(
        address owner_,
        address spender_,
        uint256 value_,
        uint256 deadline_,
        uint8 v_,
        bytes32 r_,
        bytes32 s_
    ) public virtual {
        if (deadline_ < block.timestamp) {
            revert PermitDeadlineExpired();
        }

        if (_isValidTokenId(value_)) {
            revert InvalidApproval();
        }

        if (spender_ == address(0)) {
            revert InvalidSpender();
        }

        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner_,
                                spender_,
                                value_,
                                nonces[owner_]++,
                                deadline_
                            )
                        )
                    )
                ),
                v_,
                r_,
                s_
            );

            if (recoveredAddress == address(0) || recoveredAddress != owner_) {
                revert InvalidSigner();
            }

            allowance[recoveredAddress][spender_] = value_;
        }

        emit ERC20Events.Approval(owner_, spender_, value_);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return
            block.chainid == _INITIAL_CHAIN_ID
                ? _INITIAL_DOMAIN_SEPARATOR
                : _computeDomainSeparator();
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        returns (bool)
    {
        return
            interfaceId == type(IERC404).interfaceId ||
            interfaceId == type(IERC165).interfaceId;
    }

    function setSelfERC721TransferExempt(bool state_) public virtual {
        _setERC721TransferExempt(msg.sender, state_);
    }

    function erc721TransferExempt(address target_)
        public
        view
        virtual
        returns (bool)
    {
        return target_ == address(0) || _erc721TransferExempt[target_];
    }

    function _isValidTokenId(uint256 id_) internal pure returns (bool) {
        return id_ > ID_ENCODING_PREFIX && id_ != type(uint256).max;
    }

    function _computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256(
                        "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
                    ),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    function _transferERC20(
        address from_,
        address to_,
        uint256 value_
    ) internal virtual {
        if (from_ == address(0)) {
            totalSupply += value_;
        } else {
            balanceOf[from_] -= value_;
        }

        unchecked {
            balanceOf[to_] += value_;
        }

        emit ERC20Events.Transfer(from_, to_, value_);
    }

    function _transferERC721(
        address from_,
        address to_,
        uint256 id_
    ) internal virtual {
        if (from_ != address(0)) {
            delete getApproved[id_];

            uint256 updatedId = _owned[from_][_owned[from_].length - 1];
            if (updatedId != id_) {
                uint256 updatedIndex = _getOwnedIndex(id_);
                _owned[from_][updatedIndex] = updatedId;
                _setOwnedIndex(updatedId, updatedIndex);
            }

            _owned[from_].pop();
        }

        if (to_ != address(0)) {
            _setOwnerOf(id_, to_);
            _owned[to_].push(id_);
            _setOwnedIndex(id_, _owned[to_].length - 1);
        } else {
            delete _ownedData[id_];
        }

        emit ERC721Events.Transfer(from_, to_, id_);
    }

    function _transferERC20WithERC721(
        address from_,
        address to_,
        uint256 value_
    ) internal virtual returns (bool) {
        uint256 erc20BalanceOfSenderBefore = erc20BalanceOf(from_);
        uint256 erc20BalanceOfReceiverBefore = erc20BalanceOf(to_);

        _transferERC20(from_, to_, value_);

        bool isFromERC721TransferExempt = erc721TransferExempt(from_);
        bool isToERC721TransferExempt = erc721TransferExempt(to_);

        if (isFromERC721TransferExempt && isToERC721TransferExempt) {} else if (
            isFromERC721TransferExempt
        ) {
            uint256 tokensToRetrieveOrMint = (balanceOf[to_] / units) -
                (erc20BalanceOfReceiverBefore / units);
            for (uint256 i = 0; i < tokensToRetrieveOrMint; ) {
                _retrieveOrMintERC721(to_);
                unchecked {
                    ++i;
                }
            }
        } else if (isToERC721TransferExempt) {
            uint256 tokensToWithdrawAndStore = (erc20BalanceOfSenderBefore /
                units) - (balanceOf[from_] / units);
            for (uint256 i = 0; i < tokensToWithdrawAndStore; ) {
                _withdrawAndStoreERC721(from_);
                unchecked {
                    ++i;
                }
            }
        } else {
            uint256 nftsToTransfer = value_ / units;
            for (uint256 i = 0; i < nftsToTransfer; ) {
                uint256 indexOfLastToken = _owned[from_].length - 1;
                uint256 tokenId = _owned[from_][indexOfLastToken];
                _transferERC721(from_, to_, tokenId);
                unchecked {
                    ++i;
                }
            }

            if (
                erc20BalanceOfSenderBefore /
                    units -
                    erc20BalanceOf(from_) /
                    units >
                nftsToTransfer
            ) {
                _withdrawAndStoreERC721(from_);
            }

            if (
                erc20BalanceOf(to_) /
                    units -
                    erc20BalanceOfReceiverBefore /
                    units >
                nftsToTransfer
            ) {
                _retrieveOrMintERC721(to_);
            }
        }

        return true;
    }

    function _mintERC20(address to_, uint256 value_) internal virtual {
        if (to_ == address(0)) {
            revert InvalidRecipient();
        }

        if (totalSupply + value_ > ID_ENCODING_PREFIX) {
            revert MintLimitReached();
        }

        _transferERC20WithERC721(address(0), to_, value_);
    }

    function _retrieveOrMintERC721(address to_) internal virtual {
        if (to_ == address(0)) {
            revert InvalidRecipient();
        }

        uint256 id;

        if (!_storedERC721Ids.empty()) {
            id = _storedERC721Ids.popBack();
        } else {
            ++minted;

            if (minted == type(uint256).max) {
                revert MintLimitReached();
            }

            id = ID_ENCODING_PREFIX + minted;
        }

        address erc721Owner = _getOwnerOf(id);

        if (erc721Owner != address(0)) {
            revert AlreadyExists();
        }

        _transferERC721(erc721Owner, to_, id);
    }

    function _withdrawAndStoreERC721(address from_) internal virtual {
        if (from_ == address(0)) {
            revert InvalidSender();
        }

        uint256 id = _owned[from_][_owned[from_].length - 1];

        _transferERC721(from_, address(0), id);

        _storedERC721Ids.pushFront(id);
    }

    function _setERC721TransferExempt(address target_, bool state_)
        internal
        virtual
    {
        if (target_ == address(0)) {
            revert InvalidExemption();
        }

        if (state_) {
            _clearERC721Balance(target_);
        } else {
            _reinstateERC721Balance(target_);
        }

        _erc721TransferExempt[target_] = state_;
    }

    function _reinstateERC721Balance(address target_) private {
        uint256 expectedERC721Balance = erc20BalanceOf(target_) / units;
        uint256 actualERC721Balance = erc721BalanceOf(target_);

        for (uint256 i = 0; i < expectedERC721Balance - actualERC721Balance; ) {
            _retrieveOrMintERC721(target_);
            unchecked {
                ++i;
            }
        }
    }

    function _clearERC721Balance(address target_) private {
        uint256 erc721Balance = erc721BalanceOf(target_);

        for (uint256 i = 0; i < erc721Balance; ) {
            _withdrawAndStoreERC721(target_);
            unchecked {
                ++i;
            }
        }
    }

    function _getOwnerOf(uint256 id_)
        internal
        view
        virtual
        returns (address ownerOf_)
    {
        uint256 data = _ownedData[id_];

        assembly {
            ownerOf_ := and(data, _BITMASK_ADDRESS)
        }
    }

    function _setOwnerOf(uint256 id_, address owner_) internal virtual {
        uint256 data = _ownedData[id_];

        assembly {
            data := add(
                and(data, _BITMASK_OWNED_INDEX),
                and(owner_, _BITMASK_ADDRESS)
            )
        }

        _ownedData[id_] = data;
    }

    function _getOwnedIndex(uint256 id_)
        internal
        view
        virtual
        returns (uint256 ownedIndex_)
    {
        uint256 data = _ownedData[id_];

        assembly {
            ownedIndex_ := shr(160, data)
        }
    }

    function _setOwnedIndex(uint256 id_, uint256 index_) internal virtual {
        uint256 data = _ownedData[id_];

        if (index_ > _BITMASK_OWNED_INDEX >> 160) {
            revert OwnedIndexOverflow();
        }

        assembly {
            data := add(
                and(data, _BITMASK_ADDRESS),
                and(shl(160, index_), _BITMASK_OWNED_INDEX)
            )
        }

        _ownedData[id_] = data;
    }
}

// File: Xenos ERC404/extensions/ERC404UNIV2Exempt.sol


pragma solidity ^0.8.20;



abstract contract ERC404UniswapV2Exempt is ERC404 {
  constructor(address uniswapV2Router_) {
    IUniswapV2Router02 uniswapV2RouterContract = IUniswapV2Router02(
      uniswapV2Router_
    );

    _setERC721TransferExempt(uniswapV2Router_, true);

    address uniswapV2Pair = _getUniswapV2Pair(
      uniswapV2RouterContract.factory(),
      uniswapV2RouterContract.WETH()
    );

    _setERC721TransferExempt(uniswapV2Pair, true);
  }

  function _getUniswapV2Pair(
    address uniswapV2Factory_,
    address weth_
  ) private view returns (address) {
    address thisAddress = address(this);

    (address token0, address token1) = thisAddress < weth_
      ? (thisAddress, weth_)
      : (weth_, thisAddress);

    return
      address(
        uint160(
          uint256(
            keccak256(
              abi.encodePacked(
                hex"ff",
                uniswapV2Factory_,
                keccak256(abi.encodePacked(token0, token1)),
                hex"ba8a75b5eef0e9f9b7cd66d6e68f92a973ecff5ac2db0dec5920626f18114a10"
              )
            )
          )
        )
      );
  }
}
// File: @openzeppelin/contracts/utils/math/SignedMath.sol


// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

// File: @openzeppelin/contracts/utils/math/Math.sol


// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
     * Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0 = x * y; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
            // works in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

// File: @openzeppelin/contracts/utils/Strings.sol


// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)

pragma solidity ^0.8.20;



/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant HEX_DIGITS = "0123456789abcdef";
    uint8 private constant ADDRESS_LENGTH = 20;

    /**
     * @dev The `value` string doesn't fit in the specified `length`.
     */
    error StringsInsufficientHexLength(uint256 value, uint256 length);

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toStringSigned(int256 value) internal pure returns (string memory) {
        return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

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

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
     * representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

// File: @openzeppelin/contracts/utils/Context.sol


// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @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;
    }
}

// File: @openzeppelin/contracts/access/Ownable.sol


// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;


/**
 * @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.
 *
 * The initial owner is set to the address provided by the deployer. 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;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

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

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @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 {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @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 {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

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

// File: Xenos ERC404/ERC404XENOS.sol


pragma solidity ^0.8.25;





contract ERC404XENOS is Ownable, ERC404, ERC404UniswapV2Exempt {

    string public _uri;

    constructor(
        string memory name_,
        string memory symbol_,
        uint8 decimals_,
        uint256 maxTotalSupplyERC721_,
        address initialOwner_,
        address initialMintRecipient_,
        string memory uri
    )
        ERC404(name_, symbol_, decimals_)
        Ownable(initialOwner_)
        ERC404UniswapV2Exempt(
            address(0x15e18B3b61D7ad70c05cb8c89C5f87DBf69C1939)
        ) //Xenos Router
    {
        _uri = uri;
        _setERC721TransferExempt(initialMintRecipient_, true);
        _mintERC20(initialMintRecipient_, maxTotalSupplyERC721_ * units);
    }

    function setURI(string memory uri) external onlyOwner{
        _uri = uri;
    }

    function tokenURI(uint256 id_)
        public
        view
        override
        returns (string memory)
    {
        return
            string.concat(_uri, Strings.toString(id_));
    }

    function setERC721TransferExempt(address account_, bool value_)
        external
        onlyOwner
    {
        _setERC721TransferExempt(account_, value_);
    }
}
        

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"string","name":"name_","internalType":"string"},{"type":"string","name":"symbol_","internalType":"string"},{"type":"uint8","name":"decimals_","internalType":"uint8"},{"type":"uint256","name":"maxTotalSupplyERC721_","internalType":"uint256"},{"type":"address","name":"initialOwner_","internalType":"address"},{"type":"address","name":"initialMintRecipient_","internalType":"address"},{"type":"string","name":"uri","internalType":"string"}]},{"type":"error","name":"AlreadyExists","inputs":[]},{"type":"error","name":"DecimalsTooLow","inputs":[]},{"type":"error","name":"InsufficientAllowance","inputs":[]},{"type":"error","name":"InvalidApproval","inputs":[]},{"type":"error","name":"InvalidExemption","inputs":[]},{"type":"error","name":"InvalidOperator","inputs":[]},{"type":"error","name":"InvalidRecipient","inputs":[]},{"type":"error","name":"InvalidSender","inputs":[]},{"type":"error","name":"InvalidSigner","inputs":[]},{"type":"error","name":"InvalidSpender","inputs":[]},{"type":"error","name":"InvalidTokenId","inputs":[]},{"type":"error","name":"MintLimitReached","inputs":[]},{"type":"error","name":"NotFound","inputs":[]},{"type":"error","name":"OwnableInvalidOwner","inputs":[{"type":"address","name":"owner","internalType":"address"}]},{"type":"error","name":"OwnableUnauthorizedAccount","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"error","name":"OwnedIndexOverflow","inputs":[]},{"type":"error","name":"PermitDeadlineExpired","inputs":[]},{"type":"error","name":"QueueEmpty","inputs":[]},{"type":"error","name":"QueueFull","inputs":[]},{"type":"error","name":"QueueOutOfBounds","inputs":[]},{"type":"error","name":"RecipientIsERC721TransferExempt","inputs":[]},{"type":"error","name":"Unauthorized","inputs":[]},{"type":"error","name":"UnsafeRecipient","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":"Approval","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"address","name":"spender","internalType":"address","indexed":true},{"type":"uint256","name":"id","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"ApprovalForAll","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"address","name":"operator","internalType":"address","indexed":true},{"type":"bool","name":"approved","internalType":"bool","indexed":false}],"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":"Transfer","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"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":"id","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"DOMAIN_SEPARATOR","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"ID_ENCODING_PREFIX","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"_uri","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allowance","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"approve","inputs":[{"type":"address","name":"spender_","internalType":"address"},{"type":"uint256","name":"valueOrId_","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"","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":"erc20Approve","inputs":[{"type":"address","name":"spender_","internalType":"address"},{"type":"uint256","name":"value_","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"erc20BalanceOf","inputs":[{"type":"address","name":"owner_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"erc20TotalSupply","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"erc20TransferFrom","inputs":[{"type":"address","name":"from_","internalType":"address"},{"type":"address","name":"to_","internalType":"address"},{"type":"uint256","name":"value_","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"erc721Approve","inputs":[{"type":"address","name":"spender_","internalType":"address"},{"type":"uint256","name":"id_","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"erc721BalanceOf","inputs":[{"type":"address","name":"owner_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"erc721TotalSupply","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"erc721TransferExempt","inputs":[{"type":"address","name":"target_","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"erc721TransferFrom","inputs":[{"type":"address","name":"from_","internalType":"address"},{"type":"address","name":"to_","internalType":"address"},{"type":"uint256","name":"id_","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"getApproved","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getERC721QueueLength","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getERC721TokensInQueue","inputs":[{"type":"uint256","name":"start_","internalType":"uint256"},{"type":"uint256","name":"count_","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isApprovedForAll","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"minted","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"nonces","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"owned","inputs":[{"type":"address","name":"owner_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"erc721Owner","internalType":"address"}],"name":"ownerOf","inputs":[{"type":"uint256","name":"id_","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"permit","inputs":[{"type":"address","name":"owner_","internalType":"address"},{"type":"address","name":"spender_","internalType":"address"},{"type":"uint256","name":"value_","internalType":"uint256"},{"type":"uint256","name":"deadline_","internalType":"uint256"},{"type":"uint8","name":"v_","internalType":"uint8"},{"type":"bytes32","name":"r_","internalType":"bytes32"},{"type":"bytes32","name":"s_","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"safeTransferFrom","inputs":[{"type":"address","name":"from_","internalType":"address"},{"type":"address","name":"to_","internalType":"address"},{"type":"uint256","name":"id_","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"safeTransferFrom","inputs":[{"type":"address","name":"from_","internalType":"address"},{"type":"address","name":"to_","internalType":"address"},{"type":"uint256","name":"id_","internalType":"uint256"},{"type":"bytes","name":"data_","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setApprovalForAll","inputs":[{"type":"address","name":"operator_","internalType":"address"},{"type":"bool","name":"approved_","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setERC721TransferExempt","inputs":[{"type":"address","name":"account_","internalType":"address"},{"type":"bool","name":"value_","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setSelfERC721TransferExempt","inputs":[{"type":"bool","name":"state_","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setURI","inputs":[{"type":"string","name":"uri","internalType":"string"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"supportsInterface","inputs":[{"type":"bytes4","name":"interfaceId","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"symbol","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"tokenURI","inputs":[{"type":"uint256","name":"id_","internalType":"uint256"}]},{"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":"value_","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transferFrom","inputs":[{"type":"address","name":"from_","internalType":"address"},{"type":"address","name":"to_","internalType":"address"},{"type":"uint256","name":"valueOrId_","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":"units","inputs":[]}]
              

Contract Creation Code

Verify & Publish
0x61010060405234801561001157600080fd5b5060405161393038038061393083398101604081905261003091610e24565b7315e18b3b61d7ad70c05cb8c89c5f87dbf69c1939878787866001600160a01b03811661007757604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b61008081610212565b50600361008d8482610f7c565b50600461009a8382610f7c565b5060128160ff1610156100c0576040516398790fd560e01b815260040160405180910390fd5b60ff811660808190526100d490600a611135565b60a0524660c0526100e3610262565b60e052508291506100f790508160016102fc565b60006101c5826001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa15801561013a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061015e919061114b565b836001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa15801561019c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101c0919061114b565b61036b565b90506101d28160016102fc565b50600f91506101e390508282610f7c565b506101ef8260016102fc565b6102068260a051866102019190611166565b610465565b50505050505050611280565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6003604051610294919061117d565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6001600160a01b0382166103235760405163a41e3d3f60e01b815260040160405180910390fd5b801561033757610332826104cf565b610340565b61034082610503565b6001600160a01b03919091166000908152600d60205260409020805460ff1916911515919091179055565b60003081806001600160a01b038516831061038757848361038a565b82855b6040516001600160601b0319606084811b8216602084015283901b16603482015291935091508690604801604051602081830303815290604052805190602001206040516020016104409291907fff00000000000000000000000000000000000000000000000000000000000000815260609290921b6001600160601b031916600183015260158201527fba8a75b5eef0e9f9b7cd66d6e68f92a973ecff5ac2db0dec5920626f18114a10603582015260550190565b6040516020818303038152906040528051906020012060001c93505050505b92915050565b6001600160a01b03821661048c57604051634e46966960e11b815260040160405180910390fd5b600160ff1b8160055461049f91906111f3565b11156104be5760405163303b682f60e01b815260040160405180910390fd5b6104ca60008383610582565b505050565b6001600160a01b0381166000908152600c6020526040812054905b818110156104ca576104fb836107f4565b6001016104ea565b60a051600090610528836001600160a01b031660009081526007602052604090205490565b6105329190611206565b90506000610555836001600160a01b03166000908152600c602052604090205490565b905060005b6105648284611228565b81101561057c576105748461087f565b60010161055a565b50505050565b6001600160a01b038381166000908152600760205260408082205492851682528120549091906105b3868686610967565b60006105be87610a11565b905060006105cb87610a11565b90508180156105d75750805b6107e657811561064657600060a051846105f19190611206565b60a0516001600160a01b038a166000908152600760205260409020546106179190611206565b6106219190611228565b905060005b8181101561063f576106378961087f565b600101610626565b50506107e6565b80156106a85760a0516001600160a01b038916600090815260076020526040812054909161067391611206565b60a0516106809087611206565b61068a9190611228565b905060005b8181101561063f576106a08a6107f4565b60010161068f565b600060a051876106b89190611206565b905060005b81811015610741576001600160a01b038a166000908152600c60205260408120546106ea90600190611228565b6001600160a01b038c166000908152600c6020526040812080549293509091839081106107195761071961123b565b906000526020600020015490506107378c8c83610a4360201b60201c565b50506001016106bd565b5060a05181906107668b6001600160a01b031660009081526007602052604090205490565b6107709190611206565b60a05161077d9088611206565b6107879190611228565b111561079657610796896107f4565b8060a051856107a59190611206565b60a0516001600160a01b038b166000908152600760205260409020546107cb9190611206565b6107d59190611228565b11156107e4576107e48861087f565b505b506001979650505050505050565b6001600160a01b03811661081b57604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b0381166000908152600c60205260408120805461084190600190611228565b815481106108515761085161123b565b9060005260206000200154905061087082600083610a4360201b60201c565b61087b600182610c09565b5050565b6001600160a01b0381166108a657604051634e46966960e11b815260040160405180910390fd5b60006108c6600154600160801b81046001600160801b0390811691161490565b6108db576108d46001610c73565b9050610925565b6006600081546108ea90611251565b909155506006546001016109115760405163303b682f60e01b815260040160405180910390fd5b60065461092290600160ff1b6111f3565b90505b6000818152600b60205260409020546001600160a01b0316801561095c5760405163119b4fd360e11b815260040160405180910390fd5b6104ca818484610a43565b6001600160a01b03831661099257806005600082825461098791906111f3565b909155506109c09050565b6001600160a01b038316600090815260076020526040812080548392906109ba908490611228565b90915550505b6001600160a01b038083166000818152600760205260409081902080548501905551909185169060008051602061391083398151915290610a049085815260200190565b60405180910390a3505050565b60006001600160a01b038216158061045f5750506001600160a01b03166000908152600d602052604090205460ff1690565b6001600160a01b03831615610b4e57600081815260096020908152604080832080546001600160a01b03191690556001600160a01b0386168352600c90915281208054610a9290600190611228565b81548110610aa257610aa261123b565b90600052602060002001549050818114610b0f576000828152600b602052604081205460a01c6001600160a01b0386166000908152600c602052604090208054919250839183908110610af757610af761123b565b600091825260209091200155610b0d8282610ce3565b505b6001600160a01b0384166000908152600c60205260409020805480610b3657610b3661126a565b60019003818190600052602060002001600090559055505b6001600160a01b03821615610bc5576000818152600b6020908152604080832080546001600160a01b0319166001600160a01b038716908101909155808452600c83529083208054600181810183558286529385200185905592529054610bc0918391610bbb9190611228565b610ce3565b610bd5565b6000818152600b60205260408120555b80826001600160a01b0316846001600160a01b031660008051602061391083398151915260405160405180910390a4505050565b81546001600160801b038082166000190191600160801b9004811690821603610c4557604051638acb5f2760e01b815260040160405180910390fd5b6001600160801b0316600081815260018401602052604090209190915581546001600160801b031916179055565b80546000906001600160801b03600160801b8204811691168103610caa576040516375e52f4f60e01b815260040160405180910390fd5b600019016001600160801b039081166000818152600185016020526040812080549190558454909216600160801b909102179092555090565b6000828152600b60205260409020546001600160601b03821115610d1a57604051633f2cd0e360e21b815260040160405180910390fd5b6000928352600b60205260409092206001600160a01b039290921660a09190911b6001600160a01b031916019055565b634e487b7160e01b600052604160045260246000fd5b600082601f830112610d7157600080fd5b81516001600160401b0380821115610d8b57610d8b610d4a565b604051601f8301601f19908116603f01168101908282118183101715610db357610db3610d4a565b8160405283815260209250866020858801011115610dd057600080fd5b600091505b83821015610df25785820183015181830184015290820190610dd5565b6000602085830101528094505050505092915050565b80516001600160a01b0381168114610e1f57600080fd5b919050565b600080600080600080600060e0888a031215610e3f57600080fd5b87516001600160401b0380821115610e5657600080fd5b610e628b838c01610d60565b985060208a0151915080821115610e7857600080fd5b610e848b838c01610d60565b975060408a0151915060ff82168214610e9c57600080fd5b81965060608a01519550610eb260808b01610e08565b9450610ec060a08b01610e08565b935060c08a0151915080821115610ed657600080fd5b50610ee38a828b01610d60565b91505092959891949750929550565b600181811c90821680610f0657607f821691505b602082108103610f2657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156104ca576000816000526020600020601f850160051c81016020861015610f555750805b601f850160051c820191505b81811015610f7457828155600101610f61565b505050505050565b81516001600160401b03811115610f9557610f95610d4a565b610fa981610fa38454610ef2565b84610f2c565b602080601f831160018114610fde5760008415610fc65750858301515b600019600386901b1c1916600185901b178555610f74565b600085815260208120601f198616915b8281101561100d57888601518255948401946001909101908401610fee565b508582101561102b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052601160045260246000fd5b600181815b8085111561108c5781600019048211156110725761107261103b565b8085161561107f57918102915b93841c9390800290611056565b509250929050565b6000826110a35750600161045f565b816110b05750600061045f565b81600181146110c657600281146110d0576110ec565b600191505061045f565b60ff8411156110e1576110e161103b565b50506001821b61045f565b5060208310610133831016604e8410600b841016171561110f575081810a61045f565b6111198383611051565b806000190482111561112d5761112d61103b565b029392505050565b600061114460ff841683611094565b9392505050565b60006020828403121561115d57600080fd5b61114482610e08565b808202811582820484141761045f5761045f61103b565b600080835461118b81610ef2565b600182811680156111a357600181146111b8576111e7565b60ff19841687528215158302870194506111e7565b8760005260208060002060005b858110156111de5781548a8201529084019082016111c5565b50505082870194505b50929695505050505050565b8082018082111561045f5761045f61103b565b60008261122357634e487b7160e01b600052601260045260246000fd5b500490565b8181038181111561045f5761045f61103b565b634e487b7160e01b600052603260045260246000fd5b6000600182016112635761126361103b565b5060010190565b634e487b7160e01b600052603160045260246000fd5b60805160a05160c05160e05161260a611306600039600061081b015260006107eb01526000818161048e0152818161101e015281816113f401528181611438015281816114b1015281816114db0152818161152f015281816115db015281816116280152818161166c015281816116930152611ae901526000610384015261260a6000f3fe608060405234801561001057600080fd5b506004361061025e5760003560e01c806389fb4c6611610146578063c5ab3ba6116100c3578063dd62ed3e11610087578063dd62ed3e14610586578063dd637699146105b1578063dfabc033146105c4578063e985e9c5146105d7578063f2fde38b14610605578063f780bc1a1461061857600080fd5b8063c5ab3ba614610532578063c6e672b91461053a578063c87b56dd1461054d578063d505accf14610560578063d96ca0b91461057357600080fd5b8063a22cb4651161010a578063a22cb465146104b0578063a9059cbb146104c3578063b1ab9317146104d6578063b3f9ea34146104f6578063b88d4fde1461051f57600080fd5b806389fb4c66146104555780638a696e501461045d5780638da5cb5b1461047057806395d89b4114610481578063976a84351461048957600080fd5b806323b872dd116101df5780634f02c420116101a35780634f02c420146103e65780636352211e146103ef5780636e8f624b1461040257806370a082311461040d578063715018a61461042d5780637ecebe001461043557600080fd5b806323b872dd1461036c578063313ce5671461037f5780633644e515146103b857806342842e0e146103c05780634d966072146103d357600080fd5b8063095ea7b311610226578063095ea7b31461032d57806309674eb01461034057806309f0ef65146103485780630dccc9ad1461035b57806318160ddd1461036357600080fd5b806301ffc9a71461026357806302519da31461028b57806302fe5305146102c257806306fdde03146102d7578063081812fc146102ec575b600080fd5b610276610271366004611efe565b61062b565b60405190151581526020015b60405180910390f35b6102b4610299366004611f32565b6001600160a01b031660009081526007602052604090205490565b604051908152602001610282565b6102d56102d0366004611fd9565b610662565b005b6102df61067a565b604051610282919061207a565b6103156102fa36600461208d565b6009602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610282565b61027661033b3660046120a6565b610708565b6102b4610741565b610276610356366004611f32565b61076b565b6102df61079d565b6102b460055481565b61027661037a3660046120d0565b6107aa565b6103a67f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff9091168152602001610282565b6102b46107e7565b6102d56103ce3660046120d0565b61083d565b6102766103e13660046120a6565b61085d565b6102b460065481565b6103156103fd36600461208d565b6108ea565b6102b4600160ff1b81565b6102b461041b366004611f32565b60076020526000908152604090205481565b6102d5610954565b6102b4610443366004611f32565b600e6020526000908152604090205481565b6005546102b4565b6102d561046b36600461211c565b610968565b6000546001600160a01b0316610315565b6102df610975565b6102b47f000000000000000000000000000000000000000000000000000000000000000081565b6102d56104be366004612137565b610982565b6102766104d13660046120a6565b610a15565b6104e96104e4366004611f32565b610a49565b604051610282919061216a565b6102b4610504366004611f32565b6001600160a01b03166000908152600c602052604090205490565b6102d561052d3660046121ae565b610ab5565b6006546102b4565b6102d5610548366004612137565b610ba3565b6102df61055b36600461208d565b610bb5565b6102d561056e36600461222a565b610be9565b6102766105813660046120d0565b610e2c565b6102b461059436600461229d565b600860209081526000928352604080842090915290825290205481565b6102d56105bf3660046120d0565b610eec565b6102d56105d23660046120a6565b61104d565b6102766105e536600461229d565b600a60209081526000928352604080842090915290825290205460ff1681565b6102d5610613366004611f32565b611112565b6104e96106263660046122c7565b611152565b60006001600160e01b0319821663caf91ff560e01b148061065c57506001600160e01b031982166301ffc9a760e01b145b92915050565b61066a6111ef565b600f6106768282612373565b5050565b60038054610687906122e9565b80601f01602080910402602001604051908101604052809291908181526020018280546106b3906122e9565b80156107005780601f106106d557610100808354040283529160200191610700565b820191906000526020600020905b8154815290600101906020018083116106e357829003601f168201915b505050505081565b60006107138261121c565b1561072757610722838361104d565b610738565b610731838361085d565b905061065c565b50600192915050565b60006107666001546001600160801b03808216600160801b9092048116919091031690565b905090565b60006001600160a01b038216158061065c5750506001600160a01b03166000908152600d602052604090205460ff1690565b600f8054610687906122e9565b60006107b58261121c565b156107ca576107c5848484610eec565b6107dc565b6107d5848484610e2c565b90506107e0565b5060015b9392505050565b60007f0000000000000000000000000000000000000000000000000000000000000000461461081857610766611235565b507f000000000000000000000000000000000000000000000000000000000000000090565b61085883838360405180602001604052806000815250610ab5565b505050565b60006001600160a01b03831661088657604051635461585f60e01b815260040160405180910390fd5b3360008181526008602090815260408083206001600160a01b03881680855290835292819020869055518581529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350600192915050565b6000818152600b60205260409020546001600160a01b031661090b8261121c565b610928576040516307ed98ed60e31b815260040160405180910390fd5b6001600160a01b03811661094f5760405163c5723b5160e01b815260040160405180910390fd5b919050565b61095c6111ef565b61096660006112cf565b565b610972338261131f565b50565b60048054610687906122e9565b6001600160a01b0382166109a95760405163ccea9e6f60e01b815260040160405180910390fd5b336000818152600a602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b60006001600160a01b038316610a3e57604051634e46966960e11b815260040160405180910390fd5b6107e033848461138e565b6001600160a01b0381166000908152600c6020908152604091829020805483518184028101840190945280845260609392830182828015610aa957602002820191906000526020600020905b815481526020019060010190808311610a95575b50505050509050919050565b610abe8261121c565b610adb576040516307ed98ed60e31b815260040160405180910390fd5b610ae68484846107aa565b506001600160a01b0383163b15801590610b7f5750604051630a85bd0160e11b808252906001600160a01b0385169063150b7a0290610b2f903390899088908890600401612433565b6020604051808303816000875af1158015610b4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b729190612470565b6001600160e01b03191614155b15610b9d57604051633da6393160e01b815260040160405180910390fd5b50505050565b610bab6111ef565b610676828261131f565b6060600f610bc283611704565b604051602001610bd3929190612500565b6040516020818303038152906040529050919050565b42841015610c0a576040516305787bdf60e01b815260040160405180910390fd5b610c138561121c565b15610c31576040516303e7c1bd60e31b815260040160405180910390fd5b6001600160a01b038616610c5857604051635461585f60e01b815260040160405180910390fd5b60006001610c646107e7565b6001600160a01b038a81166000818152600e602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015610d70573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381161580610da55750876001600160a01b0316816001600160a01b031614155b15610dc357604051632057875960e21b815260040160405180910390fd5b6001600160a01b0390811660009081526008602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b60006001600160a01b038416610e5557604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b038316610e7c57604051634e46966960e11b815260040160405180910390fd5b6001600160a01b03841660009081526008602090815260408083203384529091529020546000198114610ed857610eb3838261253b565b6001600160a01b03861660009081526008602090815260408083203384529091529020555b610ee385858561138e565b95945050505050565b6001600160a01b038316610f1357604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b038216610f3a57604051634e46966960e11b815260040160405180910390fd5b6000818152600b60205260409020546001600160a01b03848116911614610f73576040516282b42960e81b815260040160405180910390fd5b336001600160a01b03841614801590610fb057506001600160a01b0383166000908152600a6020908152604080832033845290915290205460ff16155b8015610fd357506000818152600960205260409020546001600160a01b03163314155b15610ff0576040516282b42960e81b815260040160405180910390fd5b610ff98261076b565b1561101757604051635ce7539760e01b815260040160405180910390fd5b61104283837f0000000000000000000000000000000000000000000000000000000000000000611797565b610858838383611853565b6000818152600b60205260409020546001600160a01b031633811480159061109957506001600160a01b0381166000908152600a6020908152604080832033845290915290205460ff16155b156110b6576040516282b42960e81b815260040160405180910390fd5b60008281526009602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b61111a6111ef565b6001600160a01b03811661114957604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b610972816112cf565b606060008267ffffffffffffffff81111561116f5761116f611f4d565b604051908082528060200260200182016040528015611198578160200160208202803683370190505b509050835b6111a7848661254e565b8110156111e7576111b9600182611a2b565b826111c4878461253b565b815181106111d4576111d4612561565b602090810291909101015260010161119d565b509392505050565b6000546001600160a01b031633146109665760405163118cdaa760e01b8152336004820152602401611140565b6000600160ff1b8211801561065c575050600019141590565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60036040516112679190612577565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b0382166113465760405163a41e3d3f60e01b815260040160405180910390fd5b801561135a5761135582611a96565b611363565b61136382611aca565b6001600160a01b03919091166000908152600d60205260409020805460ff1916911515919091179055565b6001600160a01b038381166000908152600760205260408082205492851682528120549091906113bf868686611797565b60006113ca8761076b565b905060006113d78761076b565b90508180156113e35750805b6116f657811561148c5760006114197f000000000000000000000000000000000000000000000000000000000000000085612583565b6001600160a01b03891660009081526007602052604090205461145d907f000000000000000000000000000000000000000000000000000000000000000090612583565b611467919061253b565b905060005b818110156114855761147d89611b58565b60010161146c565b50506116f6565b8015611528576001600160a01b0388166000908152600760205260408120546114d6907f000000000000000000000000000000000000000000000000000000000000000090612583565b6115007f000000000000000000000000000000000000000000000000000000000000000087612583565b61150a919061253b565b905060005b81811015611485576115208a611c40565b60010161150f565b60006115547f000000000000000000000000000000000000000000000000000000000000000088612583565b905060005b818110156115d7576001600160a01b038a166000908152600c60205260408120546115869060019061253b565b6001600160a01b038c166000908152600c6020526040812080549293509091839081106115b5576115b5612561565b906000526020600020015490506115cd8c8c83611853565b5050600101611559565b50807f00000000000000000000000000000000000000000000000000000000000000006116198b6001600160a01b031660009081526007602052604090205490565b6116239190612583565b61164d7f000000000000000000000000000000000000000000000000000000000000000088612583565b611657919061253b565b11156116665761166689611c40565b806116917f000000000000000000000000000000000000000000000000000000000000000086612583565b7f00000000000000000000000000000000000000000000000000000000000000006116d18b6001600160a01b031660009081526007602052604090205490565b6116db9190612583565b6116e5919061253b565b11156116f4576116f488611b58565b505b506001979650505050505050565b6060600061171183611cc1565b600101905060008167ffffffffffffffff81111561173157611731611f4d565b6040519080825280601f01601f19166020018201604052801561175b576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461176557509392505050565b6001600160a01b0383166117c25780600560008282546117b7919061254e565b909155506117f09050565b6001600160a01b038316600090815260076020526040812080548392906117ea90849061253b565b90915550505b6001600160a01b03808316600081815260076020526040908190208054850190555190918516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906118469085815260200190565b60405180910390a3505050565b6001600160a01b0383161561195e57600081815260096020908152604080832080546001600160a01b03191690556001600160a01b0386168352600c909152812080546118a29060019061253b565b815481106118b2576118b2612561565b9060005260206000200154905081811461191f576000828152600b602052604081205460a01c6001600160a01b0386166000908152600c60205260409020805491925083918390811061190757611907612561565b60009182526020909120015561191d8282611d99565b505b6001600160a01b0384166000908152600c60205260409020805480611946576119466125a5565b60019003818190600052602060002001600090559055505b6001600160a01b038216156119d5576000818152600b6020908152604080832080546001600160a01b0319166001600160a01b038716908101909155808452600c835290832080546001818101835582865293852001859055925290546119d09183916119cb919061253b565b611d99565b6119e5565b6000818152600b60205260408120555b80826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b6000611a4f83546001600160801b03808216600160801b9092048116919091031690565b8210611a6e5760405163580821e760e01b815260040160405180910390fd5b5081546001600160801b03908116820116600090815260018301602052604090205492915050565b6001600160a01b0381166000908152600c6020526040812054905b8181101561085857611ac283611c40565b600101611ab1565b6001600160a01b038116600090815260076020526040812054611b0e907f000000000000000000000000000000000000000000000000000000000000000090612583565b90506000611b31836001600160a01b03166000908152600c602052604090205490565b905060005b611b40828461253b565b811015610b9d57611b5084611b58565b600101611b36565b6001600160a01b038116611b7f57604051634e46966960e11b815260040160405180910390fd5b6000611b9f600154600160801b81046001600160801b0390811691161490565b611bb457611bad6001611e05565b9050611bfe565b600660008154611bc3906125bb565b90915550600654600101611bea5760405163303b682f60e01b815260040160405180910390fd5b600654611bfb90600160ff1b61254e565b90505b6000818152600b60205260409020546001600160a01b03168015611c355760405163119b4fd360e11b815260040160405180910390fd5b610858818484611853565b6001600160a01b038116611c6757604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b0381166000908152600c602052604081208054611c8d9060019061253b565b81548110611c9d57611c9d612561565b90600052602060002001549050611cb682600083611853565b610676600182611e75565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310611d005772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310611d2c576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310611d4a57662386f26fc10000830492506010015b6305f5e1008310611d62576305f5e100830492506008015b6127108310611d7657612710830492506004015b60648310611d88576064830492506002015b600a831061065c5760010192915050565b6000828152600b60205260409020546bffffffffffffffffffffffff821115611dd557604051633f2cd0e360e21b815260040160405180910390fd5b6000928352600b60205260409092206001600160a01b039290921660a09190911b6001600160a01b031916019055565b80546000906001600160801b03600160801b8204811691168103611e3c576040516375e52f4f60e01b815260040160405180910390fd5b600019016001600160801b039081166000818152600185016020526040812080549190558454909216600160801b909102179092555090565b81546001600160801b038082166000190191600160801b9004811690821603611eb157604051638acb5f2760e01b815260040160405180910390fd5b6001600160801b0316600081815260018401602052604090209190915581546fffffffffffffffffffffffffffffffff1916179055565b6001600160e01b03198116811461097257600080fd5b600060208284031215611f1057600080fd5b81356107e081611ee8565b80356001600160a01b038116811461094f57600080fd5b600060208284031215611f4457600080fd5b6107e082611f1b565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff80841115611f7e57611f7e611f4d565b604051601f8501601f19908116603f01168101908282118183101715611fa657611fa6611f4d565b81604052809350858152868686011115611fbf57600080fd5b858560208301376000602087830101525050509392505050565b600060208284031215611feb57600080fd5b813567ffffffffffffffff81111561200257600080fd5b8201601f8101841361201357600080fd5b61202284823560208401611f63565b949350505050565b60005b8381101561204557818101518382015260200161202d565b50506000910152565b6000815180845261206681602086016020860161202a565b601f01601f19169290920160200192915050565b6020815260006107e0602083018461204e565b60006020828403121561209f57600080fd5b5035919050565b600080604083850312156120b957600080fd5b6120c283611f1b565b946020939093013593505050565b6000806000606084860312156120e557600080fd5b6120ee84611f1b565b92506120fc60208501611f1b565b9150604084013590509250925092565b8035801515811461094f57600080fd5b60006020828403121561212e57600080fd5b6107e08261210c565b6000806040838503121561214a57600080fd5b61215383611f1b565b91506121616020840161210c565b90509250929050565b6020808252825182820181905260009190848201906040850190845b818110156121a257835183529284019291840191600101612186565b50909695505050505050565b600080600080608085870312156121c457600080fd5b6121cd85611f1b565b93506121db60208601611f1b565b925060408501359150606085013567ffffffffffffffff8111156121fe57600080fd5b8501601f8101871361220f57600080fd5b61221e87823560208401611f63565b91505092959194509250565b600080600080600080600060e0888a03121561224557600080fd5b61224e88611f1b565b965061225c60208901611f1b565b95506040880135945060608801359350608088013560ff8116811461228057600080fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156122b057600080fd5b6122b983611f1b565b915061216160208401611f1b565b600080604083850312156122da57600080fd5b50508035926020909101359150565b600181811c908216806122fd57607f821691505b60208210810361231d57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610858576000816000526020600020601f850160051c8101602086101561234c5750805b601f850160051c820191505b8181101561236b57828155600101612358565b505050505050565b815167ffffffffffffffff81111561238d5761238d611f4d565b6123a18161239b84546122e9565b84612323565b602080601f8311600181146123d657600084156123be5750858301515b600019600386901b1c1916600185901b17855561236b565b600085815260208120601f198616915b82811015612405578886015182559484019460019091019084016123e6565b50858210156124235787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906124669083018461204e565b9695505050505050565b60006020828403121561248257600080fd5b81516107e081611ee8565b6000815461249a816122e9565b600182811680156124b257600181146124c7576124f6565b60ff19841687528215158302870194506124f6565b8560005260208060002060005b858110156124ed5781548a8201529084019082016124d4565b50505082870194505b5050505092915050565b600061250c828561248d565b835161251c81836020880161202a565b01949350505050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561065c5761065c612525565b8082018082111561065c5761065c612525565b634e487b7160e01b600052603260045260246000fd5b60006107e0828461248d565b6000826125a057634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603160045260246000fd5b6000600182016125cd576125cd612525565b506001019056fea26469706673582212206a78bac4c618c1457bc6bfca7158dcfac38c62133530bf8c9ac66dcc4de8090664736f6c63430008190033ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000001f400000000000000000000000097496c270e57cd8131bf9a7c23922c771da4f94200000000000000000000000097496c270e57cd8131bf9a7c23922c771da4f942000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000134379626572776f6d616e206f6620466c61726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000443594f4600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004d68747470733a2f2f697066732e696f2f697066732f516d5937515a6875566779664b31586a736b6436785458614b356156635561437678707362586675645748624b732f4d657461646174612f00000000000000000000000000000000000000

Deployed ByteCode

0x608060405234801561001057600080fd5b506004361061025e5760003560e01c806389fb4c6611610146578063c5ab3ba6116100c3578063dd62ed3e11610087578063dd62ed3e14610586578063dd637699146105b1578063dfabc033146105c4578063e985e9c5146105d7578063f2fde38b14610605578063f780bc1a1461061857600080fd5b8063c5ab3ba614610532578063c6e672b91461053a578063c87b56dd1461054d578063d505accf14610560578063d96ca0b91461057357600080fd5b8063a22cb4651161010a578063a22cb465146104b0578063a9059cbb146104c3578063b1ab9317146104d6578063b3f9ea34146104f6578063b88d4fde1461051f57600080fd5b806389fb4c66146104555780638a696e501461045d5780638da5cb5b1461047057806395d89b4114610481578063976a84351461048957600080fd5b806323b872dd116101df5780634f02c420116101a35780634f02c420146103e65780636352211e146103ef5780636e8f624b1461040257806370a082311461040d578063715018a61461042d5780637ecebe001461043557600080fd5b806323b872dd1461036c578063313ce5671461037f5780633644e515146103b857806342842e0e146103c05780634d966072146103d357600080fd5b8063095ea7b311610226578063095ea7b31461032d57806309674eb01461034057806309f0ef65146103485780630dccc9ad1461035b57806318160ddd1461036357600080fd5b806301ffc9a71461026357806302519da31461028b57806302fe5305146102c257806306fdde03146102d7578063081812fc146102ec575b600080fd5b610276610271366004611efe565b61062b565b60405190151581526020015b60405180910390f35b6102b4610299366004611f32565b6001600160a01b031660009081526007602052604090205490565b604051908152602001610282565b6102d56102d0366004611fd9565b610662565b005b6102df61067a565b604051610282919061207a565b6103156102fa36600461208d565b6009602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610282565b61027661033b3660046120a6565b610708565b6102b4610741565b610276610356366004611f32565b61076b565b6102df61079d565b6102b460055481565b61027661037a3660046120d0565b6107aa565b6103a67f000000000000000000000000000000000000000000000000000000000000001281565b60405160ff9091168152602001610282565b6102b46107e7565b6102d56103ce3660046120d0565b61083d565b6102766103e13660046120a6565b61085d565b6102b460065481565b6103156103fd36600461208d565b6108ea565b6102b4600160ff1b81565b6102b461041b366004611f32565b60076020526000908152604090205481565b6102d5610954565b6102b4610443366004611f32565b600e6020526000908152604090205481565b6005546102b4565b6102d561046b36600461211c565b610968565b6000546001600160a01b0316610315565b6102df610975565b6102b47f0000000000000000000000000000000000000000000000000de0b6b3a764000081565b6102d56104be366004612137565b610982565b6102766104d13660046120a6565b610a15565b6104e96104e4366004611f32565b610a49565b604051610282919061216a565b6102b4610504366004611f32565b6001600160a01b03166000908152600c602052604090205490565b6102d561052d3660046121ae565b610ab5565b6006546102b4565b6102d5610548366004612137565b610ba3565b6102df61055b36600461208d565b610bb5565b6102d561056e36600461222a565b610be9565b6102766105813660046120d0565b610e2c565b6102b461059436600461229d565b600860209081526000928352604080842090915290825290205481565b6102d56105bf3660046120d0565b610eec565b6102d56105d23660046120a6565b61104d565b6102766105e536600461229d565b600a60209081526000928352604080842090915290825290205460ff1681565b6102d5610613366004611f32565b611112565b6104e96106263660046122c7565b611152565b60006001600160e01b0319821663caf91ff560e01b148061065c57506001600160e01b031982166301ffc9a760e01b145b92915050565b61066a6111ef565b600f6106768282612373565b5050565b60038054610687906122e9565b80601f01602080910402602001604051908101604052809291908181526020018280546106b3906122e9565b80156107005780601f106106d557610100808354040283529160200191610700565b820191906000526020600020905b8154815290600101906020018083116106e357829003601f168201915b505050505081565b60006107138261121c565b1561072757610722838361104d565b610738565b610731838361085d565b905061065c565b50600192915050565b60006107666001546001600160801b03808216600160801b9092048116919091031690565b905090565b60006001600160a01b038216158061065c5750506001600160a01b03166000908152600d602052604090205460ff1690565b600f8054610687906122e9565b60006107b58261121c565b156107ca576107c5848484610eec565b6107dc565b6107d5848484610e2c565b90506107e0565b5060015b9392505050565b60007f000000000000000000000000000000000000000000000000000000000000000e461461081857610766611235565b507ffff6b2446e5d4be4d0b1c0dd9e4c94bf22e8d6c7b10a295462340b988716470f90565b61085883838360405180602001604052806000815250610ab5565b505050565b60006001600160a01b03831661088657604051635461585f60e01b815260040160405180910390fd5b3360008181526008602090815260408083206001600160a01b03881680855290835292819020869055518581529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350600192915050565b6000818152600b60205260409020546001600160a01b031661090b8261121c565b610928576040516307ed98ed60e31b815260040160405180910390fd5b6001600160a01b03811661094f5760405163c5723b5160e01b815260040160405180910390fd5b919050565b61095c6111ef565b61096660006112cf565b565b610972338261131f565b50565b60048054610687906122e9565b6001600160a01b0382166109a95760405163ccea9e6f60e01b815260040160405180910390fd5b336000818152600a602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b60006001600160a01b038316610a3e57604051634e46966960e11b815260040160405180910390fd5b6107e033848461138e565b6001600160a01b0381166000908152600c6020908152604091829020805483518184028101840190945280845260609392830182828015610aa957602002820191906000526020600020905b815481526020019060010190808311610a95575b50505050509050919050565b610abe8261121c565b610adb576040516307ed98ed60e31b815260040160405180910390fd5b610ae68484846107aa565b506001600160a01b0383163b15801590610b7f5750604051630a85bd0160e11b808252906001600160a01b0385169063150b7a0290610b2f903390899088908890600401612433565b6020604051808303816000875af1158015610b4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b729190612470565b6001600160e01b03191614155b15610b9d57604051633da6393160e01b815260040160405180910390fd5b50505050565b610bab6111ef565b610676828261131f565b6060600f610bc283611704565b604051602001610bd3929190612500565b6040516020818303038152906040529050919050565b42841015610c0a576040516305787bdf60e01b815260040160405180910390fd5b610c138561121c565b15610c31576040516303e7c1bd60e31b815260040160405180910390fd5b6001600160a01b038616610c5857604051635461585f60e01b815260040160405180910390fd5b60006001610c646107e7565b6001600160a01b038a81166000818152600e602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015610d70573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381161580610da55750876001600160a01b0316816001600160a01b031614155b15610dc357604051632057875960e21b815260040160405180910390fd5b6001600160a01b0390811660009081526008602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b60006001600160a01b038416610e5557604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b038316610e7c57604051634e46966960e11b815260040160405180910390fd5b6001600160a01b03841660009081526008602090815260408083203384529091529020546000198114610ed857610eb3838261253b565b6001600160a01b03861660009081526008602090815260408083203384529091529020555b610ee385858561138e565b95945050505050565b6001600160a01b038316610f1357604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b038216610f3a57604051634e46966960e11b815260040160405180910390fd5b6000818152600b60205260409020546001600160a01b03848116911614610f73576040516282b42960e81b815260040160405180910390fd5b336001600160a01b03841614801590610fb057506001600160a01b0383166000908152600a6020908152604080832033845290915290205460ff16155b8015610fd357506000818152600960205260409020546001600160a01b03163314155b15610ff0576040516282b42960e81b815260040160405180910390fd5b610ff98261076b565b1561101757604051635ce7539760e01b815260040160405180910390fd5b61104283837f0000000000000000000000000000000000000000000000000de0b6b3a7640000611797565b610858838383611853565b6000818152600b60205260409020546001600160a01b031633811480159061109957506001600160a01b0381166000908152600a6020908152604080832033845290915290205460ff16155b156110b6576040516282b42960e81b815260040160405180910390fd5b60008281526009602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b61111a6111ef565b6001600160a01b03811661114957604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b610972816112cf565b606060008267ffffffffffffffff81111561116f5761116f611f4d565b604051908082528060200260200182016040528015611198578160200160208202803683370190505b509050835b6111a7848661254e565b8110156111e7576111b9600182611a2b565b826111c4878461253b565b815181106111d4576111d4612561565b602090810291909101015260010161119d565b509392505050565b6000546001600160a01b031633146109665760405163118cdaa760e01b8152336004820152602401611140565b6000600160ff1b8211801561065c575050600019141590565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60036040516112679190612577565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b0382166113465760405163a41e3d3f60e01b815260040160405180910390fd5b801561135a5761135582611a96565b611363565b61136382611aca565b6001600160a01b03919091166000908152600d60205260409020805460ff1916911515919091179055565b6001600160a01b038381166000908152600760205260408082205492851682528120549091906113bf868686611797565b60006113ca8761076b565b905060006113d78761076b565b90508180156113e35750805b6116f657811561148c5760006114197f0000000000000000000000000000000000000000000000000de0b6b3a764000085612583565b6001600160a01b03891660009081526007602052604090205461145d907f0000000000000000000000000000000000000000000000000de0b6b3a764000090612583565b611467919061253b565b905060005b818110156114855761147d89611b58565b60010161146c565b50506116f6565b8015611528576001600160a01b0388166000908152600760205260408120546114d6907f0000000000000000000000000000000000000000000000000de0b6b3a764000090612583565b6115007f0000000000000000000000000000000000000000000000000de0b6b3a764000087612583565b61150a919061253b565b905060005b81811015611485576115208a611c40565b60010161150f565b60006115547f0000000000000000000000000000000000000000000000000de0b6b3a764000088612583565b905060005b818110156115d7576001600160a01b038a166000908152600c60205260408120546115869060019061253b565b6001600160a01b038c166000908152600c6020526040812080549293509091839081106115b5576115b5612561565b906000526020600020015490506115cd8c8c83611853565b5050600101611559565b50807f0000000000000000000000000000000000000000000000000de0b6b3a76400006116198b6001600160a01b031660009081526007602052604090205490565b6116239190612583565b61164d7f0000000000000000000000000000000000000000000000000de0b6b3a764000088612583565b611657919061253b565b11156116665761166689611c40565b806116917f0000000000000000000000000000000000000000000000000de0b6b3a764000086612583565b7f0000000000000000000000000000000000000000000000000de0b6b3a76400006116d18b6001600160a01b031660009081526007602052604090205490565b6116db9190612583565b6116e5919061253b565b11156116f4576116f488611b58565b505b506001979650505050505050565b6060600061171183611cc1565b600101905060008167ffffffffffffffff81111561173157611731611f4d565b6040519080825280601f01601f19166020018201604052801561175b576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461176557509392505050565b6001600160a01b0383166117c25780600560008282546117b7919061254e565b909155506117f09050565b6001600160a01b038316600090815260076020526040812080548392906117ea90849061253b565b90915550505b6001600160a01b03808316600081815260076020526040908190208054850190555190918516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906118469085815260200190565b60405180910390a3505050565b6001600160a01b0383161561195e57600081815260096020908152604080832080546001600160a01b03191690556001600160a01b0386168352600c909152812080546118a29060019061253b565b815481106118b2576118b2612561565b9060005260206000200154905081811461191f576000828152600b602052604081205460a01c6001600160a01b0386166000908152600c60205260409020805491925083918390811061190757611907612561565b60009182526020909120015561191d8282611d99565b505b6001600160a01b0384166000908152600c60205260409020805480611946576119466125a5565b60019003818190600052602060002001600090559055505b6001600160a01b038216156119d5576000818152600b6020908152604080832080546001600160a01b0319166001600160a01b038716908101909155808452600c835290832080546001818101835582865293852001859055925290546119d09183916119cb919061253b565b611d99565b6119e5565b6000818152600b60205260408120555b80826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b6000611a4f83546001600160801b03808216600160801b9092048116919091031690565b8210611a6e5760405163580821e760e01b815260040160405180910390fd5b5081546001600160801b03908116820116600090815260018301602052604090205492915050565b6001600160a01b0381166000908152600c6020526040812054905b8181101561085857611ac283611c40565b600101611ab1565b6001600160a01b038116600090815260076020526040812054611b0e907f0000000000000000000000000000000000000000000000000de0b6b3a764000090612583565b90506000611b31836001600160a01b03166000908152600c602052604090205490565b905060005b611b40828461253b565b811015610b9d57611b5084611b58565b600101611b36565b6001600160a01b038116611b7f57604051634e46966960e11b815260040160405180910390fd5b6000611b9f600154600160801b81046001600160801b0390811691161490565b611bb457611bad6001611e05565b9050611bfe565b600660008154611bc3906125bb565b90915550600654600101611bea5760405163303b682f60e01b815260040160405180910390fd5b600654611bfb90600160ff1b61254e565b90505b6000818152600b60205260409020546001600160a01b03168015611c355760405163119b4fd360e11b815260040160405180910390fd5b610858818484611853565b6001600160a01b038116611c6757604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b0381166000908152600c602052604081208054611c8d9060019061253b565b81548110611c9d57611c9d612561565b90600052602060002001549050611cb682600083611853565b610676600182611e75565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310611d005772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310611d2c576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310611d4a57662386f26fc10000830492506010015b6305f5e1008310611d62576305f5e100830492506008015b6127108310611d7657612710830492506004015b60648310611d88576064830492506002015b600a831061065c5760010192915050565b6000828152600b60205260409020546bffffffffffffffffffffffff821115611dd557604051633f2cd0e360e21b815260040160405180910390fd5b6000928352600b60205260409092206001600160a01b039290921660a09190911b6001600160a01b031916019055565b80546000906001600160801b03600160801b8204811691168103611e3c576040516375e52f4f60e01b815260040160405180910390fd5b600019016001600160801b039081166000818152600185016020526040812080549190558454909216600160801b909102179092555090565b81546001600160801b038082166000190191600160801b9004811690821603611eb157604051638acb5f2760e01b815260040160405180910390fd5b6001600160801b0316600081815260018401602052604090209190915581546fffffffffffffffffffffffffffffffff1916179055565b6001600160e01b03198116811461097257600080fd5b600060208284031215611f1057600080fd5b81356107e081611ee8565b80356001600160a01b038116811461094f57600080fd5b600060208284031215611f4457600080fd5b6107e082611f1b565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff80841115611f7e57611f7e611f4d565b604051601f8501601f19908116603f01168101908282118183101715611fa657611fa6611f4d565b81604052809350858152868686011115611fbf57600080fd5b858560208301376000602087830101525050509392505050565b600060208284031215611feb57600080fd5b813567ffffffffffffffff81111561200257600080fd5b8201601f8101841361201357600080fd5b61202284823560208401611f63565b949350505050565b60005b8381101561204557818101518382015260200161202d565b50506000910152565b6000815180845261206681602086016020860161202a565b601f01601f19169290920160200192915050565b6020815260006107e0602083018461204e565b60006020828403121561209f57600080fd5b5035919050565b600080604083850312156120b957600080fd5b6120c283611f1b565b946020939093013593505050565b6000806000606084860312156120e557600080fd5b6120ee84611f1b565b92506120fc60208501611f1b565b9150604084013590509250925092565b8035801515811461094f57600080fd5b60006020828403121561212e57600080fd5b6107e08261210c565b6000806040838503121561214a57600080fd5b61215383611f1b565b91506121616020840161210c565b90509250929050565b6020808252825182820181905260009190848201906040850190845b818110156121a257835183529284019291840191600101612186565b50909695505050505050565b600080600080608085870312156121c457600080fd5b6121cd85611f1b565b93506121db60208601611f1b565b925060408501359150606085013567ffffffffffffffff8111156121fe57600080fd5b8501601f8101871361220f57600080fd5b61221e87823560208401611f63565b91505092959194509250565b600080600080600080600060e0888a03121561224557600080fd5b61224e88611f1b565b965061225c60208901611f1b565b95506040880135945060608801359350608088013560ff8116811461228057600080fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156122b057600080fd5b6122b983611f1b565b915061216160208401611f1b565b600080604083850312156122da57600080fd5b50508035926020909101359150565b600181811c908216806122fd57607f821691505b60208210810361231d57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610858576000816000526020600020601f850160051c8101602086101561234c5750805b601f850160051c820191505b8181101561236b57828155600101612358565b505050505050565b815167ffffffffffffffff81111561238d5761238d611f4d565b6123a18161239b84546122e9565b84612323565b602080601f8311600181146123d657600084156123be5750858301515b600019600386901b1c1916600185901b17855561236b565b600085815260208120601f198616915b82811015612405578886015182559484019460019091019084016123e6565b50858210156124235787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906124669083018461204e565b9695505050505050565b60006020828403121561248257600080fd5b81516107e081611ee8565b6000815461249a816122e9565b600182811680156124b257600181146124c7576124f6565b60ff19841687528215158302870194506124f6565b8560005260208060002060005b858110156124ed5781548a8201529084019082016124d4565b50505082870194505b5050505092915050565b600061250c828561248d565b835161251c81836020880161202a565b01949350505050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561065c5761065c612525565b8082018082111561065c5761065c612525565b634e487b7160e01b600052603260045260246000fd5b60006107e0828461248d565b6000826125a057634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603160045260246000fd5b6000600182016125cd576125cd612525565b506001019056fea26469706673582212206a78bac4c618c1457bc6bfca7158dcfac38c62133530bf8c9ac66dcc4de8090664736f6c63430008190033