Contract 0x5d24b566f91a1b3d8b3c8e83544e8160924ce276

Contract Overview

Balance:
0 BNB
Txn Hash
Block
From
To
Value [Txn Fee]
0x557d31a5a64f7cb7ec7ba163437ab7c8e013a676b86e3fb9c295edd36c7b5e8593837622021-06-02 15:40:4213 days 19 hrs ago0x1bab8030249382a887f967fcaa7fe0be7b390728 IN  Contract Creation0 BNB0.11353378
[ Download CSV Export 
Parent Txn Hash Block From To Value
Loading

Contract Source Code Verified (Similar Match)
Note: This contract matches the deployed ByteCode of the Source Code for Contract 0xa9f5b8F0b7B114Cd7F902381D6b64Cf59aD27F67

Contract Name:
MoonKnight

Compiler Version
v0.8.0+commit.c7dfd78e

Optimization Enabled:
Yes with 100 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 20 : MoonKnight.sol
//SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "./interfaces/IMoonKnight.sol";
import "./interfaces/IEquipment.sol";
import "./interfaces/IPet.sol";
import "./utils/AcceptedToken.sol";

contract MoonKnight is IMoonKnight, ERC721, AcceptedToken, ReentrancyGuard {
    using SafeERC20 for IERC20;
    using EnumerableSet for EnumerableSet.UintSet;

    uint private constant BPS = 10000;

    IEquipment public equipmentContract;
    IPet public petContract;

    uint public floorPriceInBps = 200;
    uint public marketFeeInBps = 22;
    uint public serviceFeeInToken = 1e20;
    uint public maxLevel = 100;
    string private _uri;

    Version[] public versions;
    mapping(uint => uint) public knightsOnSale;
    mapping(uint => mapping(address => uint)) public knightsWithOffers;
    mapping(string => bool) public reservedNames;

    Knight[] private _knights;
    mapping(uint => uint) private _knightsWithPet;
    mapping(uint => EnumerableSet.UintSet) private _knightSkills;

    constructor(
        IEquipment equipmentAddress,
        IERC20 tokenAddress,
        string memory baseURI,
        uint maxSupply,
        uint salePrice,
        uint startTime,
        uint revealTime,
        string memory provenance
    ) ERC721("MoonKnight", "KNIGHT") AcceptedToken(tokenAddress) {
        equipmentContract = equipmentAddress;
        _uri = baseURI;
        versions.push(Version(0, 0, maxSupply, salePrice, startTime, revealTime, provenance));
    }

    modifier onlyKnightOwner(uint knightId) {
        require(ownerOf(knightId) == msg.sender, "MoonKnight: not knight owner");
        _;
    }

    function setEquipmentContract(IEquipment equipmentAddress) external onlyOwner {
        require(address(equipmentAddress) != address(0));
        equipmentContract = equipmentAddress;
    }

    function setPetContract(IPet petAddress) external onlyOwner {
        require(address(petAddress) != address(0));
        petContract = petAddress;
    }

    function setFloorPriceAndMarketFeeInBps(uint floorPrice, uint marketFee) external onlyOwner {
        require(floorPrice + marketFee <= BPS);
        floorPriceInBps = floorPrice;
        marketFeeInBps = marketFee;
    }

    function setServiceFee(uint value) external onlyOwner {
        serviceFeeInToken = value;
    }

    function setMaxLevel(uint newMaxLevel) external onlyOwner {
        require(newMaxLevel > maxLevel);
        maxLevel = newMaxLevel;
    }

    function setBaseURI(string memory baseURI) external onlyOwner {
        _uri = baseURI;
    }

    function addNewVersion(
        uint maxSupply,
        uint salePrice,
        uint startTime,
        uint revealTime,
        string memory provenance
    ) external onlyOwner {
        uint latestVersionId = getLatestVersion();
        Version memory latestVersion = versions[latestVersionId];

        require(latestVersion.currentSupply == latestVersion.maxSupply);

        versions.push(Version(0, 0, maxSupply, salePrice, startTime, revealTime, provenance));
        emit NewVersionAdded(latestVersionId + 1);
    }

    function claimMoonKnight(uint versionId, uint amount) external override payable {
        Version storage version = versions[versionId];
        uint floorPrice = version.salePrice * 1000 / BPS;

        require(amount > 0 && amount <= 50, "MoonKnight: amount out of range");
        require(block.timestamp >= version.startTime, "MoonKnight: Sale has not started");
        require(version.currentSupply + amount <= version.maxSupply, "MoonKnight: sold out");
        require(msg.value == version.salePrice * amount, "MoonKnight: incorrect value");

        for (uint i = 0; i < amount; i++) {
            uint knightId = _createKnight(floorPrice);
            _safeMint(msg.sender, knightId);
        }

        version.currentSupply += amount;

        (bool isSuccess,) = owner().call{value: msg.value - (floorPrice * amount)}("");
        require(isSuccess);

        if (version.startingIndex == 0 && (version.currentSupply == version.maxSupply || block.timestamp >= version.revealTime)) {
            _finalizeStartingIndex(versionId, version);
        }
    }

    function changeKnightName(
        uint knightId,
        string memory newName
    ) external override onlyKnightOwner(knightId) collectTokenAsFee(serviceFeeInToken, owner()) {
        require(_validateStr(newName), "MoonKnight: invalid name");
        require(reservedNames[newName] == false, "MoonKnight: name already exists");

        Knight storage knight = _knights[knightId];

        // If already named, de-reserve current name
        if (bytes(knight.name).length > 0) {
            reservedNames[knight.name] = false;
        }

        knight.name = newName;
        reservedNames[newName] = true;

        emit NameChanged(knightId, newName);
    }

    function equipItems(uint knightId, uint[] memory itemIds) external override onlyKnightOwner(knightId) {
        _setKnightEquipment(knightId, itemIds, false);

        equipmentContract.putItemsIntoStorage(msg.sender, itemIds);

        emit ItemsEquipped(knightId, itemIds);
    }

    function removeItems(uint knightId, uint[] memory itemIds) external override onlyKnightOwner(knightId) {
        _setKnightEquipment(knightId, itemIds, true);

        equipmentContract.returnItems(msg.sender, itemIds);

        emit ItemsUnequipped(knightId, itemIds);
    }

    function addFloorPriceToKnight(uint knightId) external override payable {
        Knight storage knight = _knights[knightId];
        uint newFloorPrice = knight.floorPrice + msg.value;

        require(msg.value > 0, "MoonKnight: no value sent");
        require(newFloorPrice <= 100 ether, "MoonKnight: cannot add more");
        require(acceptedToken.balanceOf(msg.sender) >= serviceFeeInToken, "MoonKnight: insufficient token balance");

        knight.floorPrice = newFloorPrice;
        acceptedToken.safeTransferFrom(msg.sender, owner(), serviceFeeInToken);

        emit KnightPriceIncreased(knightId, newFloorPrice, serviceFeeInToken);
    }

    function sacrificeKnight(uint knightId) external override nonReentrant onlyKnightOwner(knightId) {
        Knight storage knight = _knights[knightId];
        uint amount = knight.floorPrice;

        knight.floorPrice = 0;
        _burn(knightId);

        (bool isSuccess,) = msg.sender.call{value: amount}("");
        require(isSuccess);
    }

    function list(uint knightId, uint price) external override onlyKnightOwner(knightId) {
        require(price >= _knights[knightId].floorPrice, "MoonKnight: under floor price");

        knightsOnSale[knightId] = price;

        emit KnightListed(knightId, price);
    }

    function delist(uint knightId) external override onlyKnightOwner(knightId) {
        require(knightsOnSale[knightId] > 0, "MoonKnight: not listed");

        knightsOnSale[knightId] = 0;

        emit KnightDelisted(knightId);
    }

    function buy(uint knightId) external override payable nonReentrant {
        uint price = knightsOnSale[knightId];
        address seller = ownerOf(knightId);
        address buyer = msg.sender;

        require(price > 0, "MoonKnight: not on sale");
        require(msg.value == price, "MoonKnight: incorrect value");
        require(buyer != seller, "MoonKnight: cannot buy your own Knight");

        _makeTransaction(knightId, buyer, seller, price);

        emit KnightBought(knightId, buyer, seller, price);
    }

    function offer(uint knightId, uint offerValue) external override nonReentrant payable {
        address buyer = msg.sender;
        uint currentOffer = knightsWithOffers[knightId][buyer];
        bool needRefund = offerValue < currentOffer;
        uint requiredValue = needRefund ? 0 : offerValue - currentOffer;

        require(buyer != ownerOf(knightId), "MoonKnight: owner cannot offer");
        require(offerValue != currentOffer, "MoonKnight: same offer");
        require(msg.value == requiredValue, "MoonKnight: sent value incorrect");

        knightsWithOffers[knightId][buyer] = offerValue;

        if (needRefund) {
            uint returnedValue = currentOffer - offerValue;

            (bool success,) = buyer.call{value: returnedValue}("");
            require(success);
        }

        emit KnightOffered(knightId, buyer, offerValue);
    }

    function takeOffer(
        uint knightId,
        address buyer,
        uint minPrice
    ) external override nonReentrant onlyKnightOwner(knightId) {
        uint offeredValue = knightsWithOffers[knightId][buyer];
        address seller = msg.sender;

        require(offeredValue >= _knights[knightId].floorPrice, "MoonKnight: under floor price");
        require(offeredValue >= minPrice, "MoonKnight: less than min price");
        require(buyer != seller, "MoonKnight: cannot buy your own Knight");

        knightsWithOffers[knightId][buyer] = 0;

        _makeTransaction(knightId, buyer, seller, offeredValue);

        emit KnightBought(knightId, buyer, seller, offeredValue);
    }

    function cancelOffer(uint knightId) external override nonReentrant {
        address sender = msg.sender;
        uint offerValue = knightsWithOffers[knightId][sender];

        require(offerValue > 0, "MoonKnight: no offer found");

        knightsWithOffers[knightId][sender] = 0;

        (bool success,) = sender.call{value: offerValue}("");
        require(success);

        emit KnightOfferCanceled(knightId, sender);
    }

    function learnSkill(uint knightId, uint skillId) external override onlyKnightOwner(knightId) {
        IEquipment.ItemType itemType = equipmentContract.getItemType(skillId);
        EnumerableSet.UintSet storage skills = _knightSkills[knightId];

        require(itemType == IEquipment.ItemType.SKILL_BOOK, "MoonKnight: invalid skill book");

        bool isSuccess = skills.add(skillId);
        if (!isSuccess) revert("MoonKnight: already learned");

        uint[] memory skillIds = new uint[](1);
        skillIds[0] = skillId;
        equipmentContract.putItemsIntoStorage(msg.sender, skillIds);

        emit SkillLearned(knightId, skillId);
    }

    function adoptPet(uint knightId, uint petId) external override onlyKnightOwner(knightId) {
        require(petContract.ownerOf(petId) == msg.sender, "MoonKnight: not pet owner");

        _knightsWithPet[knightId] = petId;
        petContract.bindPet(petId);

        emit PetAdopted(knightId, petId);
    }

    function abandonPet(uint knightId) external override onlyKnightOwner(knightId) {
        uint petId = _knightsWithPet[knightId];

        require(petId != 0, "MoonKnight: no pet");

        _knightsWithPet[knightId] = 0;
        petContract.releasePet(petId);

        emit PetReleased(knightId, petId);
    }

    function levelUp(uint knightId, uint amount) external override onlyOperator {
        Knight storage knight = _knights[knightId];
        uint newLevel = knight.level + amount;

        require(amount > 0);
        require(newLevel <= maxLevel, "MoonKnight: max level reached");

        knight.level = newLevel;

        emit KnightLeveledUp(knightId, newLevel, amount);
    }

    function finalizeDuelResult(
        uint winningKnightId,
        uint losingKnightId,
        uint penaltyInBps
    ) external override onlyOperator {
        require(penaltyInBps <= BPS);

        Knight storage winningKnight = _knights[winningKnightId];
        Knight storage losingKnight = _knights[losingKnightId];
        uint baseFloorPrice = winningKnight.floorPrice > losingKnight.floorPrice ? losingKnight.floorPrice : winningKnight.floorPrice;

        uint penaltyAmount = baseFloorPrice * penaltyInBps / BPS;

        winningKnight.floorPrice += penaltyAmount;
        losingKnight.floorPrice -= penaltyAmount;

        emit DuelConcluded(winningKnightId, losingKnightId, penaltyAmount);
    }

    function getKnight(uint knightId) external view override returns (
        string memory name,
        uint level,
        uint floorPrice,
        uint pet,
        uint[] memory skills,
        uint[9] memory equipment
    ) {
        Knight memory knight = _knights[knightId];

        uint skillCount = _knightSkills[knightId].length();
        uint[] memory skillIds = new uint[](skillCount);
        for (uint i = 0; i < skillCount; i++) {
            skillIds[i] = _knightSkills[knightId].at(i);
        }

        name = knight.name;
        level = knight.level;
        floorPrice = knight.floorPrice;
        pet = _knightsWithPet[knightId];
        skills = skillIds;
        equipment = [
            knight.mainWeapon,
            knight.subWeapon,
            knight.headgear,
            knight.armor,
            knight.footwear,
            knight.pants,
            knight.gloves,
            knight.mount,
            knight.troop
        ];
    }

    function getKnightLevel(uint knightId) external view override returns (uint) {
        return _knights[knightId].level;
    }

    function getLatestVersion() public view returns (uint) {
        return versions.length - 1;
    }

    function totalSupply() external view returns (uint) {
        return _knights.length;
    }

    function _baseURI() internal view override returns (string memory) {
        return _uri;
    }

    function _makeTransaction(uint knightId, address buyer, address seller, uint price) private {
        Knight storage knight = _knights[knightId];
        uint floorPrice = price * floorPriceInBps / BPS;
        uint marketFee = price * marketFeeInBps / BPS;
        uint newPrice = knight.floorPrice + floorPrice;

        knightsOnSale[knightId] = 0;
        knight.floorPrice = newPrice;

        (bool transferToSeller,) = seller.call{value: price - (floorPrice + marketFee)}("");
        require(transferToSeller);

        (bool transferToTreasury,) = owner().call{value: marketFee}("");
        require(transferToTreasury);

        _transfer(seller, buyer, knightId);

        emit KnightPriceIncreased(knightId, newPrice, floorPrice);
    }

    function _createKnight(uint floorPrice) private returns (uint knightId) {
        _knights.push(Knight("", 1, floorPrice, 0, 0, 0, 0, 0, 0, 0, 0, 0));
        knightId = _knights.length - 1;
        emit KnightCreated(knightId, floorPrice);
    }

    function _setKnightEquipment(uint knightId, uint[] memory itemIds, bool isRemove) private {
        require(knightsOnSale[knightId] == 0, "MoonKnight: cannot change items while on sale");
        require(itemIds.length > 0, "MoonKnight: no item");

        Knight storage knight = _knights[knightId];
        bool[] memory itemSet = new bool[](9);

        for (uint i = 0; i < itemIds.length; i++) {
            uint itemId = itemIds[i];
            uint updatedItemId = isRemove ? 0 : itemId;
            IEquipment.ItemType itemType = equipmentContract.getItemType(itemId);

            require(itemId != 0, "MoonKnight: invalid itemId");
            require(itemType != IEquipment.ItemType.SKILL_BOOK, "MoonKnight: cannot equip skill book");
            require(!itemSet[uint(itemType)], "MoonKnight: duplicate itemType");

            if (itemType == IEquipment.ItemType.MAIN_WEAPON) {
                require(isRemove ? knight.mainWeapon == itemId : knight.mainWeapon == 0, "MoonKnight : invalid mainWeapon");
                knight.mainWeapon = updatedItemId;
                itemSet[uint(IEquipment.ItemType.MAIN_WEAPON)] = true;
            } else if (itemType == IEquipment.ItemType.SUB_WEAPON) {
                require(isRemove ? knight.subWeapon == itemId : knight.subWeapon == 0, "MoonKnight : invalid subWeapon");
                knight.subWeapon = updatedItemId;
                itemSet[uint(IEquipment.ItemType.SUB_WEAPON)] = true;
            } else if (itemType == IEquipment.ItemType.HEADGEAR) {
                require(isRemove ? knight.headgear == itemId : knight.headgear == 0, "MoonKnight : invalid headgear");
                knight.headgear = updatedItemId;
                itemSet[uint(IEquipment.ItemType.HEADGEAR)] = true;
            } else if (itemType == IEquipment.ItemType.ARMOR) {
                require(isRemove ? knight.armor == itemId : knight.armor == 0, "MoonKnight : invalid armor");
                knight.armor = updatedItemId;
                itemSet[uint(IEquipment.ItemType.ARMOR)] = true;
            } else if (itemType == IEquipment.ItemType.FOOTWEAR) {
                require(isRemove ? knight.footwear == itemId : knight.footwear == 0, "MoonKnight : invalid footwear");
                knight.footwear = updatedItemId;
                itemSet[uint(IEquipment.ItemType.FOOTWEAR)] = true;
            } else if (itemType == IEquipment.ItemType.PANTS) {
                require(isRemove ? knight.pants == itemId : knight.pants == 0, "MoonKnight : invalid pants");
                knight.pants = updatedItemId;
                itemSet[uint(IEquipment.ItemType.PANTS)] = true;
            } else if (itemType == IEquipment.ItemType.GLOVES) {
                require(isRemove ? knight.gloves == itemId : knight.gloves == 0, "MoonKnight : invalid gloves");
                knight.gloves = updatedItemId;
                itemSet[uint(IEquipment.ItemType.GLOVES)] = true;
            } else if (itemType == IEquipment.ItemType.MOUNT) {
                require(isRemove ? knight.mount == itemId : knight.mount == 0, "MoonKnight : invalid mount");
                knight.mount = updatedItemId;
                itemSet[uint(IEquipment.ItemType.MOUNT)] = true;
            } else if (itemType == IEquipment.ItemType.TROOP) {
                require(isRemove ? knight.troop == itemId : knight.troop == 0, "MoonKnight : invalid troop");
                knight.troop = updatedItemId;
                itemSet[uint(IEquipment.ItemType.TROOP)] = true;
            }
        }
    }

    function _finalizeStartingIndex(uint versionId, Version storage version) private {
        uint startingIndex = uint(keccak256(abi.encodePacked(block.difficulty, block.timestamp))) % version.maxSupply;
        if (startingIndex == 0) startingIndex = startingIndex + 1;
        version.startingIndex = startingIndex;

        emit StartingIndexFinalized(versionId, startingIndex);
    }

    /**
     * @dev Check if the name string is valid (Alphanumeric and spaces without leading or trailing space)
     */
    function _validateStr(string memory str) internal pure returns (bool) {
        bytes memory b = bytes(str);
        if (b.length < 1) return false;
        if (b.length > 20) return false;

        // Leading space
        if (b[0] == 0x20) return false;

        // Trailing space
        if (b[b.length - 1] == 0x20) return false;

        bytes1 lastChar = b[0];

        for (uint i; i < b.length; i++) {
            bytes1 char = b[i];

            // Cannot contain continuous spaces
            if (char == 0x20 && lastChar == 0x20) return false;

            if (
                !(char >= 0x30 && char <= 0x39) && //9-0
                !(char >= 0x41 && char <= 0x5A) && //A-Z
                !(char >= 0x61 && char <= 0x7A) && //a-z
                !(char == 0x20) //space
            ) {
                return false;
            }

            lastChar = char;
        }

        return true;
    }
}

File 2 of 20 : ERC721.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "./extensions/IERC721Metadata.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/Strings.sol";
import "../../utils/introspection/ERC165.sol";

/**
 * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
 * the Metadata extension, but not including the Enumerable extension, which is available separately as
 * {ERC721Enumerable}.
 */
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
    using Address for address;
    using Strings for uint256;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Mapping from token ID to owner address
    mapping (uint256 => address) private _owners;

    // Mapping owner address to token count
    mapping (address => uint256) private _balances;

    // Mapping from token ID to approved address
    mapping (uint256 => address) private _tokenApprovals;

    // Mapping from owner to operator approvals
    mapping (address => mapping (address => bool)) private _operatorApprovals;

    /**
     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
     */
    constructor (string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

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

    /**
     * @dev See {IERC721-balanceOf}.
     */
    function balanceOf(address owner) public view virtual override returns (uint256) {
        require(owner != address(0), "ERC721: balance query for the zero address");
        return _balances[owner];
    }

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId) public view virtual override returns (address) {
        address owner = _owners[tokenId];
        require(owner != address(0), "ERC721: owner query for nonexistent token");
        return owner;
    }

    /**
     * @dev See {IERC721Metadata-name}.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev See {IERC721Metadata-symbol}.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

        string memory baseURI = _baseURI();
        return bytes(baseURI).length > 0
            ? string(abi.encodePacked(baseURI, tokenId.toString()))
            : '';
    }

    /**
     * @dev Base URI for computing {tokenURI}. Empty by default, can be overriden
     * in child contracts.
     */
    function _baseURI() internal view virtual returns (string memory) {
        return "";
    }

    /**
     * @dev See {IERC721-approve}.
     */
    function approve(address to, uint256 tokenId) public virtual override {
        address owner = ERC721.ownerOf(tokenId);
        require(to != owner, "ERC721: approval to current owner");

        require(_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
            "ERC721: approve caller is not owner nor approved for all"
        );

        _approve(to, tokenId);
    }

    /**
     * @dev See {IERC721-getApproved}.
     */
    function getApproved(uint256 tokenId) public view virtual override returns (address) {
        require(_exists(tokenId), "ERC721: approved query for nonexistent token");

        return _tokenApprovals[tokenId];
    }

    /**
     * @dev See {IERC721-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved) public virtual override {
        require(operator != _msgSender(), "ERC721: approve to caller");

        _operatorApprovals[_msgSender()][operator] = approved;
        emit ApprovalForAll(_msgSender(), operator, approved);
    }

    /**
     * @dev See {IERC721-isApprovedForAll}.
     */
    function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
        return _operatorApprovals[owner][operator];
    }

    /**
     * @dev See {IERC721-transferFrom}.
     */
    function transferFrom(address from, address to, uint256 tokenId) public virtual override {
        //solhint-disable-next-line max-line-length
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");

        _transfer(from, to, tokenId);
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override {
        safeTransferFrom(from, to, tokenId, "");
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override {
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
        _safeTransfer(from, to, tokenId, _data);
    }

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * `_data` is additional data, it has no specified format and it is sent in call to `to`.
     *
     * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
     * implement alternative mechanisms to perform token transfer, such as signature-based.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual {
        _transfer(from, to, tokenId);
        require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }

    /**
     * @dev Returns whether `tokenId` exists.
     *
     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
     *
     * Tokens start existing when they are minted (`_mint`),
     * and stop existing when they are burned (`_burn`).
     */
    function _exists(uint256 tokenId) internal view virtual returns (bool) {
        return _owners[tokenId] != address(0);
    }

    /**
     * @dev Returns whether `spender` is allowed to manage `tokenId`.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
        require(_exists(tokenId), "ERC721: operator query for nonexistent token");
        address owner = ERC721.ownerOf(tokenId);
        return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
    }

    /**
     * @dev Safely mints `tokenId` and transfers it to `to`.
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeMint(address to, uint256 tokenId) internal virtual {
        _safeMint(to, tokenId, "");
    }

    /**
     * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
     */
    function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual {
        _mint(to, tokenId);
        require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }

    /**
     * @dev Mints `tokenId` and transfers it to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - `to` cannot be the zero address.
     *
     * Emits a {Transfer} event.
     */
    function _mint(address to, uint256 tokenId) internal virtual {
        require(to != address(0), "ERC721: mint to the zero address");
        require(!_exists(tokenId), "ERC721: token already minted");

        _beforeTokenTransfer(address(0), to, tokenId);

        _balances[to] += 1;
        _owners[tokenId] = to;

        emit Transfer(address(0), to, tokenId);
    }

    /**
     * @dev Destroys `tokenId`.
     * The approval is cleared when the token is burned.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     *
     * Emits a {Transfer} event.
     */
    function _burn(uint256 tokenId) internal virtual {
        address owner = ERC721.ownerOf(tokenId);

        _beforeTokenTransfer(owner, address(0), tokenId);

        // Clear approvals
        _approve(address(0), tokenId);

        _balances[owner] -= 1;
        delete _owners[tokenId];

        emit Transfer(owner, address(0), tokenId);
    }

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     *
     * Emits a {Transfer} event.
     */
    function _transfer(address from, address to, uint256 tokenId) internal virtual {
        require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
        require(to != address(0), "ERC721: transfer to the zero address");

        _beforeTokenTransfer(from, to, tokenId);

        // Clear approvals from the previous owner
        _approve(address(0), tokenId);

        _balances[from] -= 1;
        _balances[to] += 1;
        _owners[tokenId] = to;

        emit Transfer(from, to, tokenId);
    }

    /**
     * @dev Approve `to` to operate on `tokenId`
     *
     * Emits a {Approval} event.
     */
    function _approve(address to, uint256 tokenId) internal virtual {
        _tokenApprovals[tokenId] = to;
        emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
    }

    /**
     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
     * The call is not executed if the target address is not a contract.
     *
     * @param from address representing the previous owner of the given token ID
     * @param to target address that will receive the tokens
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes optional data to send along with the call
     * @return bool whether the call correctly returned the expected magic value
     */
    function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
        private returns (bool)
    {
        if (to.isContract()) {
            try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
                return retval == IERC721Receiver(to).onERC721Received.selector;
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert("ERC721: transfer to non ERC721Receiver implementer");
                } else {
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        } else {
            return true;
        }
    }

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

File 3 of 20 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

File 4 of 20 : SafeERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

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

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

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

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 5 of 20 : EnumerableSet.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;

        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping (bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) { // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

            bytes32 lastvalue = set._values[lastIndex];

            // Move the last value to the index where the value to delete is
            set._values[toDeleteIndex] = lastvalue;
            // Update the index for the moved value
            set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        require(set._values.length > index, "EnumerableSet: index out of bounds");
        return set._values[index];
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }


    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }
}

File 6 of 20 : Ownable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

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

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

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

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

File 7 of 20 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor () {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

File 8 of 20 : IMoonKnight.sol
//SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IMoonKnight {
    struct Knight {
        string name;
        uint level;
        uint floorPrice;
        uint mainWeapon;
        uint subWeapon;
        uint headgear;
        uint armor;
        uint footwear;
        uint pants;
        uint gloves;
        uint mount;
        uint troop;
    }

    struct Version {
        uint startingIndex;
        uint currentSupply;
        uint maxSupply;
        uint salePrice;
        uint startTime;
        uint revealTime;
        string provenance; // This is the provenance record of all MoonKnight artworks in existence.
    }

    event KnightCreated(uint indexed knightId, uint floorPrice);
    event KnightListed(uint indexed knightId, uint price);
    event KnightDelisted(uint indexed knightId);
    event KnightBought(uint indexed knightId, address buyer, address seller, uint price);
    event KnightOffered(uint indexed knightId, address buyer, uint price);
    event KnightOfferCanceled(uint indexed knightId, address buyer);
    event KnightPriceIncreased(uint indexed knightId, uint floorPrice, uint increasedAmount);
    event NameChanged(uint indexed knightId, string newName);
    event PetAdopted(uint indexed knightId, uint indexed petId);
    event PetReleased(uint indexed knightId, uint indexed petId);
    event SkillLearned(uint indexed knightId, uint indexed skillId);
    event ItemsEquipped(uint indexed knightId, uint[] itemIds);
    event ItemsUnequipped(uint indexed knightId, uint[] itemIds);
    event KnightLeveledUp(uint indexed knightId, uint level, uint amount);
    event DuelConcluded(uint indexed winningKnightId, uint indexed losingKnightId, uint penaltyAmount);
    event StartingIndexFinalized(uint versionId, uint startingIndex);
    event NewVersionAdded(uint versionId);

    /**
     * @notice Claims moon knights when it's on presale phase.
     */
    function claimMoonKnight(uint versionId, uint amount) external payable;

    /**
     * @notice Changes a knight's name.
     *
     * Requirements:
     * - `newName` must be a valid string.
     * - `newName` is not duplicated to other.
     * - Token required: `serviceFeeInToken`.
     */
    function changeKnightName(uint knightId, string memory newName) external;

    /**
     * @notice Anyone can call this function to manually add `floorPrice` to a knight.
     *
     * Requirements:
     * - `msg.value` must not be zero.
     * - knight's `floorPrice` must be under `floorPriceCap`.
     * - Token required: `serviceFeeInToken` * value
     */
    function addFloorPriceToKnight(uint knightId) external payable;

    /**
     * @notice Owner equips items to their knight by burning ERC1155 Equipment NFTs.
     *
     * Requirements:
     * - caller must be owner of the knight.
     */
    function equipItems(uint knightId, uint[] memory itemIds) external;

    /**
     * @notice Owner removes items from their knight. ERC1155 Equipment NFTs are minted back to the owner.
     *
     * Requirements:
     * - caller must be owner of the knight.
     */
    function removeItems(uint knightId, uint[] memory itemIds) external;

    /**
     * @notice Burns a knight to claim its `floorPrice`.
     *
     * - Not financial advice: DONT DO THAT.
     * - Remember to remove all items before calling this function.
     */
    function sacrificeKnight(uint knightId) external;

    /**
     * @notice Lists a knight on sale.
     *
     * Requirements:
     * - `price` cannot be under knight's `floorPrice`.
     * - Caller must be the owner of the knight.
     */
    function list(uint knightId, uint price) external;

    /**
     * @notice Delist a knight on sale.
     */
    function delist(uint knightId) external;

    /**
     * @notice Instant buy a specific knight on sale.
     *
     * Requirements:
     * - Target knight must be currently on sale.
     * - Sent value must be exact the same as current listing price.
     */
    function buy(uint knightId) external payable;

    /**
     * @notice Gives offer for a knight.
     *
     * Requirements:
     * - Owner cannot offer.
     */
    function offer(uint knightId, uint offerValue) external payable;

    /**
     * @notice Owner take an offer to sell their knight.
     *
     * Requirements:
     * - Cannot take offer under knight's `floorPrice`.
     * - Offer value must be at least equal to `minPrice`.
     */
    function takeOffer(uint knightId, address offerAddr, uint minPrice) external;

    /**
     * @notice Cancels an offer for a specific knight.
     */
    function cancelOffer(uint knightId) external;

    /**
     * @notice Learns a skill for given Knight.
     */
    function learnSkill(uint knightId, uint skillId) external;

    /**
     * @notice Adopts a Pet.
     */
    function adoptPet(uint knightId, uint petId) external;

    /**
     * @notice Abandons a Pet attached to a Knight.
     */
    function abandonPet(uint knightId) external;

    /**
     * @notice Operators can level up a Knight
     */
    function levelUp(uint knightId, uint amount) external;

    /**
     * @notice Finalizes the battle aftermath of 2 knights.
     */
    function finalizeDuelResult(uint winningKnightId, uint losingKnightId, uint penaltyInBps) external;

    /**
     * @notice Gets knight information.
     */
    function getKnight(uint knightId) external view returns (
        string memory name,
        uint level,
        uint floorPrice,
        uint pet,
        uint[] memory skills,
        uint[9] memory equipment
    );

    /**
     * @notice Gets current level of given knight.
     */
    function getKnightLevel(uint knightId) external view returns (uint);
}

File 9 of 20 : IEquipment.sol
//SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IEquipment {
    enum ItemType { MAIN_WEAPON, SUB_WEAPON, HEADGEAR, ARMOR, FOOTWEAR, PANTS, GLOVES, MOUNT, TROOP, SKILL_BOOK }
    enum Rarity { COMMON, UNCOMMON, RARE, EPIC, LEGENDARY, MYTHICAL }

    struct Item {
        string name;
        uint16 maxSupply;
        uint16 minted;
        uint16 burnt;
        uint8 tier;
        uint8 upgradeAmount;
        ItemType itemType;
        Rarity rarity;
    }

    event ItemCreated(uint indexed itemId, string name, uint16 maxSupply, ItemType itemType, Rarity rarity);
    event ItemUpgradable(uint indexed itemId, uint indexed nextTierItemId, uint8 upgradeAmount);

    /**
     * @notice Create an item.
     */
    function createItem(string memory name, uint16 maxSupply, ItemType itemType, Rarity rarity) external;

    /**
     * @notice Add next tier item to existing one.
     */
    function addNextTierItem(uint itemId, uint8 upgradeAmount) external;

    /**
     * @notice Burns the same items to upgrade its tier.
     *
     * Requirements:
     * - sufficient token balance.
     * - Item must have its next tier.
     * - Sender's balance must have at least `upgradeAmount`
     */
    function upgradeItem(uint itemId) external;

    /**
     * @notice Pays some fee to get random items.
     */
    function rollEquipmentGacha(uint vendorId, uint amount) external;

    /**
     * @notice Mints items and returns true if it's run out of stock.
     */
    function mint(address account, uint itemId, uint16 amount) external returns (bool);

    /**
     * @notice Burns ERC1155 equipment since it is equipped to the knight.
     */
    function putItemsIntoStorage(address account, uint[] memory itemIds) external;

    /**
     * @notice Returns ERC1155 equipment back to the owner.
     */
    function returnItems(address account, uint[] memory itemIds) external;

    /**
     * @notice Gets item information.
     */
    function getItem(uint itemId) external view returns (Item memory item);

    /**
     * @notice Gets item type.
     */
    function getItemType(uint itemId) external view returns (ItemType);

    /**
     * @notice Check if item is out of stock.
     */
    function isOutOfStock(uint itemId, uint16 amount) external view returns (bool);
}

File 10 of 20 : IPet.sol
//SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IPet {
    /**
     * @notice Temporarily burn a pet.
     */
    function bindPet(uint petId) external;

    /**
     * @notice Release given pet back into user inventory.
     */
    function releasePet(uint petId) external;

    /**
     * @notice Gets owner of given pet.
     */
    function ownerOf(uint petId) external view returns (address);
}

File 11 of 20 : AcceptedToken.sol
//SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "./PermissionGroup.sol";

contract AcceptedToken is PermissionGroup {
    using SafeERC20 for IERC20;

    // Token to be used in the ecosystem.
    IERC20 public acceptedToken;

    constructor(IERC20 tokenAddress) {
        acceptedToken = tokenAddress;
    }

    modifier collectTokenAsFee(uint amount, address destAddr) {
        require(acceptedToken.balanceOf(msg.sender) >= amount, "AcceptedToken: insufficient token balance");
        _;
        acceptedToken.safeTransferFrom(msg.sender, destAddr, amount);
    }

    /**
     * @dev Sets accepted token using in the ecosystem.
     */
    function setAcceptedTokenContract(IERC20 tokenAddr) external onlyOwner {
        require(address(tokenAddr) != address(0));
        acceptedToken = tokenAddr;
    }
}

File 12 of 20 : IERC721.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);

    /**
      * @dev Safely transfers `tokenId` token from `from` to `to`.
      *
      * Requirements:
      *
      * - `from` cannot be the zero address.
      * - `to` cannot be the zero address.
      * - `tokenId` token must exist and be owned by `from`.
      * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
      * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
      *
      * Emits a {Transfer} event.
      */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
}

File 13 of 20 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @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 `IERC721.onERC721Received.selector`.
     */
    function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4);
}

File 14 of 20 : IERC721Metadata.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {

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

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

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

File 15 of 20 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain`call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
      return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 16 of 20 : Context.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

    function _msgData() internal view virtual returns (bytes calldata) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

File 17 of 20 : Strings.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

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

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

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

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

}

File 18 of 20 : ERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IERC165.sol";

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

File 19 of 20 : IERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

File 20 of 20 : PermissionGroup.sol
//SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Context.sol";

contract PermissionGroup is Ownable {
    // List of authorized address to perform some restricted actions
    mapping(address => bool) public operators;

    modifier onlyOperator() {
        require(operators[msg.sender], "PermissionGroup: not operator");
        _;
    }

    /**
     * @notice Adds an address as operator.
     */
    function addOperator(address operator) external onlyOwner {
        operators[operator] = true;
    }

    /**
    * @notice Removes an address as operator.
    */
    function removeOperator(address operator) external onlyOwner {
        operators[operator] = false;
    }
}

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

Contract ABI

[{"inputs":[{"internalType":"contract IEquipment","name":"equipmentAddress","type":"address"},{"internalType":"contract IERC20","name":"tokenAddress","type":"address"},{"internalType":"string","name":"baseURI","type":"string"},{"internalType":"uint256","name":"maxSupply","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"revealTime","type":"uint256"},{"internalType":"string","name":"provenance","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"winningKnightId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"losingKnightId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"penaltyAmount","type":"uint256"}],"name":"DuelConcluded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"knightId","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"itemIds","type":"uint256[]"}],"name":"ItemsEquipped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"knightId","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"itemIds","type":"uint256[]"}],"name":"ItemsUnequipped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"knightId","type":"uint256"},{"indexed":false,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"address","name":"seller","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"KnightBought","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"knightId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"floorPrice","type":"uint256"}],"name":"KnightCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"knightId","type":"uint256"}],"name":"KnightDelisted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"knightId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"level","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"KnightLeveledUp","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"knightId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"KnightListed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"knightId","type":"uint256"},{"indexed":false,"internalType":"address","name":"buyer","type":"address"}],"name":"KnightOfferCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"knightId","type":"uint256"},{"indexed":false,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"KnightOffered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"knightId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"floorPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"increasedAmount","type":"uint256"}],"name":"KnightPriceIncreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"knightId","type":"uint256"},{"indexed":false,"internalType":"string","name":"newName","type":"string"}],"name":"NameChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"versionId","type":"uint256"}],"name":"NewVersionAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"knightId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"petId","type":"uint256"}],"name":"PetAdopted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"knightId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"petId","type":"uint256"}],"name":"PetReleased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"knightId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"skillId","type":"uint256"}],"name":"SkillLearned","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"versionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startingIndex","type":"uint256"}],"name":"StartingIndexFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"uint256","name":"knightId","type":"uint256"}],"name":"abandonPet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"acceptedToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"knightId","type":"uint256"}],"name":"addFloorPriceToKnight","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxSupply","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"revealTime","type":"uint256"},{"internalType":"string","name":"provenance","type":"string"}],"name":"addNewVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"addOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"knightId","type":"uint256"},{"internalType":"uint256","name":"petId","type":"uint256"}],"name":"adoptPet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"knightId","type":"uint256"}],"name":"buy","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"knightId","type":"uint256"}],"name":"cancelOffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"knightId","type":"uint256"},{"internalType":"string","name":"newName","type":"string"}],"name":"changeKnightName","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"versionId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"claimMoonKnight","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"knightId","type":"uint256"}],"name":"delist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"knightId","type":"uint256"},{"internalType":"uint256[]","name":"itemIds","type":"uint256[]"}],"name":"equipItems","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"equipmentContract","outputs":[{"internalType":"contract IEquipment","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"winningKnightId","type":"uint256"},{"internalType":"uint256","name":"losingKnightId","type":"uint256"},{"internalType":"uint256","name":"penaltyInBps","type":"uint256"}],"name":"finalizeDuelResult","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"floorPriceInBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"knightId","type":"uint256"}],"name":"getKnight","outputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"level","type":"uint256"},{"internalType":"uint256","name":"floorPrice","type":"uint256"},{"internalType":"uint256","name":"pet","type":"uint256"},{"internalType":"uint256[]","name":"skills","type":"uint256[]"},{"internalType":"uint256[9]","name":"equipment","type":"uint256[9]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"knightId","type":"uint256"}],"name":"getKnightLevel","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLatestVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"knightsOnSale","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"knightsWithOffers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"knightId","type":"uint256"},{"internalType":"uint256","name":"skillId","type":"uint256"}],"name":"learnSkill","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"knightId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"levelUp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"knightId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"}],"name":"list","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"marketFeeInBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLevel","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"knightId","type":"uint256"},{"internalType":"uint256","name":"offerValue","type":"uint256"}],"name":"offer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"operators","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"petContract","outputs":[{"internalType":"contract IPet","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"knightId","type":"uint256"},{"internalType":"uint256[]","name":"itemIds","type":"uint256[]"}],"name":"removeItems","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"removeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"reservedNames","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"knightId","type":"uint256"}],"name":"sacrificeKnight","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"serviceFeeInToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"tokenAddr","type":"address"}],"name":"setAcceptedTokenContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"baseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IEquipment","name":"equipmentAddress","type":"address"}],"name":"setEquipmentContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"floorPrice","type":"uint256"},{"internalType":"uint256","name":"marketFee","type":"uint256"}],"name":"setFloorPriceAndMarketFeeInBps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMaxLevel","type":"uint256"}],"name":"setMaxLevel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IPet","name":"petAddress","type":"address"}],"name":"setPetContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"setServiceFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"knightId","type":"uint256"},{"internalType":"address","name":"buyer","type":"address"},{"internalType":"uint256","name":"minPrice","type":"uint256"}],"name":"takeOffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"versions","outputs":[{"internalType":"uint256","name":"startingIndex","type":"uint256"},{"internalType":"uint256","name":"currentSupply","type":"uint256"},{"internalType":"uint256","name":"maxSupply","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"revealTime","type":"uint256"},{"internalType":"string","name":"provenance","type":"string"}],"stateMutability":"view","type":"function"}]

608060405260c8600c556016600d5568056bc75e2d63100000600e556064600f553480156200002d57600080fd5b506040516200656038038062006560833981016040819052620000509162000432565b604080518082018252600a815269135bdbdb92db9a59da1d60b21b60208083019182528351808501909452600684526512d39251d21560d21b9084015281518a9391620000a19160009190620002e1565b508051620000b7906001906020840190620002e1565b5050506000620000cc620002dd60201b60201c565b600680546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350600880546001600160a01b03199081166001600160a01b03938416179091556001600955600a8054909116918a16919091179055855162000163906010906020890190620002e1565b506040805160e08101825260008082526020808301828152938301898152606084018981526080850189815260a0860189815260c08701898152601180546001810182559752875160079097027f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c68810197885598517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c698a015593517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6a89015591517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6b880155517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6c870155517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6d86015551805193949293620002cc937f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6e01929190910190620002e1565b505050505050505050505062000557565b3390565b828054620002ef90620004eb565b90600052602060002090601f0160209004810192826200031357600085556200035e565b82601f106200032e57805160ff19168380011785556200035e565b828001600101855582156200035e579182015b828111156200035e57825182559160200191906001019062000341565b506200036c92915062000370565b5090565b5b808211156200036c576000815560010162000371565b600082601f83011262000398578081fd5b81516001600160401b0380821115620003b557620003b562000528565b6040516020601f8401601f1916820181018381118382101715620003dd57620003dd62000528565b6040528382528584018101871015620003f4578485fd5b8492505b83831015620004175785830181015182840182015291820191620003f8565b838311156200042857848185840101525b5095945050505050565b600080600080600080600080610100898b0312156200044f578384fd5b88516200045c816200053e565b60208a01519098506200046f816200053e565b60408a01519097506001600160401b03808211156200048c578586fd5b6200049a8c838d0162000387565b975060608b0151965060808b0151955060a08b0151945060c08b0151935060e08b0151915080821115620004cc578283fd5b50620004db8b828c0162000387565b9150509295985092959890939650565b6002810460018216806200050057607f821691505b602082108114156200052257634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146200055457600080fd5b50565b615ff980620005676000396000f3fe60806040526004361061030c5760003560e01c806370a082311161019c578063b3517b93116100e2578063cc06c35911610090578063cc06c3591461092a578063d96a094a1461093f578063db2e5bde14610952578063dc2b045d14610972578063e985e9c514610992578063ef706adf146109b2578063f2fde38b146109d2578063ff611a9a146109f25761030c565b8063b3517b9314610857578063b5a045f71461086a578063b856717a1461088a578063b88d4fde146108aa578063c0b83d28146108ca578063c467e7e9146108ea578063c87b56dd1461090a5761030c565b8063964bc33f1161014a578063964bc33f1461077a5780639870d7fe1461079a5780639997e137146107ba578063a1920586146107cf578063a22cb465146107e2578063a51dabd014610802578063a68aa72614610817578063ac8a584a146108375761030c565b806370a08231146106b5578063715018a6146106d55780637363e025146106ea578063785ea864146106fd57806387aee00e1461071d5780638da5cb5b1461075057806395d89b41146107655761030c565b8063344f1ba511610261578063559b1ef61161020f578063559b1ef6146105ae57806355f804b3146105ce57806359c656be146105ee5780635cdf76f8146106205780636352211e146106405780636644a3501461066057806368436f101461067557806369333963146106955761030c565b8063344f1ba5146104d957806340fac938146104f957806342842e0e14610519578063451c3d801461053957806350fd73671461054e5780635226dc931461056e57806352d68d6c1461058e5761030c565b8063119f0ef8116102be578063119f0ef81461041a57806313e7c9d81461042f57806318160ddd1461044f5780631872ef121461046457806323b872dd1461048457806327b3a385146104a457806331debdb9146104b95761030c565b806301ffc9a71461031157806306fdde0314610347578063081812fc14610369578063082459fa14610396578063095ea7b3146103b85780630b3fdf17146103d85780630e6d1de9146103f8575b600080fd5b34801561031d57600080fd5b5061033161032c366004614a0e565b610a12565b60405161033e9190614ed6565b60405180910390f35b34801561035357600080fd5b5061035c610a5a565b60405161033e9190614ee1565b34801561037557600080fd5b50610389610384366004614a97565b610aec565b60405161033e9190614e11565b3480156103a257600080fd5b506103b66103b1366004614aeb565b610b38565b005b3480156103c457600080fd5b506103b66103d33660046149c7565b610cd4565b3480156103e457600080fd5b506103b66103f3366004614a97565b610d6c565b34801561040457600080fd5b5061040d610e81565b60405161033e9190615dab565b34801561042657600080fd5b50610389610e98565b34801561043b57600080fd5b5061033161044a36600461486e565b610ea7565b34801561045b57600080fd5b5061040d610ebc565b34801561047057600080fd5b506103b661047f36600461486e565b610ec2565b34801561049057600080fd5b506103b661049f3660046148de565b610f36565b3480156104b057600080fd5b5061040d610f6e565b3480156104c557600080fd5b506103b66104d4366004614c07565b610f74565b3480156104e557600080fd5b506103b66104f4366004614a97565b610fd6565b34801561050557600080fd5b506103b6610514366004614c07565b611028565b34801561052557600080fd5b506103b66105343660046148de565b61123e565b34801561054557600080fd5b50610389611259565b34801561055a57600080fd5b506103b6610569366004614c07565b611268565b34801561057a57600080fd5b506103b6610589366004614c07565b61133b565b34801561059a57600080fd5b506103b66105a936600461486e565b611429565b3480156105ba57600080fd5b506103b66105c9366004614b11565b61149d565b3480156105da57600080fd5b506103b66105e9366004614a65565b61156e565b3480156105fa57600080fd5b5061060e610609366004614a97565b6115c4565b60405161033e96959493929190614ef4565b34801561062c57600080fd5b506103b661063b366004614a97565b61188c565b34801561064c57600080fd5b5061038961065b366004614a97565b6118d0565b34801561066c57600080fd5b5061040d611905565b34801561068157600080fd5b50610331610690366004614a65565b61190b565b3480156106a157600080fd5b506103b66106b0366004614c07565b61192b565b3480156106c157600080fd5b5061040d6106d036600461486e565b611aa8565b3480156106e157600080fd5b506103b6611aec565b6103b66106f8366004614c07565b611b75565b34801561070957600080fd5b506103b6610718366004614a97565b611d8a565b34801561072957600080fd5b5061073d610738366004614a97565b611e8d565b60405161033e9796959493929190615db4565b34801561075c57600080fd5b50610389611f67565b34801561077157600080fd5b5061035c611f76565b34801561078657600080fd5b506103b6610795366004614a97565b611f85565b3480156107a657600080fd5b506103b66107b536600461486e565b61201d565b3480156107c657600080fd5b50610389612080565b6103b66107dd366004614c07565b61208f565b3480156107ee57600080fd5b506103b66107fd36600461499a565b612240565b34801561080e57600080fd5b5061040d61230e565b34801561082357600080fd5b506103b661083236600461486e565b612314565b34801561084357600080fd5b506103b661085236600461486e565b612388565b6103b6610865366004614a97565b6123e8565b34801561087657600080fd5b506103b6610885366004614bc3565b612577565b34801561089657600080fd5b506103b66108a5366004614b11565b6127ce565b3480156108b657600080fd5b506103b66108c536600461491e565b61289f565b3480156108d657600080fd5b5061040d6108e5366004614a97565b6128de565b3480156108f657600080fd5b5061040d610905366004614ac7565b6128f0565b34801561091657600080fd5b5061035c610925366004614a97565b61290d565b34801561093657600080fd5b5061040d612990565b6103b661094d366004614a97565b612996565b34801561095e57600080fd5b506103b661096d366004614c28565b612a9b565b34801561097e57600080fd5b506103b661098d366004614c53565b612bf5565b34801561099e57600080fd5b506103316109ad3660046148a6565b612f15565b3480156109be57600080fd5b506103b66109cd366004614a97565b612f45565b3480156109de57600080fd5b506103b66109ed36600461486e565b613057565b3480156109fe57600080fd5b5061040d610a0d366004614a97565b613118565b60006001600160e01b031982166380ac58cd60e01b1480610a4357506001600160e01b03198216635b5e139f60e01b145b80610a525750610a5282613154565b90505b919050565b606060008054610a6990615ebb565b80601f0160208091040260200160405190810160405280929190818152602001828054610a9590615ebb565b8015610ae25780601f10610ab757610100808354040283529160200191610ae2565b820191906000526020600020905b815481529060010190602001808311610ac557829003601f168201915b5050505050905090565b6000610af78261316d565b610b1c5760405162461bcd60e51b8152600401610b13906156bf565b60405180910390fd5b506000908152600460205260409020546001600160a01b031690565b60026009541415610b5b5760405162461bcd60e51b8152600401610b1390615d41565b60026009558233610b6b826118d0565b6001600160a01b031614610b915760405162461bcd60e51b8152600401610b13906155a8565b60008481526013602090815260408083206001600160a01b03871684529091529020546015805433919087908110610bd957634e487b7160e01b600052603260045260246000fd5b90600052602060002090600c020160020154821015610c0a5760405162461bcd60e51b8152600401610b1390615779565b83821015610c2a5760405162461bcd60e51b8152600401610b1390615a4f565b806001600160a01b0316856001600160a01b03161415610c5c5760405162461bcd60e51b8152600401610b13906155df565b60008681526013602090815260408083206001600160a01b0389168452909152812055610c8b8686838561318a565b857f8e5b24f8b069110da0f44ac86e8883213e03a2290268235615824c0e86280d47868385604051610cbf93929190614e25565b60405180910390a25050600160095550505050565b6000610cdf826118d0565b9050806001600160a01b0316836001600160a01b03161415610d135760405162461bcd60e51b8152600401610b1390615a0e565b806001600160a01b0316610d25613363565b6001600160a01b03161480610d415750610d41816109ad613363565b610d5d5760405162461bcd60e51b8152600401610b13906154bd565b610d678383613367565b505050565b60026009541415610d8f5760405162461bcd60e51b8152600401610b1390615d41565b60026009558033610d9f826118d0565b6001600160a01b031614610dc55760405162461bcd60e51b8152600401610b13906155a8565b600060158381548110610de857634e487b7160e01b600052603260045260246000fd5b6000918252602082206002600c9092020190810180549290559150610e0c846133d5565b6000336001600160a01b031682604051610e2590614e00565b60006040518083038185875af1925050503d8060008114610e62576040519150601f19603f3d011682016040523d82523d6000602084013e610e67565b606091505b5050905080610e7557600080fd5b50506001600955505050565b601154600090610e9390600190615e78565b905090565b600a546001600160a01b031681565b60076020526000908152604090205460ff1681565b60155490565b610eca613363565b6001600160a01b0316610edb611f67565b6001600160a01b031614610f015760405162461bcd60e51b8152600401610b13906157e1565b6001600160a01b038116610f1457600080fd5b600880546001600160a01b0319166001600160a01b0392909216919091179055565b610f47610f41613363565b8261346a565b610f635760405162461bcd60e51b8152600401610b1390615b29565b610d678383836134ef565b600e5481565b610f7c613363565b6001600160a01b0316610f8d611f67565b6001600160a01b031614610fb35760405162461bcd60e51b8152600401610b13906157e1565b612710610fc08284615e2d565b1115610fcb57600080fd5b600c91909155600d55565b610fde613363565b6001600160a01b0316610fef611f67565b6001600160a01b0316146110155760405162461bcd60e51b8152600401610b13906157e1565b600f54811161102357600080fd5b600f55565b8133611033826118d0565b6001600160a01b0316146110595760405162461bcd60e51b8152600401610b13906155a8565b600a5460405163c19a4ef560e01b81526000916001600160a01b03169063c19a4ef59061108a908690600401615dab565b60206040518083038186803b1580156110a257600080fd5b505afa1580156110b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110da9190614a46565b6000858152601760205260409020909150600982600981111561110d57634e487b7160e01b600052602160045260246000fd5b1461112a5760405162461bcd60e51b8152600401610b139061591c565b6000611136828661360a565b9050806111555760405162461bcd60e51b8152600401610b139061570b565b60408051600180825281830190925260009160208083019080368337019050509050858160008151811061119957634e487b7160e01b600052603260045260246000fd5b6020908102919091010152600a5460405163bf0d3f7560e01b81526001600160a01b039091169063bf0d3f75906111d69033908590600401614e86565b600060405180830381600087803b1580156111f057600080fd5b505af1158015611204573d6000803e3d6000fd5b50506040518892508991507fccf19ad398faa1e99163ffe5bcc2e588dba13c8c500d65c61260f52dbc4dbdec90600090a350505050505050565b610d678383836040518060200160405280600081525061289f565b6008546001600160a01b031681565b8133611273826118d0565b6001600160a01b0316146112995760405162461bcd60e51b8152600401610b13906155a8565b601583815481106112ba57634e487b7160e01b600052603260045260246000fd5b90600052602060002090600c0201600201548210156112eb5760405162461bcd60e51b8152600401610b1390615779565b600083815260126020526040908190208390555183907fbbfc0cdc6e5f417a8ed325a749156d2b5656913de94bcc8e46cf968d79fbd4aa9061132e908590615dab565b60405180910390a2505050565b3360009081526007602052604090205460ff1661136a5760405162461bcd60e51b8152600401610b1390615953565b60006015838154811061138d57634e487b7160e01b600052603260045260246000fd5b90600052602060002090600c0201905060008282600101546113af9190615e2d565b9050600083116113be57600080fd5b600f548111156113e05760405162461bcd60e51b8152600401610b139061565a565b808260010181905550837ff8ce76aded20692895cb3987a0f52c19c8ee8c8c9a234f6aec9f9d48d31ba8b4828560405161141b929190614e03565b60405180910390a250505050565b611431613363565b6001600160a01b0316611442611f67565b6001600160a01b0316146114685760405162461bcd60e51b8152600401610b13906157e1565b6001600160a01b03811661147b57600080fd5b600a80546001600160a01b0319166001600160a01b0392909216919091179055565b81336114a8826118d0565b6001600160a01b0316146114ce5760405162461bcd60e51b8152600401610b13906155a8565b6114da83836001613616565b600a5460405163b112673360e01b81526001600160a01b039091169063b11267339061150c9033908690600401614e86565b600060405180830381600087803b15801561152657600080fd5b505af115801561153a573d6000803e3d6000fd5b50505050827fab405b1cd965024eb3b0d30a7d59cf2f5242cb2d5aefb32eeff6c33f1d52c07f8360405161132e9190614ec3565b611576613363565b6001600160a01b0316611587611f67565b6001600160a01b0316146115ad5760405162461bcd60e51b8152600401610b13906157e1565b80516115c0906010906020840190614740565b5050565b6060600080600060606115d56147c4565b6000601588815481106115f857634e487b7160e01b600052603260045260246000fd5b90600052602060002090600c02016040518061018001604052908160008201805461162290615ebb565b80601f016020809104026020016040519081016040528092919081815260200182805461164e90615ebb565b801561169b5780601f106116705761010080835404028352916020019161169b565b820191906000526020600020905b81548152906001019060200180831161167e57829003601f168201915b50505050508152602001600182015481526020016002820154815260200160038201548152602001600482015481526020016005820154815260200160068201548152602001600782015481526020016008820154815260200160098201548152602001600a8201548152602001600b8201548152505090506000611731601760008b8152602001908152602001600020613c98565b90506000816001600160401b0381111561175b57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611784578160200160208202803683370190505b50905060005b828110156117e75760008b81526017602052604090206117aa9082613ca3565b8282815181106117ca57634e487b7160e01b600052603260045260246000fd5b6020908102919091010152806117df81615ef6565b91505061178a565b50826000015198508260200151975082604001519650601660008b815260200190815260200160002054955080945060405180610120016040528084606001518152602001846080015181526020018460a0015181526020018460c0015181526020018460e001518152602001846101000151815260200184610120015181526020018461014001518152602001846101600151815250935050505091939550919395565b611894613363565b6001600160a01b03166118a5611f67565b6001600160a01b0316146118cb5760405162461bcd60e51b8152600401610b13906157e1565b600e55565b6000818152600260205260408120546001600160a01b031680610a525760405162461bcd60e51b8152600401610b139061555f565b600c5481565b805160208183018101805160148252928201919093012091525460ff1681565b8133611936826118d0565b6001600160a01b03161461195c5760405162461bcd60e51b8152600401610b13906155a8565b600b546040516331a9108f60e11b815233916001600160a01b031690636352211e9061198c908690600401615dab565b60206040518083038186803b1580156119a457600080fd5b505afa1580156119b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119dc919061488a565b6001600160a01b031614611a025760405162461bcd60e51b8152600401610b1390615d78565b60008381526016602052604090819020839055600b549051633e72286560e21b81526001600160a01b039091169063f9c8a19490611a44908590600401615dab565b600060405180830381600087803b158015611a5e57600080fd5b505af1158015611a72573d6000803e3d6000fd5b50506040518492508591507f5f0a58d6dd6d5ca80551306b121d87f079ae2ae169233c018d4a34b22e0be7e090600090a3505050565b60006001600160a01b038216611ad05760405162461bcd60e51b8152600401610b1390615515565b506001600160a01b031660009081526003602052604090205490565b611af4613363565b6001600160a01b0316611b05611f67565b6001600160a01b031614611b2b5760405162461bcd60e51b8152600401610b13906157e1565b6006546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600680546001600160a01b0319169055565b600060118381548110611b9857634e487b7160e01b600052603260045260246000fd5b90600052602060002090600702019050600061271082600301546103e8611bbf9190615e59565b611bc99190615e45565b9050600083118015611bdc575060328311155b611bf85760405162461bcd60e51b8152600401610b1390614fdb565b8160040154421015611c1c5760405162461bcd60e51b8152600401610b139061510e565b8160020154838360010154611c319190615e2d565b1115611c4f5760405162461bcd60e51b8152600401610b1390615691565b828260030154611c5f9190615e59565b3414611c7d5760405162461bcd60e51b8152600401610b1390615bb1565b60005b83811015611cb2576000611c9383613caf565b9050611c9f3382613e25565b5080611caa81615ef6565b915050611c80565b5082826001016000828254611cc79190615e2d565b9091555060009050611cd7611f67565b6001600160a01b0316611cea8584615e59565b611cf49034615e78565b604051611d0090614e00565b60006040518083038185875af1925050503d8060008114611d3d576040519150601f19603f3d011682016040523d82523d6000602084013e611d42565b606091505b5050905080611d5057600080fd5b8254158015611d745750826002015483600101541480611d74575082600501544210155b15611d8357611d838584613e3f565b5050505050565b8033611d95826118d0565b6001600160a01b031614611dbb5760405162461bcd60e51b8152600401610b13906155a8565b60008281526016602052604090205480611de75760405162461bcd60e51b8152600401610b1390615491565b60008381526016602052604080822091909155600b549051631730b48b60e21b81526001600160a01b0390911690635cc2d22c90611e29908490600401615dab565b600060405180830381600087803b158015611e4357600080fd5b505af1158015611e57573d6000803e3d6000fd5b50506040518392508591507f9f2ad2e9c967359fde12a00ff405c52926c27b89d77724cc56e6fa3915475b1590600090a3505050565b60118181548110611e9d57600080fd5b9060005260206000209060070201600091509050806000015490806001015490806002015490806003015490806004015490806005015490806006018054611ee490615ebb565b80601f0160208091040260200160405190810160405280929190818152602001828054611f1090615ebb565b8015611f5d5780601f10611f3257610100808354040283529160200191611f5d565b820191906000526020600020905b815481529060010190602001808311611f4057829003601f168201915b5050505050905087565b6006546001600160a01b031690565b606060018054610a6990615ebb565b8033611f90826118d0565b6001600160a01b031614611fb65760405162461bcd60e51b8152600401610b13906155a8565b600082815260126020526040902054611fe15760405162461bcd60e51b8152600401610b13906150de565b6000828152601260205260408082208290555183917fb8374e4567c34cb2d58f7ac4847c3877016109e6d2c890d6a35f08e746125ed191a25050565b612025613363565b6001600160a01b0316612036611f67565b6001600160a01b03161461205c5760405162461bcd60e51b8152600401610b13906157e1565b6001600160a01b03166000908152600760205260409020805460ff19166001179055565b600b546001600160a01b031681565b600260095414156120b25760405162461bcd60e51b8152600401610b1390615d41565b60026009556000828152601360209081526040808320338085529252822054909181841090816120eb576120e68386615e78565b6120ee565b60005b90506120f9866118d0565b6001600160a01b0316846001600160a01b0316141561212a5760405162461bcd60e51b8152600401610b1390615c56565b8285141561214a5760405162461bcd60e51b8152600401610b1390615434565b8034146121695760405162461bcd60e51b8152600401610b1390615a86565b60008681526013602090815260408083206001600160a01b03881684529091529020859055811561220e5760006121a08685615e78565b90506000856001600160a01b0316826040516121bb90614e00565b60006040518083038185875af1925050503d80600081146121f8576040519150601f19603f3d011682016040523d82523d6000602084013e6121fd565b606091505b505090508061220b57600080fd5b50505b857f6213c17a7c670bb7d839f96fa965d96e3217369d9c641d085e5c14140691b8858587604051610cbf929190614eaa565b612248613363565b6001600160a01b0316826001600160a01b031614156122795760405162461bcd60e51b8152600401610b13906152a9565b8060056000612286613363565b6001600160a01b03908116825260208083019390935260409182016000908120918716808252919093529120805460ff1916921515929092179091556122ca613363565b6001600160a01b03167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31836040516123029190614ed6565b60405180910390a35050565b600d5481565b61231c613363565b6001600160a01b031661232d611f67565b6001600160a01b0316146123535760405162461bcd60e51b8152600401610b13906157e1565b6001600160a01b03811661236657600080fd5b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b612390613363565b6001600160a01b03166123a1611f67565b6001600160a01b0316146123c75760405162461bcd60e51b8152600401610b13906157e1565b6001600160a01b03166000908152600760205260409020805460ff19169055565b60006015828154811061240b57634e487b7160e01b600052603260045260246000fd5b90600052602060002090600c02019050600034826002015461242d9190615e2d565b90506000341161244f5760405162461bcd60e51b8152600401610b1390615d0e565b68056bc75e2d631000008111156124785760405162461bcd60e51b8152600401610b139061522e565b600e546008546040516370a0823160e01b81526001600160a01b03909116906370a08231906124ab903390600401614e11565b60206040518083038186803b1580156124c357600080fd5b505afa1580156124d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124fb9190614aaf565b10156125195760405162461bcd60e51b8152600401610b13906152dc565b600282018190556125433361252c611f67565b600e546008546001600160a01b0316929190613ed3565b827f086277eb5274417916ccef96cc09aa48d5982bd87d0d03370427f211e934f59082600e5460405161132e929190614e03565b8133612582826118d0565b6001600160a01b0316146125a85760405162461bcd60e51b8152600401610b13906155a8565b600e546125b3611f67565b6008546040516370a0823160e01b815283916001600160a01b0316906370a08231906125e3903390600401614e11565b60206040518083038186803b1580156125fb57600080fd5b505afa15801561260f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126339190614aaf565b10156126515760405162461bcd60e51b8152600401610b13906153eb565b61265a84613f2b565b6126765760405162461bcd60e51b8152600401610b1390614fa9565b6014846040516126869190614d1a565b9081526040519081900360200190205460ff16156126b65760405162461bcd60e51b8152600401610b1390615816565b6000601586815481106126d957634e487b7160e01b600052603260045260246000fd5b90600052602060002090600c0201905060008160000180546126fa90615ebb565b905011156127385760006014826000016040516127179190614d65565b908152604051908190036020019020805491151560ff199092169190911790555b845161274a9082906020880190614740565b50600160148660405161275d9190614d1a565b908152604051908190036020018120805492151560ff199093169290921790915586907f8edfa912e70e283a8ef6d6f52cd1faef9690ff989eff2f11a134e8478ba7b28b906127ad908890614ee1565b60405180910390a250600854611d83906001600160a01b0316338385613ed3565b81336127d9826118d0565b6001600160a01b0316146127ff5760405162461bcd60e51b8152600401610b13906155a8565b61280b83836000613616565b600a5460405163bf0d3f7560e01b81526001600160a01b039091169063bf0d3f759061283d9033908690600401614e86565b600060405180830381600087803b15801561285757600080fd5b505af115801561286b573d6000803e3d6000fd5b50505050827f486feabfbbba4afb4ada394c6deea2ebc86e03923978134dd47ad92b8cff26ef8360405161132e9190614ec3565b6128b06128aa613363565b8361346a565b6128cc5760405162461bcd60e51b8152600401610b1390615b29565b6128d884848484614178565b50505050565b60126020526000908152604090205481565b601360209081526000928352604080842090915290825290205481565b60606129188261316d565b6129345760405162461bcd60e51b8152600401610b13906158cd565b600061293e6141ab565b9050600081511161295e5760405180602001604052806000815250612989565b80612968846141ba565b604051602001612979929190614d36565b6040516020818303038152906040525b9392505050565b600f5481565b600260095414156129b95760405162461bcd60e51b8152600401610b1390615d41565b6002600955600081815260126020526040812054906129d7836118d0565b905033826129f75760405162461bcd60e51b8152600401610b13906157b0565b823414612a165760405162461bcd60e51b8152600401610b1390615bb1565b816001600160a01b0316816001600160a01b03161415612a485760405162461bcd60e51b8152600401610b13906155df565b612a548482848661318a565b837f8e5b24f8b069110da0f44ac86e8883213e03a2290268235615824c0e86280d47828486604051612a8893929190614e25565b60405180910390a2505060016009555050565b3360009081526007602052604090205460ff16612aca5760405162461bcd60e51b8152600401610b1390615953565b612710811115612ad957600080fd5b600060158481548110612afc57634e487b7160e01b600052603260045260246000fd5b90600052602060002090600c02019050600060158481548110612b2f57634e487b7160e01b600052603260045260246000fd5b90600052602060002090600c0201905060008160020154836002015411612b5a578260020154612b60565b81600201545b90506000612710612b718684615e59565b612b7b9190615e45565b905080846002016000828254612b919190615e2d565b9250508190555080836002016000828254612bac9190615e78565b9250508190555085877f613d6c2f0dea7098f87432d2f00bb35f24b7a243406cab36dd4056777a9e5aa983604051612be49190615dab565b60405180910390a350505050505050565b612bfd613363565b6001600160a01b0316612c0e611f67565b6001600160a01b031614612c345760405162461bcd60e51b8152600401610b13906157e1565b6000612c3e610e81565b9050600060118281548110612c6357634e487b7160e01b600052603260045260246000fd5b90600052602060002090600702016040518060e0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815260200160058201548152602001600682018054612cc890615ebb565b80601f0160208091040260200160405190810160405280929190818152602001828054612cf490615ebb565b8015612d415780601f10612d1657610100808354040283529160200191612d41565b820191906000526020600020905b815481529060010190602001808311612d2457829003601f168201915b50505050508152505090508060400151816020015114612d6057600080fd5b6040805160e081018252600080825260208083018281529383018b8152606084018b8152608085018b815260a086018b815260c087018b8152601180546001810182559752875160079097027f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c68810197885598517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c698a015593517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6a89015591517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6b880155517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6c870155517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6d86015551805193949293612ec6937f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6e01929190910190614740565b5050507ff5177867b3cf937deaac25da8e7733f654828440429b272c4171f20e50129bf7826001612ef79190615e2d565b604051612f049190615dab565b60405180910390a150505050505050565b6001600160a01b0380831660009081526005602090815260408083209385168352929052205460ff165b92915050565b60026009541415612f685760405162461bcd60e51b8152600401610b1390615d41565b600260095560008181526013602090815260408083203380855292529091205480612fa55760405162461bcd60e51b8152600401610b1390615cd7565b60008381526013602090815260408083206001600160a01b0386168085529252808320839055518390612fd790614e00565b60006040518083038185875af1925050503d8060008114613014576040519150601f19603f3d011682016040523d82523d6000602084013e613019565b606091505b505090508061302757600080fd5b837f352824f537d55388283e894a5f9948bc36fa9d487c0271a4c1108c7d32da7f0484604051612a889190614e11565b61305f613363565b6001600160a01b0316613070611f67565b6001600160a01b0316146130965760405162461bcd60e51b8152600401610b13906157e1565b6001600160a01b0381166130bc5760405162461bcd60e51b8152600401610b1390615143565b6006546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600680546001600160a01b0319166001600160a01b0392909216919091179055565b60006015828154811061313b57634e487b7160e01b600052603260045260246000fd5b90600052602060002090600c0201600101549050919050565b6001600160e01b031981166301ffc9a760e01b14919050565b6000908152600260205260409020546001600160a01b0316151590565b6000601585815481106131ad57634e487b7160e01b600052603260045260246000fd5b90600052602060002090600c020190506000612710600c54846131d09190615e59565b6131da9190615e45565b90506000612710600d54856131ef9190615e59565b6131f99190615e45565b9050600082846002015461320d9190615e2d565b6000898152601260205260408120819055600286018290559091506001600160a01b03871661323c8486615e2d565b6132469088615e78565b60405161325290614e00565b60006040518083038185875af1925050503d806000811461328f576040519150601f19603f3d011682016040523d82523d6000602084013e613294565b606091505b50509050806132a257600080fd5b60006132ac611f67565b6001600160a01b0316846040516132c290614e00565b60006040518083038185875af1925050503d80600081146132ff576040519150601f19603f3d011682016040523d82523d6000602084013e613304565b606091505b505090508061331257600080fd5b61331d888a8c6134ef565b897f086277eb5274417916ccef96cc09aa48d5982bd87d0d03370427f211e934f590848760405161334f929190614e03565b60405180910390a250505050505050505050565b3390565b600081815260046020526040902080546001600160a01b0319166001600160a01b038416908117909155819061339c826118d0565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60006133e0826118d0565b90506133ee81600084610d67565b6133f9600083613367565b6001600160a01b0381166000908152600360205260408120805460019290613422908490615e78565b909155505060008281526002602052604080822080546001600160a01b0319169055518391906001600160a01b03841690600080516020615fa4833981519152908390a45050565b60006134758261316d565b6134915760405162461bcd60e51b8152600401610b1390615368565b600061349c836118d0565b9050806001600160a01b0316846001600160a01b031614806134d75750836001600160a01b03166134cc84610aec565b6001600160a01b0316145b806134e757506134e78185612f15565b949350505050565b826001600160a01b0316613502826118d0565b6001600160a01b0316146135285760405162461bcd60e51b8152600401610b1390615884565b6001600160a01b03821661354e5760405162461bcd60e51b8152600401610b1390615265565b613559838383610d67565b613564600082613367565b6001600160a01b038316600090815260036020526040812080546001929061358d908490615e78565b90915550506001600160a01b03821660009081526003602052604081208054600192906135bb908490615e2d565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b038681169182179092559151849391871691600080516020615fa483398151915291a4505050565b600061298983836142d4565b600083815260126020526040902054156136425760405162461bcd60e51b8152600401610b13906159c1565b60008251116136635760405162461bcd60e51b8152600401610b1390615464565b60006015848154811061368657634e487b7160e01b600052603260045260246000fd5b600091825260208083206040805160098082526101408201909252600c9490940290910194509082016101208036833701905050905060005b8451811015613c905760008582815181106136ea57634e487b7160e01b600052603260045260246000fd5b602002602001015190506000856137015781613704565b60005b600a5460405163c19a4ef560e01b81529192506000916001600160a01b039091169063c19a4ef59061373a908690600401615dab565b60206040518083038186803b15801561375257600080fd5b505afa158015613766573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061378a9190614a46565b9050826137a95760405162461bcd60e51b8152600401610b139061584d565b60098160098111156137cb57634e487b7160e01b600052602160045260246000fd5b14156137e95760405162461bcd60e51b8152600401610b1390615012565b8481600981111561380a57634e487b7160e01b600052602160045260246000fd5b8151811061382857634e487b7160e01b600052603260045260246000fd5b60200260200101511561384d5760405162461bcd60e51b8152600401610b13906151f7565b600081600981111561386f57634e487b7160e01b600052602160045260246000fd5b14156138e957866138855760038601541561388d565b828660030154145b6138a95760405162461bcd60e51b8152600401610b1390615be8565b6003860182905560018560005b815181106138d457634e487b7160e01b600052603260045260246000fd5b91151560209283029190910190910152613c7a565b600181600981111561390b57634e487b7160e01b600052602160045260246000fd5b1415613955578661392157600486015415613929565b828660040154145b6139455760405162461bcd60e51b8152600401610b1390615af2565b60048601829055600185816138b6565b600281600981111561397757634e487b7160e01b600052602160045260246000fd5b14156139c2578661398d57600586015415613995565b828660050154145b6139b15760405162461bcd60e51b8152600401610b139061598a565b6005860182905560018560026138b6565b60038160098111156139e457634e487b7160e01b600052602160045260246000fd5b1415613a2f57866139fa57600686015415613a02565b828660060154145b613a1e5760405162461bcd60e51b8152600401610b1390615055565b6006860182905560018560036138b6565b6004816009811115613a5157634e487b7160e01b600052602160045260246000fd5b1415613a9c5786613a6757600786015415613a6f565b828660070154145b613a8b5760405162461bcd60e51b8152600401610b13906153b4565b6007860182905560018560046138b6565b6005816009811115613abe57634e487b7160e01b600052602160045260246000fd5b1415613b095786613ad457600886015415613adc565b828660080154145b613af85760405162461bcd60e51b8152600401610b1390615c1f565b6008860182905560018560056138b6565b6006816009811115613b2b57634e487b7160e01b600052602160045260246000fd5b1415613b765786613b4157600986015415613b49565b828660090154145b613b655760405162461bcd60e51b8152600401610b1390615742565b6009860182905560018560066138b6565b6007816009811115613b9857634e487b7160e01b600052602160045260246000fd5b1415613be35786613bae57600a86015415613bb6565b8286600a0154145b613bd25760405162461bcd60e51b8152600401610b1390615abb565b600a860182905560018560076138b6565b6008816009811115613c0557634e487b7160e01b600052602160045260246000fd5b1415613c7a5786613c1b57600b86015415613c23565b8286600b0154145b613c3f5760405162461bcd60e51b8152600401610b1390615189565b600b8601829055600185600881518110613c6957634e487b7160e01b600052603260045260246000fd5b911515602092830291909101909101525b5050508080613c8890615ef6565b9150506136bf565b505050505050565b6000610a528261431e565b60006129898383614322565b604080516101a08101825260006101808201818152825260016020808401829052938301859052606083018290526080830182905260a0830182905260c0830182905260e0830182905261010083018290526101208301829052610140830182905261016083018290526015805491820181558252825180519294600c9092027f55f448fdea98c4d29eb340757ef0a66cd03dbb9538908a6a81d96026b71ec4750192613d5f9284920190614740565b506020820151816001015560408201518160020155606082015181600301556080820151816004015560a0820151816005015560c0820151816006015560e082015181600701556101008201518160080155610120820151816009015561014082015181600a015561016082015181600b015550506001601580549050613de69190615e78565b9050807f0206a5f891c1e0173fe67376aa91f7cb1396d1304ce0c96e5c9d8e7baac7d7fb83604051613e189190615dab565b60405180910390a2919050565b6115c082826040518060200160405280600081525061437b565b600081600201544442604051602001613e59929190614e03565b6040516020818303038152906040528051906020012060001c613e7c9190615f11565b905080613e9157613e8e816001615e2d565b90505b8082556040517f2cef2ac652db7d723fb9cffa5df9729234275ec9377763568b8337912851d9f790613ec69085908490614e03565b60405180910390a1505050565b6128d8846323b872dd60e01b858585604051602401613ef493929190614e25565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526143ae565b600080829050600181511015613f45576000915050610a55565b601481511115613f59576000915050610a55565b80600081518110613f7a57634e487b7160e01b600052603260045260246000fd5b6020910101516001600160f81b031916600160fd1b1415613f9f576000915050610a55565b8060018251613fae9190615e78565b81518110613fcc57634e487b7160e01b600052603260045260246000fd5b6020910101516001600160f81b031916600160fd1b1415613ff1576000915050610a55565b60008160008151811061401457634e487b7160e01b600052603260045260246000fd5b01602001516001600160f81b031916905060005b825181101561416d57600083828151811061405357634e487b7160e01b600052603260045260246000fd5b01602001516001600160f81b0319169050600160fd1b811480156140845750600160fd1b6001600160f81b03198416145b15614096576000945050505050610a55565b600360fc1b6001600160f81b03198216108015906140c25750603960f81b6001600160f81b0319821611155b1580156140f85750604160f81b6001600160f81b03198216108015906140f65750602d60f91b6001600160f81b0319821611155b155b801561412d5750606160f81b6001600160f81b031982161080159061412b5750603d60f91b6001600160f81b0319821611155b155b80156141475750600160fd1b6001600160f81b0319821614155b15614159576000945050505050610a55565b91508061416581615ef6565b915050614028565b506001949350505050565b6141838484846134ef565b61418f8484848461443d565b6128d85760405162461bcd60e51b8152600401610b139061508c565b606060108054610a6990615ebb565b6060816141df57506040805180820190915260018152600360fc1b6020820152610a55565b8160005b811561420957806141f381615ef6565b91506142029050600a83615e45565b91506141e3565b6000816001600160401b0381111561423157634e487b7160e01b600052604160045260246000fd5b6040519080825280601f01601f19166020018201604052801561425b576020820181803683370190505b5090505b84156134e757614270600183615e78565b915061427d600a86615f11565b614288906030615e2d565b60f81b8183815181106142ab57634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a9053506142cd600a86615e45565b945061425f565b60006142e0838361454d565b61431657508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155612f3f565b506000612f3f565b5490565b815460009082106143455760405162461bcd60e51b8152600401610b1390614f67565b82600001828154811061436857634e487b7160e01b600052603260045260246000fd5b9060005260206000200154905092915050565b6143858383614565565b614392600084848461443d565b610d675760405162461bcd60e51b8152600401610b139061508c565b6000614403826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166146329092919063ffffffff16565b805190915015610d67578080602001905181019061442191906149f2565b610d675760405162461bcd60e51b8152600401610b1390615c8d565b6000614451846001600160a01b0316614641565b1561416d57836001600160a01b031663150b7a0261446d613363565b8786866040518563ffffffff1660e01b815260040161448f9493929190614e49565b602060405180830381600087803b1580156144a957600080fd5b505af19250505080156144d9575060408051601f3d908101601f191682019092526144d691810190614a2a565b60015b614533573d808015614507576040519150601f19603f3d011682016040523d82523d6000602084013e61450c565b606091505b50805161452b5760405162461bcd60e51b8152600401610b139061508c565b805181602001fd5b6001600160e01b031916630a85bd0160e11b1490506134e7565b60009081526001919091016020526040902054151590565b6001600160a01b03821661458b5760405162461bcd60e51b8152600401610b1390615625565b6145948161316d565b156145b15760405162461bcd60e51b8152600401610b13906151c0565b6145bd60008383610d67565b6001600160a01b03821660009081526003602052604081208054600192906145e6908490615e2d565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b0386169081179091559051839290600080516020615fa4833981519152908290a45050565b60606134e78484600085614647565b3b151590565b6060824710156146695760405162461bcd60e51b8152600401610b1390615322565b61467285614641565b61468e5760405162461bcd60e51b8152600401610b1390615b7a565b600080866001600160a01b031685876040516146aa9190614d1a565b60006040518083038185875af1925050503d80600081146146e7576040519150601f19603f3d011682016040523d82523d6000602084013e6146ec565b606091505b50915091506146fc828286614707565b979650505050505050565b60608315614716575081612989565b8251156147265782518084602001fd5b8160405162461bcd60e51b8152600401610b139190614ee1565b82805461474c90615ebb565b90600052602060002090601f01602090048101928261476e57600085556147b4565b82601f1061478757805160ff19168380011785556147b4565b828001600101855582156147b4579182015b828111156147b4578251825591602001919060010190614799565b506147c09291506147e3565b5090565b6040518061012001604052806009906020820280368337509192915050565b5b808211156147c057600081556001016147e4565b60006001600160401b0383111561481157614811615f51565b614824601f8401601f1916602001615df8565b905082815283838301111561483857600080fd5b828260208301376000602084830101529392505050565b600082601f83011261485f578081fd5b612989838335602085016147f8565b60006020828403121561487f578081fd5b813561298981615f67565b60006020828403121561489b578081fd5b815161298981615f67565b600080604083850312156148b8578081fd5b82356148c381615f67565b915060208301356148d381615f67565b809150509250929050565b6000806000606084860312156148f2578081fd5b83356148fd81615f67565b9250602084013561490d81615f67565b929592945050506040919091013590565b60008060008060808587031215614933578081fd5b843561493e81615f67565b9350602085013561494e81615f67565b92506040850135915060608501356001600160401b0381111561496f578182fd5b8501601f8101871361497f578182fd5b61498e878235602084016147f8565b91505092959194509250565b600080604083850312156149ac578182fd5b82356149b781615f67565b915060208301356148d381615f7f565b600080604083850312156149d9578182fd5b82356149e481615f67565b946020939093013593505050565b600060208284031215614a03578081fd5b815161298981615f7f565b600060208284031215614a1f578081fd5b813561298981615f8d565b600060208284031215614a3b578081fd5b815161298981615f8d565b600060208284031215614a57578081fd5b8151600a8110612989578182fd5b600060208284031215614a76578081fd5b81356001600160401b03811115614a8b578182fd5b6134e78482850161484f565b600060208284031215614aa8578081fd5b5035919050565b600060208284031215614ac0578081fd5b5051919050565b60008060408385031215614ad9578182fd5b8235915060208301356148d381615f67565b600080600060608486031215614aff578081fd5b83359250602084013561490d81615f67565b60008060408385031215614b23578182fd5b823591506020808401356001600160401b0380821115614b41578384fd5b818601915086601f830112614b54578384fd5b813581811115614b6657614b66615f51565b8381029150614b76848301615df8565b8181528481019084860184860187018b1015614b90578788fd5b8795505b83861015614bb2578035835260019590950194918601918601614b94565b508096505050505050509250929050565b60008060408385031215614bd5578182fd5b8235915060208301356001600160401b03811115614bf1578182fd5b614bfd8582860161484f565b9150509250929050565b60008060408385031215614c19578182fd5b50508035926020909101359150565b600080600060608486031215614c3c578081fd5b505081359360208301359350604090920135919050565b600080600080600060a08688031215614c6a578283fd5b8535945060208601359350604086013592506060860135915060808601356001600160401b03811115614c9b578182fd5b614ca78882890161484f565b9150509295509295909350565b6000815180845260208085019450808401835b83811015614ce357815187529582019590820190600101614cc7565b509495945050505050565b60008151808452614d06816020860160208601615e8f565b601f01601f19169290920160200192915050565b60008251614d2c818460208701615e8f565b9190910192915050565b60008351614d48818460208801615e8f565b835190830190614d5c818360208801615e8f565b01949350505050565b8154600090819060028104600180831680614d8157607f831692505b6020808410821415614da157634e487b7160e01b87526022600452602487fd5b818015614db55760018114614dc657614df2565b60ff19861689528489019650614df2565b614dcf8a615e21565b885b86811015614dea5781548b820152908501908301614dd1565b505084890196505b509498975050505050505050565b90565b918252602082015260400190565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090614e7c90830184614cee565b9695505050505050565b6001600160a01b03831681526040602082018190526000906134e790830184614cb4565b6001600160a01b03929092168252602082015260400190565b6000602082526129896020830184614cb4565b901515815260200190565b6000602082526129896020830184614cee565b60006101c0808352614f088184018a614cee565b9050602088818501528760408501528660608501528382036080850152614f2f8287614cb4565b925060a0840191508460005b6009811015614f5857815184529282019290820190600101614f3b565b50505050979650505050505050565b60208082526022908201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604082015261647360f01b606082015260800190565b6020808252601890820152774d6f6f6e4b6e696768743a20696e76616c6964206e616d6560401b604082015260600190565b6020808252601f908201527f4d6f6f6e4b6e696768743a20616d6f756e74206f7574206f662072616e676500604082015260600190565b60208082526023908201527f4d6f6f6e4b6e696768743a2063616e6e6f7420657175697020736b696c6c20626040820152626f6f6b60e81b606082015260800190565b6020808252601a908201527f4d6f6f6e4b6e69676874203a20696e76616c69642061726d6f72000000000000604082015260600190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b602080825260169082015275135bdbdb92db9a59da1d0e881b9bdd081b1a5cdd195960521b604082015260600190565b6020808252818101527f4d6f6f6e4b6e696768743a2053616c6520686173206e6f742073746172746564604082015260600190565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201526564647265737360d01b606082015260800190565b6020808252601a908201527f4d6f6f6e4b6e69676874203a20696e76616c69642074726f6f70000000000000604082015260600190565b6020808252601c908201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604082015260600190565b6020808252601e908201527f4d6f6f6e4b6e696768743a206475706c6963617465206974656d547970650000604082015260600190565b6020808252601b908201527f4d6f6f6e4b6e696768743a2063616e6e6f7420616464206d6f72650000000000604082015260600190565b60208082526024908201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646040820152637265737360e01b606082015260800190565b60208082526019908201527822a9219b99189d1030b8383937bb32903a379031b0b63632b960391b604082015260600190565b60208082526026908201527f4d6f6f6e4b6e696768743a20696e73756666696369656e7420746f6b656e2062604082015265616c616e636560d01b606082015260800190565b60208082526026908201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6040820152651c8818d85b1b60d21b606082015260800190565b6020808252602c908201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860408201526b34b9ba32b73a103a37b5b2b760a11b606082015260800190565b6020808252601d908201527f4d6f6f6e4b6e69676874203a20696e76616c696420666f6f7477656172000000604082015260600190565b60208082526029908201527f4163636570746564546f6b656e3a20696e73756666696369656e7420746f6b656040820152686e2062616c616e636560b81b606082015260800190565b60208082526016908201527526b7b7b725b734b3b43a1d1039b0b6b29037b33332b960511b604082015260600190565b6020808252601390820152724d6f6f6e4b6e696768743a206e6f206974656d60681b604082015260600190565b602080825260129082015271135bdbdb92db9a59da1d0e881b9bc81c195d60721b604082015260600190565b60208082526038908201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f776040820152771b995c881b9bdc88185c1c1c9bdd995908199bdc88185b1b60421b606082015260800190565b6020808252602a908201527f4552433732313a2062616c616e636520717565727920666f7220746865207a65604082015269726f206164647265737360b01b606082015260800190565b60208082526029908201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460408201526832b73a103a37b5b2b760b91b606082015260800190565b6020808252601c908201527f4d6f6f6e4b6e696768743a206e6f74206b6e69676874206f776e657200000000604082015260600190565b60208082526026908201527f4d6f6f6e4b6e696768743a2063616e6e6f742062757920796f7572206f776e2060408201526512db9a59da1d60d21b606082015260800190565b6020808252818101527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604082015260600190565b6020808252601d908201527f4d6f6f6e4b6e696768743a206d6178206c6576656c2072656163686564000000604082015260600190565b602080825260149082015273135bdbdb92db9a59da1d0e881cdbdb19081bdd5d60621b604082015260600190565b6020808252602c908201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860408201526b34b9ba32b73a103a37b5b2b760a11b606082015260800190565b6020808252601b908201527f4d6f6f6e4b6e696768743a20616c7265616479206c6561726e65640000000000604082015260600190565b6020808252601b908201527f4d6f6f6e4b6e69676874203a20696e76616c696420676c6f7665730000000000604082015260600190565b6020808252601d908201527f4d6f6f6e4b6e696768743a20756e64657220666c6f6f72207072696365000000604082015260600190565b6020808252601790820152764d6f6f6e4b6e696768743a206e6f74206f6e2073616c6560481b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601f908201527f4d6f6f6e4b6e696768743a206e616d6520616c72656164792065786973747300604082015260600190565b6020808252601a908201527f4d6f6f6e4b6e696768743a20696e76616c6964206974656d4964000000000000604082015260600190565b60208082526029908201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960408201526839903737ba1037bbb760b91b606082015260800190565b6020808252602f908201527f4552433732314d657461646174613a2055524920717565727920666f72206e6f60408201526e3732bc34b9ba32b73a103a37b5b2b760891b606082015260800190565b6020808252601e908201527f4d6f6f6e4b6e696768743a20696e76616c696420736b696c6c20626f6f6b0000604082015260600190565b6020808252601d908201527f5065726d697373696f6e47726f75703a206e6f74206f70657261746f72000000604082015260600190565b6020808252601d908201527f4d6f6f6e4b6e69676874203a20696e76616c6964206865616467656172000000604082015260600190565b6020808252602d908201527f4d6f6f6e4b6e696768743a2063616e6e6f74206368616e6765206974656d732060408201526c7768696c65206f6e2073616c6560981b606082015260800190565b60208082526021908201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656040820152603960f91b606082015260800190565b6020808252601f908201527f4d6f6f6e4b6e696768743a206c657373207468616e206d696e20707269636500604082015260600190565b6020808252818101527f4d6f6f6e4b6e696768743a2073656e742076616c756520696e636f7272656374604082015260600190565b6020808252601a908201527f4d6f6f6e4b6e69676874203a20696e76616c6964206d6f756e74000000000000604082015260600190565b6020808252601e908201527f4d6f6f6e4b6e69676874203a20696e76616c696420737562576561706f6e0000604082015260600190565b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252601b908201527f4d6f6f6e4b6e696768743a20696e636f72726563742076616c75650000000000604082015260600190565b6020808252601f908201527f4d6f6f6e4b6e69676874203a20696e76616c6964206d61696e576561706f6e00604082015260600190565b6020808252601a908201527f4d6f6f6e4b6e69676874203a20696e76616c69642070616e7473000000000000604082015260600190565b6020808252601e908201527f4d6f6f6e4b6e696768743a206f776e65722063616e6e6f74206f666665720000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b6020808252601a908201527f4d6f6f6e4b6e696768743a206e6f206f6666657220666f756e64000000000000604082015260600190565b602080825260199082015278135bdbdb92db9a59da1d0e881b9bc81d985b1d59481cd95b9d603a1b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526019908201527826b7b7b725b734b3b43a1d103737ba103832ba1037bbb732b960391b604082015260600190565b90815260200190565b60008882528760208301528660408301528560608301528460808301528360a083015260e060c0830152615deb60e0830184614cee565b9998505050505050505050565b6040518181016001600160401b0381118282101715615e1957615e19615f51565b604052919050565b60009081526020902090565b60008219821115615e4057615e40615f25565b500190565b600082615e5457615e54615f3b565b500490565b6000816000190483118215151615615e7357615e73615f25565b500290565b600082821015615e8a57615e8a615f25565b500390565b60005b83811015615eaa578181015183820152602001615e92565b838111156128d85750506000910152565b600281046001821680615ecf57607f821691505b60208210811415615ef057634e487b7160e01b600052602260045260246000fd5b50919050565b6000600019821415615f0a57615f0a615f25565b5060010190565b600082615f2057615f20615f3b565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114615f7c57600080fd5b50565b8015158114615f7c57600080fd5b6001600160e01b031981168114615f7c57600080fdfeddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122053def132e367e2b07dc19109a5ff1ce50b655f8014ee05d8c3411f223dc9bca264736f6c63430008000033000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014ec6ee23dd1589ea147deb6c41d5ae3d654489300000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000060b7a5240000000000000000000000000000000000000000000000000000000060b7a524000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading