ETH Price: $3,484.25 (-0.20%)

Token

Brawler Bearz (BB)
 

Overview

Max Total Supply

4,169 BB

Holders

1,219

Market

Volume (24H)

0.8116 ETH

Min Price (24H)

$36.93 @ 0.010600 ETH

Max Price (24H)

$114.98 @ 0.033000 ETH

Other Info

Balance
33 BB
0xbf0f10b3fefbfbb8f74387879c8812763444a5d2
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
BrawlerBearz

Compiler Version
v0.8.9+commit.e5eed63a

Optimization Enabled:
Yes with 550 runs

Other Settings:
default evmVersion
File 1 of 35 : BrawlerBearz.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {LockRegistry} from "./abstract/LockRegistry.sol";
import {IBrawlerBearz} from "./interfaces/IBrawlerBearz.sol";
import {IBrawlerBearzFaction} from "./interfaces/IBrawlerBearzFaction.sol";
import {IBrawlerBearzRenderer} from "./interfaces/IBrawlerBearzRenderer.sol";
import {IBrawlerBearzDynamicItems} from "./interfaces/IBrawlerBearzDynamicItems.sol";
import {ERC721Psi, ERC721PsiRandomSeedReveal, ERC721PsiRandomSeedRevealBurnable} from "./ERC721PsiRandomSeedRevealBurnable.sol";

/*******************************************************************************
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|(@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|,|@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&&@@@@@@@@@@@|,*|&@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%,**%@@@@@@@@%|******%&@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&##*****|||**,(%%%%%**|%@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@***,#%%%%**#&@@@@@#**,|@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@*,(@@@@@@@@@@**,(&@@@@#**%@@@@@@||(%@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@%|,****&@((@&***&@@@@@@%||||||||#%&@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@&%#*****||||||**#%&@%%||||||||#@&%#(@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@&**,(&@@@@@%|||||*##&&&&##|||||(%@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@**,%@@@@@@@(|*|#%@@@@@@@@#||#%%@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@#||||#@@@@||*|%@@@@@@@@&|||%%&@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@#,,,,,,*|**||%|||||||###&@@@@@@@#|||#%@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@&#||*|||||%%%@%%%#|||%@@@@@@@@&(|(%&@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@&&%%(||||@@@@@@&|||||(%&((||(#%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@%%(||||||||||#%#(|||||%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@&%#######%%@@**||(#%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%##%%&@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
********************************************************************************/

/**************************************************
 * @title BrawlerBearz
 * @author @ScottMitchell18
 **************************************************/

contract BrawlerBearz is
    IBrawlerBearz,
    ERC721PsiRandomSeedRevealBurnable,
    LockRegistry,
    ReentrancyGuard,
    AccessControl
{
    address public constant DEAD_ADDRESS =
        0x000000000000000000000000000000000000dEaD;

    // Roles
    bytes32 constant XP_MUTATOR_ROLE = keccak256("XP_MUTATOR_ROLE");
    bytes32 constant OWNER_ROLE = keccak256("OWNER_ROLE");

    // Equip types
    bytes32 constant HEAD_ITEM_TYPE = keccak256(abi.encodePacked("HEAD"));
    bytes32 constant WEAPON_ITEM_TYPE = keccak256(abi.encodePacked("WEAPON"));
    bytes32 constant BACKGROUND_ITEM_TYPE =
        keccak256(abi.encodePacked("BACKGROUND"));
    bytes32 constant ARMOR_ITEM_TYPE = keccak256(abi.encodePacked("ARMOR"));
    bytes32 constant FACE_ARMOR_ITEM_TYPE =
        keccak256(abi.encodePacked("FACE_ARMOR"));
    bytes32 constant EYEWEAR_ITEM_TYPE = keccak256(abi.encodePacked("EYEWEAR"));
    bytes32 constant MISC_ITEM_TYPE = keccak256(abi.encodePacked("MISC"));

    /// @notice bytes32 of Chainlink keyhash
    bytes32 public immutable keyHash;

    /// @notice value of Chainlink subscription id
    uint64 public immutable subscriptionId;

    /// @notice 4% of total minted
    uint256 public teamMintAmount = 128;

    /// @notice address of treasury (e.g, gnosis safe)
    address public treasury =
        payable(0x39bfA2b4319581bc885A2d4b9F0C90C2e1c24B87);

    /*
     * @notice Whitelist Live ~ September 16th, 2022, 10AM EST
     * @dev timestamp for whitelist
     */
    uint256 public whitelistLiveAt = 1663336800;

    /*
     * @notice Public / Free Claim Live ~ September 16th, 2022, 5PM EST
     * @dev timestamp for public and free claim
     */
    uint256 public liveAt = 1663362000;

    /// @notice amount of the total supply of the collection (n - 1)
    uint256 public maxSupply = 3335; // Excludes 2666 access passes

    /// @notice price in ether
    uint256 public price = 0.045 ether;

    /// @notice amount of transactions allowed per wallet (n - 1)
    uint256 public maxPerWallet = 3;

    /// @notice boolean for if the shop drop is enabled
    bool private isShopDropEnabled = true;

    /// @notice boolean for if its revealed
    bool public isRevealed = false;

    /// @notice bytes32 hash of the merkle root
    bytes32 public merkleRoot;

    /// @notice map from token id to custom metadata
    mapping(uint256 => CustomMetadata) internal metadata;

    // @dev An address mapping for max mint per wallet
    mapping(address => uint256) public addressToMinted;

    /// @notice Vendor contract
    IBrawlerBearzDynamicItems public vendorContract;

    /// @notice Access pass contract
    IERC721 public accessPassContract;

    /// @notice The rendering library contract
    IBrawlerBearzRenderer public renderer;

    /// @notice Faction contract
    IBrawlerBearzFaction public factionContract;

    // ========================================
    // Modifiers
    // ========================================

    modifier isTokenOwner(uint256 tokenId) {
        if (ownerOf(tokenId) != _msgSender()) {
            revert InvalidOwner();
        }
        _;
    }

    modifier isItemTokenOwner(uint256 itemTokenId) {
        if (vendorContract.balanceOf(_msgSender(), itemTokenId) == 0) {
            revert InvalidOwner();
        }
        _;
    }

    modifier isItemValidType(uint256 itemTokenId, string memory validTypeOf) {
        if (
            keccak256(abi.encodePacked(validTypeOf)) !=
            keccak256(abi.encodePacked(vendorContract.getItemType(itemTokenId)))
        ) {
            revert InvalidItemType();
        }
        _;
    }

    modifier isItemXPMet(uint256 itemTokenId, uint256 tokenId) {
        if (metadata[tokenId].xp < vendorContract.getItemXPReq(itemTokenId)) {
            revert ItemRequiresMoreXP();
        }
        _;
    }

    // " and \ are not valid
    modifier isValidString(string calldata value) {
        bytes memory str = bytes(value);
        for (uint256 i; i < str.length; i++) {
            bytes1 char = str[i];
            if ((char == 0x22) || (char == 0x5c)) revert InvalidString();
        }
        _;
    }

    constructor(
        address _vrfV2Coordinator,
        bytes32 keyHash_,
        uint64 subscriptionId_,
        address _accessPassContract,
        address _factionContract,
        address _renderingContract,
        address _vendorContract
    )
        ERC721Psi("Brawler Bearz", "BB")
        ERC721PsiRandomSeedReveal(_vrfV2Coordinator, 400000, 3)
    {
        // Chainlink VRF initialization
        keyHash = keyHash_;
        subscriptionId = subscriptionId_;
        // Setup access control
        _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
        _setupRole(OWNER_ROLE, _msgSender());
        // NFT integration contracts
        accessPassContract = IERC721(_accessPassContract);
        factionContract = IBrawlerBearzFaction(_factionContract);
        // On-chain metadata rendering contract
        renderer = IBrawlerBearzRenderer(_renderingContract);
        // Shop integration contract
        vendorContract = IBrawlerBearzDynamicItems(_vendorContract);
        // Placeholder mint for collection protection
        _safeMint(_msgSender(), 1, "");
    }

    // ========================================
    // Dynamic metadata
    // ========================================

    /**
     * @notice Sets the name of a particular token id
     * @dev only token owner call this function
     * @param tokenId The token id
     * @param name The name to set
     */
    function setName(uint256 tokenId, string calldata name)
        public
        override
        isTokenOwner(tokenId)
        isValidString(name)
    {
        bytes memory n = bytes(name);
        if (n.length > 25) revert InvalidLength();
        if (keccak256(n) == keccak256(bytes(metadata[tokenId].name)))
            revert InvalidValue();
        metadata[tokenId].name = name;
        emit NameChanged(tokenId, name);
    }

    /**
     * @notice Sets the lore/backstory of a particular token id
     * @dev only token owner call this function
     * @param tokenId The token id
     * @param lore The name to set
     */
    function setLore(uint256 tokenId, string calldata lore)
        public
        override
        isTokenOwner(tokenId)
        isValidString(lore)
    {
        bytes memory n = bytes(lore);
        if (keccak256(n) == keccak256(bytes(metadata[tokenId].lore)))
            revert InvalidValue();
        metadata[tokenId].lore = lore;
        emit LoreChanged(tokenId, lore);
    }

    /**
     * @notice Sets the equipped items of a particular token id and item type
     * @dev only token owner call this function
     * @param tokenId The token id of the bear
     * @param typeOf The type of item to equip
     * @param itemTokenId The token id of the item
     */
    function equip(
        uint256 tokenId,
        string calldata typeOf,
        uint256 itemTokenId
    )
        public
        override
        isTokenOwner(tokenId)
        isItemTokenOwner(itemTokenId)
        isItemValidType(itemTokenId, typeOf)
        isItemXPMet(itemTokenId, tokenId)
        nonReentrant
    {
        bytes32 itemType = keccak256(abi.encodePacked(typeOf));
        CustomMetadata storage instance = metadata[tokenId];

        if (WEAPON_ITEM_TYPE == itemType) {
            require(instance.weapon == 0, "96");
            instance.weapon = itemTokenId;
        } else if (HEAD_ITEM_TYPE == itemType) {
            require(instance.head == 0, "96");
            instance.head = itemTokenId;
        } else if (ARMOR_ITEM_TYPE == itemType) {
            require(instance.armor == 0, "96");
            instance.armor = itemTokenId;
        } else if (BACKGROUND_ITEM_TYPE == itemType) {
            require(instance.background == 0, "96");
            instance.background = itemTokenId;
        } else if (FACE_ARMOR_ITEM_TYPE == itemType) {
            require(instance.faceArmor == 0, "96");
            instance.faceArmor = itemTokenId;
        } else if (EYEWEAR_ITEM_TYPE == itemType) {
            require(instance.eyewear == 0, "96");
            instance.eyewear = itemTokenId;
        } else if (MISC_ITEM_TYPE == itemType) {
            require(instance.misc == 0, "96");
            instance.misc = itemTokenId;
        } else {
            revert InvalidItemType();
        }
        // Burn item
        vendorContract.burnItemForOwnerAddress(itemTokenId, 1, _msgSender());
        emit Equipped(tokenId, typeOf, itemTokenId);
    }

    /**
     * @notice Unsets the equipped items of a particular token id
     * @dev only token owner call this function
     * @param typeOf The type of item to equip
     * @param tokenId The token id
     */
    function unequip(uint256 tokenId, string calldata typeOf)
        public
        override
        isTokenOwner(tokenId)
        nonReentrant
    {
        uint256 itemTokenId;
        bytes32 itemType = keccak256(abi.encodePacked(typeOf));
        CustomMetadata storage instance = metadata[tokenId];

        if (WEAPON_ITEM_TYPE == itemType) {
            itemTokenId = instance.weapon;
            instance.weapon = 0;
        } else if (HEAD_ITEM_TYPE == itemType) {
            itemTokenId = instance.head;
            instance.head = 0;
        } else if (ARMOR_ITEM_TYPE == itemType) {
            itemTokenId = instance.armor;
            instance.armor = 0;
        } else if (BACKGROUND_ITEM_TYPE == itemType) {
            itemTokenId = instance.background;
            instance.background = 0;
        } else if (FACE_ARMOR_ITEM_TYPE == itemType) {
            itemTokenId = instance.faceArmor;
            instance.faceArmor = 0;
        } else if (EYEWEAR_ITEM_TYPE == itemType) {
            itemTokenId = instance.eyewear;
            instance.eyewear = 0;
        } else if (MISC_ITEM_TYPE == itemType) {
            itemTokenId = instance.misc;
            instance.misc = 0;
        } else {
            revert InvalidItemType();
        }

        require(itemTokenId > 0, "6969");
        // Mint item
        vendorContract.mintItemToAddress(itemTokenId, 1, _msgSender());
        emit Unequipped(tokenId, typeOf, itemTokenId);
    }

    // ========================================
    // NFT display helpers
    // ========================================

    /// @notice Reveal called by the governance to reveal the seed of the NFT
    function reveal() external onlyRole(OWNER_ROLE) {
        _reveal();
        emit Revealed(totalSupply());
    }

    /// @notice The custom metadata associated to a given tokenId
    function getMetadata(uint256 tokenId)
        external
        view
        override
        returns (CustomMetadata memory)
    {
        require(_exists(tokenId), "0");
        return metadata[tokenId];
    }

    /// @notice The token uri for a given tokenId
    function tokenURI(uint256 tokenId)
        public
        view
        override
        returns (string memory)
    {
        if (isRevealed == false) {
            return renderer.hiddenURI(tokenId);
        }
        require(_exists(tokenId), "0");
        CustomMetadata memory md = metadata[tokenId];
        md.isUnlocked = isUnlocked(tokenId);
        md.faction = factionContract.getFaction(ownerOf(tokenId));
        return renderer.tokenURI(tokenId, seed(tokenId), md);
    }

    // ========================================
    // Mint Helpers
    // ========================================

    /**
     * @notice Free claim mint, requires access pass ownership
     * @param _tokenIds of the access pass
     */
    function claim(uint256[] calldata _tokenIds) external nonReentrant {
        require(isPublicLive(), "0");
        for (uint256 i = 0; i < _tokenIds.length; i++) {
            accessPassContract.transferFrom(
                _msgSender(),
                DEAD_ADDRESS,
                _tokenIds[i]
            );
        }
        _safeMint(_msgSender(), _tokenIds.length, "");
    }

    /**
     * @notice Whitelisted mint, requires a merkle proof
     * @param _amount of mints
     * @param _proof hashed array proof
     */
    function whitelistMint(uint256 _amount, bytes32[] calldata _proof)
        external
        payable
        nonReentrant
    {
        require(isWhitelistLive(), "0");
        require(totalSupply() + _amount < maxSupply, "9");
        require(msg.value >= _amount * price, "1");
        require(addressToMinted[_msgSender()] + _amount < maxPerWallet, "2");
        bytes32 leaf = keccak256(abi.encodePacked(_msgSender()));
        require(MerkleProof.verify(_proof, merkleRoot, leaf), "4");
        addressToMinted[_msgSender()] += _amount;
        _safeMint(_msgSender(), _amount, "");
        // Shop drop chance game
        if (isShopDropEnabled) {
            vendorContract.shopDrop(_msgSender(), _amount);
        }
    }

    /**
     * @notice Public mint
     * @param _amount of mints
     */
    function mint(uint256 _amount) external payable {
        require(isPublicLive(), "0");
        require(totalSupply() + _amount < maxSupply, "9");
        require(msg.value >= _amount * price, "1");
        require(addressToMinted[_msgSender()] + _amount < maxPerWallet, "2");
        addressToMinted[_msgSender()] += _amount;
        _safeMint(_msgSender(), _amount, "");
    }

    /**
     * @notice Sets public price in wei
     * @dev only owner call this function
     * @param _price The new public price in wei
     */
    function setPrice(uint256 _price) public onlyRole(OWNER_ROLE) {
        price = _price;
    }

    /**
     * @notice Sets the treasury recipient
     * @dev only owner call this function
     * @param _treasury The new price in wei
     */
    function setTreasury(address _treasury) public onlyRole(OWNER_ROLE) {
        treasury = payable(_treasury);
    }

    /**
     * @notice Sets the reveal status of the metadata
     * @dev only owner call this function
     * @param _isRevealed The new boolean of the reveal
     */
    function setIsRevealed(bool _isRevealed) public onlyRole(OWNER_ROLE) {
        isRevealed = _isRevealed;
    }

    /**
     * @notice Sets max supply for the collection
     * @dev only owner call this function
     * @param _maxSupply The new max supply value
     */
    function setMaxSupply(uint256 _maxSupply) external onlyRole(OWNER_ROLE) {
        maxSupply = _maxSupply;
    }

    /**
     * @notice Sets the max mints per wallet
     * @param _maxPerWallet The max per wallet (Keep mind its +1 n)
     */
    function setMaxPerWallet(uint256 _maxPerWallet)
        external
        onlyRole(OWNER_ROLE)
    {
        maxPerWallet = _maxPerWallet;
    }

    /**
     * @notice Sets the go live timestamp for whitelist
     * @param _whitelistLiveAt A base uri
     */
    function setWhitelistLiveAt(uint256 _whitelistLiveAt)
        external
        onlyRole(OWNER_ROLE)
    {
        whitelistLiveAt = _whitelistLiveAt;
    }

    /**
     * @notice Sets the go live timestamp
     * @param _liveAt A base uri
     */
    function setLiveAt(uint256 _liveAt) external onlyRole(OWNER_ROLE) {
        liveAt = _liveAt;
    }

    /**
     * @notice Sets the merkle root for the mint
     * @param _merkleRoot The merkle root to set
     */
    function setMerkleRoot(bytes32 _merkleRoot) external onlyRole(OWNER_ROLE) {
        merkleRoot = _merkleRoot;
    }

    /// @notice Withdraw from contract
    function withdraw() public onlyRole(OWNER_ROLE) {
        (bool success, ) = treasury.call{value: address(this).balance}("");
        require(success, "999");
    }

    /// @notice Team mints ~4% of max supply - resets to 0 after team mint happens
    function teamMints(address _to) external onlyRole(OWNER_ROLE) {
        require(teamMintAmount > 0, "69");
        _safeMint(_to, teamMintAmount, "");
        teamMintAmount = 0;
    }

    /**
     * @notice Sets whether shop drop is enabled
     * @param _isShopDropEnabled the bool value
     */
    function setShopDropEnabled(bool _isShopDropEnabled)
        external
        onlyRole(OWNER_ROLE)
    {
        isShopDropEnabled = _isShopDropEnabled;
    }

    // ========================================
    // Lock registry
    // ========================================

    /**
     * @dev Overrides the normal `transferFrom` to include lock check
     * @param from address
     * @param to address
     * @param tokenId of asset
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public override {
        require(isUnlocked(tokenId), "1337");
        super.transferFrom(from, to, tokenId);
    }

    /**
     * @dev Overrides the normal `safeTransferFrom` to include lock check
     * @param from address
     * @param to address
     * @param tokenId of asset
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) public override {
        require(isUnlocked(tokenId), "1337");
        super.safeTransferFrom(from, to, tokenId, _data);
    }

    function lockId(uint256 tokenId) external onlyRole(XP_MUTATOR_ROLE) {
        require(_exists(tokenId), "0");
        _lockId(tokenId);
    }

    function unlockId(uint256 tokenId) external onlyRole(XP_MUTATOR_ROLE) {
        require(_exists(tokenId), "0");
        _unlockId(tokenId);
    }

    function freeId(uint256 tokenId, address contractAddress)
        external
        onlyRole(XP_MUTATOR_ROLE)
    {
        require(_exists(tokenId), "0");
        _freeId(tokenId, contractAddress);
    }

    // ========================================
    // External contract helpers
    // ========================================

    /**
     * @notice Adds XP to tokenId
     * @param tokenId the token
     * @param amount of xp to add
     */
    function addXP(uint256 tokenId, uint256 amount)
        external
        onlyRole(XP_MUTATOR_ROLE)
    {
        metadata[tokenId].xp += amount;
    }

    /**
     * @notice Subtracts XP from tokenId
     * @param tokenId the token
     * @param amount of xp to subtract
     */
    function subtractXP(uint256 tokenId, uint256 amount)
        external
        onlyRole(XP_MUTATOR_ROLE)
    {
        metadata[tokenId].xp -= amount;
    }

    /**
     * @notice Sets the bearz rendering library contract
     * @dev only owner call this function
     * @param _renderingContractAddress The new contract address
     */
    function setRenderingContractAddress(address _renderingContractAddress)
        external
        onlyRole(OWNER_ROLE)
    {
        renderer = IBrawlerBearzRenderer(_renderingContractAddress);
    }

    /**
     * @notice Sets the bearz vendor item contract
     * @dev only owner call this function
     * @param _vendorContractAddress The new contract address
     */
    function setVendorContractAddress(address _vendorContractAddress)
        external
        onlyRole(OWNER_ROLE)
    {
        vendorContract = IBrawlerBearzDynamicItems(_vendorContractAddress);
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        override(ERC721Psi, AccessControl)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }

    // ========================================
    // Read operations
    // ========================================

    // @dev Check if mint is public live
    function isWhitelistLive() public view returns (bool) {
        return block.timestamp > whitelistLiveAt;
    }

    // @dev Check if mint is public live
    function isPublicLive() public view returns (bool) {
        return block.timestamp > liveAt;
    }

    // @dev Check if mint is public live
    function getAddressMintsRemaining(address _address)
        public
        view
        returns (uint256)
    {
        return maxPerWallet - addressToMinted[_address] - 1;
    }

    /*
     * @notice Return token ids for a given address
     * @param _owner address
     */
    function walletOfOwner(address _owner)
        public
        view
        returns (uint256[] memory)
    {
        uint256 tokenCount = balanceOf(_owner);
        if (tokenCount == 0) return new uint256[](0);
        uint256[] memory tokensId = new uint256[](tokenCount);
        for (uint256 i; i < tokenCount; i++) {
            tokensId[i] = tokenOfOwnerByIndex(_owner, i);
        }
        return tokensId;
    }

    // ========================================
    // Chainlink integrations
    // ========================================

    function _keyHash() internal view override returns (bytes32) {
        return keyHash;
    }

    function _subscriptionId() internal view override returns (uint64) {
        return subscriptionId;
    }
}

File 2 of 35 : MerkleProof.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (utils/cryptography/MerkleProof.sol)

pragma solidity ^0.8.0;

/**
 * @dev These functions deal with verification of Merkle Trees proofs.
 *
 * The proofs can be generated using the JavaScript library
 * https://github.com/miguelmota/merkletreejs[merkletreejs].
 * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.
 *
 * See `test/utils/cryptography/MerkleProof.test.js` for some examples.
 *
 * WARNING: You should avoid using leaf values that are 64 bytes long prior to
 * hashing, or use a hash function other than keccak256 for hashing leaves.
 * This is because the concatenation of a sorted pair of internal nodes in
 * the merkle tree could be reinterpreted as a leaf value.
 */
library MerkleProof {
    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     */
    function verify(
        bytes32[] memory proof,
        bytes32 root,
        bytes32 leaf
    ) internal pure returns (bool) {
        return processProof(proof, leaf) == root;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. When processing the proof, the pairs
     * of leafs & pre-images are assumed to be sorted.
     *
     * _Available since v4.4._
     */
    function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            bytes32 proofElement = proof[i];
            if (computedHash <= proofElement) {
                // Hash(current computed hash + current element of the proof)
                computedHash = _efficientHash(computedHash, proofElement);
            } else {
                // Hash(current element of the proof + current computed hash)
                computedHash = _efficientHash(proofElement, computedHash);
            }
        }
        return computedHash;
    }

    function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
        assembly {
            mstore(0x00, a)
            mstore(0x20, b)
            value := keccak256(0x00, 0x40)
        }
    }
}

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

pragma solidity ^0.8.0;

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

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

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

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

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

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

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

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

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

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

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

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

        _revokeRole(role, account);
    }

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

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

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

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

File 4 of 35 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

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

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

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

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

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

        _;

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

File 5 of 35 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721.sol)

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`.
     *
     * 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;

    /**
     * @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 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 the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

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

File 6 of 35 : LockRegistry.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

/*
 * Origin author
 *     ,_,
 *    (',')
 *    {/"\}
 *    -"-"-
 * Utilized by @ScottMitchell18
 */

abstract contract LockRegistry is Ownable {
    mapping(address => bool) public approvedContract;
    mapping(uint256 => uint256) public lockCount;
    mapping(uint256 => mapping(uint256 => address)) public lockMap;
    mapping(uint256 => mapping(address => uint256)) public lockMapIndex;

    event TokenLocked(
        uint256 indexed tokenId,
        address indexed approvedContract
    );

    event TokenUnlocked(
        uint256 indexed tokenId,
        address indexed approvedContract
    );

    function isUnlocked(uint256 _id) public view returns (bool) {
        return lockCount[_id] == 0;
    }

    function updateApprovedContracts(
        address[] calldata _contracts,
        bool[] calldata _values
    ) external onlyOwner {
        require(_contracts.length == _values.length, "!length");
        for (uint256 i = 0; i < _contracts.length; i++)
            approvedContract[_contracts[i]] = _values[i];
    }

    function _lockId(uint256 _id) internal {
        require(approvedContract[msg.sender], "Cannot update map");
        require(
            lockMapIndex[_id][msg.sender] == 0,
            "ID already locked by caller"
        );

        uint256 count = lockCount[_id] + 1;
        lockMap[_id][count] = msg.sender;
        lockMapIndex[_id][msg.sender] = count;
        lockCount[_id]++;
        emit TokenLocked(_id, msg.sender);
    }

    function _unlockId(uint256 _id) internal {
        require(approvedContract[msg.sender], "Cannot update map");
        uint256 index = lockMapIndex[_id][msg.sender];
        require(index != 0, "ID not locked by caller");

        uint256 last = lockCount[_id];
        if (index != last) {
            address lastContract = lockMap[_id][last];
            lockMap[_id][index] = lastContract;
            lockMap[_id][last] = address(0);
            lockMapIndex[_id][lastContract] = index;
        } else lockMap[_id][index] = address(0);
        lockMapIndex[_id][msg.sender] = 0;
        lockCount[_id]--;
        emit TokenUnlocked(_id, msg.sender);
    }

    function _freeId(uint256 _id, address _contract) internal {
        require(!approvedContract[_contract], "Cannot update map");
        uint256 index = lockMapIndex[_id][_contract];
        require(index != 0, "ID not locked");

        uint256 last = lockCount[_id];
        if (index != last) {
            address lastContract = lockMap[_id][last];
            lockMap[_id][index] = lastContract;
            lockMap[_id][last] = address(0);
            lockMapIndex[_id][lastContract] = index;
        } else lockMap[_id][index] = address(0);
        lockMapIndex[_id][_contract] = 0;
        lockCount[_id]--;
        emit TokenUnlocked(_id, _contract);
    }
}

File 7 of 35 : IBrawlerBearz.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IBrawlerBearzCommon} from "./IBrawlerBearzCommon.sol";
import {IBrawlerBearzEvents} from "./IBrawlerBearzEvents.sol";
import {IBrawlerBearzErrors} from "./IBrawlerBearzErrors.sol";

interface IBrawlerBearz is
    IBrawlerBearzCommon,
    IBrawlerBearzEvents,
    IBrawlerBearzErrors
{
    function getMetadata(uint256 tokenId)
        external
        view
        returns (CustomMetadata memory);

    function setName(uint256 tokenId, string calldata newName) external;

    function setLore(uint256 tokenId, string calldata newLore) external;

    function equip(
        uint256 tokenId,
        string calldata typeOf,
        uint256 itemTokenId
    ) external;

    function unequip(uint256 tokenId, string calldata typeOf) external;

    function whitelistMint(uint256 amount, bytes32[] calldata proof)
        external
        payable;

    function mint(uint256 amount) external payable;

    function freeId(uint256 tokenId, address contractAddress) external;

    function lockId(uint256 tokenId) external;

    function unlockId(uint256 tokenId) external;

    function addXP(uint256 tokenId, uint256 amount) external;

    function subtractXP(uint256 tokenId, uint256 amount) external;
}

File 8 of 35 : IBrawlerBearzFaction.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";

interface IBrawlerBearzFaction is IERC1155 {
    function getFaction(address _address) external view returns (uint256);
}

File 9 of 35 : IBrawlerBearzRenderer.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IBrawlerBearzCommon} from "./IBrawlerBearzCommon.sol";

interface IBrawlerBearzRenderer is IBrawlerBearzCommon {
    function hiddenURI(uint256 _tokenId) external view returns (string memory);

    function tokenURI(
        uint256 _tokenId,
        uint256 _seed,
        CustomMetadata memory _md
    ) external view returns (string memory);

    function dna(
        uint256 _tokenId,
        uint256 _seed,
        CustomMetadata memory _md
    ) external view returns (string memory);
}

File 10 of 35 : IBrawlerBearzDynamicItems.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable.sol";

interface IBrawlerBearzDynamicItems is IERC1155Upgradeable {
    struct CustomMetadata {
        string typeOf;
        string name;
        uint256 xp; // Min XP required to equip
        string rarity; // LEGENDARY, SUPER_RARE, RARE, UNCOMMON, COMMON
        uint256 atk; // Correlated to Strength (5%-50%)
        uint256 def; // Correlated to Endurance (5%-30%), resistance to attack
        uint256 usageChance; // Correlated to Luck + Intelligence (20%-90%)
        string usageDuration; // PERSISTENT - equipable items, TEMPORARY - battles, ONE-TIME - buffs
        string description;
    }

    function getMetadata(uint256 tokenId)
        external
        view
        returns (CustomMetadata memory);

    function getMetadataBatch(uint256[] calldata tokenIds)
        external
        view
        returns (CustomMetadata[] memory);

    function getItemType(uint256 tokenId) external view returns (string memory);

    function getItemName(uint256 tokenId) external view returns (string memory);

    function getItemXPReq(uint256 tokenId) external view returns (uint256);

    function setItemMetadata(
        uint256 tokenId,
        string calldata typeOf,
        string calldata name,
        uint256 xp
    ) external;

    function setItemMetadataStruct(
        uint256 tokenId,
        CustomMetadata memory metadata
    ) external;

    function shopDrop(address _toAddress, uint256 _amount) external;

    function dropItems(address _toAddress, uint256[] calldata itemIds) external;

    function burnItemForOwnerAddress(
        uint256 _typeId,
        uint256 _quantity,
        address _materialOwnerAddress
    ) external;

    function mintItemToAddress(
        uint256 _typeId,
        uint256 _quantity,
        address _toAddress
    ) external;

    function mintBatchItemsToAddress(
        uint256[] memory _typeIds,
        uint256[] memory _quantities,
        address _toAddress
    ) external;

    function bulkSafeTransfer(
        uint256 _typeId,
        uint256 _quantityPerRecipient,
        address[] calldata recipients
    ) external;
}

File 11 of 35 : ERC721PsiRandomSeedRevealBurnable.sol
// SPDX-License-Identifier: MIT
/**
  ______ _____   _____ ______ ___  __ _  _  _ 
 |  ____|  __ \ / ____|____  |__ \/_ | || || |
 | |__  | |__) | |        / /   ) || | \| |/ |
 |  __| |  _  /| |       / /   / / | |\_   _/ 
 | |____| | \ \| |____  / /   / /_ | |  | |   
 |______|_|  \_\\_____|/_/   |____||_|  |_|   
                                              
                                            
 */
pragma solidity ^0.8.0;

import "./BitMaps.sol";
import "./ERC721PsiRandomSeedReveal.sol";

abstract contract ERC721PsiRandomSeedRevealBurnable is
    ERC721PsiRandomSeedReveal
{
    using BitMaps for BitMaps.BitMap;
    BitMaps.BitMap private _burnedToken;

    /**
     * @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 from = ownerOf(tokenId);
        _beforeTokenTransfers(from, address(0), tokenId, 1);
        _burnedToken.set(tokenId);
        emit Transfer(from, address(0), tokenId);
        _afterTokenTransfers(from, address(0), tokenId, 1);
    }

    /**
     * @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
        override
        returns (bool)
    {
        if (_burnedToken.get(tokenId)) {
            return false;
        }
        return super._exists(tokenId);
    }

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

    /**
     * @dev Returns number of token burned.
     */
    function _burned() internal view returns (uint256 burned) {
        uint256 totalBucket = (_minted >> 8) + 1;
        for (uint256 i = 0; i < totalBucket; i++) {
            uint256 bucket = _burnedToken.getBucket(i);
            burned += _popcount(bucket);
        }
    }

    /**
     * @dev Returns number of set bits.
     */
    function _popcount(uint256 x) private pure returns (uint256 count) {
        unchecked {
            for (count = 0; x != 0; count++) x &= x - 1;
        }
    }
}

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

File 13 of 35 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

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

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

File 14 of 35 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

pragma solidity ^0.8.0;

import "./IERC165.sol";

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

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

pragma solidity ^0.8.0;

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

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

pragma solidity ^0.8.0;

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

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

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

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

    /**
     * @dev 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 {
        _transferOwnership(address(0));
    }

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

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

File 18 of 35 : IBrawlerBearzCommon.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IBrawlerBearzCommon {
    struct CustomMetadata {
        string name;
        string lore;
        uint256 background;
        uint256 head;
        uint256 weapon;
        uint256 armor;
        uint256 faceArmor;
        uint256 eyewear;
        uint256 misc;
        uint256 xp;
        bool isUnlocked;
        uint256 faction;
    }

    struct Traits {
        uint256 strength;
        uint256 endurance;
        uint256 intelligence;
        uint256 luck;
        uint256 xp;
        uint256 level;
        string skin;
        string head;
        string eyes;
        string outfit;
        string mouth;
        string background;
        string weapon;
        string armor;
        string eyewear;
        string faceArmor;
        string misc;
        string locked;
        string faction;
    }

    struct Bear {
        string name;
        string description;
        string dna;
        Traits traits;
        CustomMetadata dynamic;
    }
}

File 19 of 35 : IBrawlerBearzEvents.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IBrawlerBearzEvents {
    event Revealed(uint256 currentTokenId);
    event NameChanged(uint256 indexed id, string name);
    event LoreChanged(uint256 indexed id, string lore);
    event Equipped(uint256 indexed id, string typeOf, uint256 itemTokenId);
    event Unequipped(uint256 indexed id, string typeOf, uint256 itemTokenId);
    event Staked(uint256 indexed id);
    event UnStaked(uint256 indexed id, uint256 amount);
    event ClaimedTokens(uint256 indexed id, uint256 amount);
}

File 20 of 35 : IBrawlerBearzErrors.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IBrawlerBearzErrors {
    error InvalidRecipient();
    error InvalidTokenIds();
    error InvalidOwner();
    error InvalidItemType();
    error InvalidString();
    error InvalidLength();
    error InvalidValue();
    error ItemRequiresMoreXP();
}

File 21 of 35 : IERC1155.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.0;

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

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the amount of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
        external
        view
        returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
}

File 22 of 35 : IERC1155Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.0;

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

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155Upgradeable is IERC165Upgradeable {
    /**
     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the amount of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
        external
        view
        returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
}

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

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165Upgradeable {
    /**
     * @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 24 of 35 : BitMaps.sol
// SPDX-License-Identifier: MIT
/**
  ______ _____   _____ ______ ___  __ _  _  _ 
 |  ____|  __ \ / ____|____  |__ \/_ | || || |
 | |__  | |__) | |        / /   ) || | \| |/ |
 |  __| |  _  /| |       / /   / / | |\_   _/ 
 | |____| | \ \| |____  / /   / /_ | |  | |   
 |______|_|  \_\\_____|/_/   |____||_|  |_|   
                                              
                                            
 */
pragma solidity ^0.8.0;

import "./BitScan.sol";

/**
 * @dev This Library is a modified version of Openzeppelin's BitMaps library.
 * Functions of finding the index of the closest set bit from a given index are added.
 * The indexing of each bucket is modifed to count from the MSB to the LSB instead of from the LSB to the MSB.
 * The modification of indexing makes finding the closest previous set bit more efficient in gas usage.
 */

/**
 * @dev Library for managing uint256 to bool mapping in a compact and efficient way, providing the keys are sequential.
 * Largelly inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor].
 */

library BitMaps {
    using BitScan for uint256;
    uint256 private constant MASK_INDEX_ZERO = (1 << 255);
    struct BitMap {
        mapping(uint256 => uint256) _data;
    }

    /**
     * @dev Returns whether the bit at `index` is set.
     */
    function get(BitMap storage bitmap, uint256 index)
        internal
        view
        returns (bool)
    {
        uint256 bucket = index >> 8;
        uint256 mask = MASK_INDEX_ZERO >> (index & 0xff);
        return bitmap._data[bucket] & mask != 0;
    }

    /**
     * @dev Sets the bit at `index` to the boolean `value`.
     */
    function setTo(
        BitMap storage bitmap,
        uint256 index,
        bool value
    ) internal {
        if (value) {
            set(bitmap, index);
        } else {
            unset(bitmap, index);
        }
    }

    /**
     * @dev Sets the bit at `index`.
     */
    function set(BitMap storage bitmap, uint256 index) internal {
        uint256 bucket = index >> 8;
        uint256 mask = MASK_INDEX_ZERO >> (index & 0xff);
        bitmap._data[bucket] |= mask;
    }

    /**
     * @dev Unsets the bit at `index`.
     */
    function unset(BitMap storage bitmap, uint256 index) internal {
        uint256 bucket = index >> 8;
        uint256 mask = MASK_INDEX_ZERO >> (index & 0xff);
        bitmap._data[bucket] &= ~mask;
    }

    /**
     * @dev Find the closest index of the set bit before `index`.
     */
    function scanForward(BitMap storage bitmap, uint256 index)
        internal
        view
        returns (uint256)
    {
        uint256 bucket = index >> 8;
        uint256 bucketIndex = (index & 0xff);
        uint256 offset = 0xff ^ bucketIndex;
        uint256 bb = bitmap._data[bucket];
        bb = bb >> offset;
        if (bb > 0) {
            unchecked {
                return (bucket << 8) | (bucketIndex - bb.bitScanForward256());
            }
        } else {
            require(bucket > 0, "!exists");
            unchecked {
                bucket--;
                bucketIndex = 255;
                offset = 0;
            }
            while (true) {
                bb = bitmap._data[bucket];
                if (bb > 0) {
                    unchecked {
                        return
                            (bucket << 8) |
                            (bucketIndex - bb.bitScanForward256());
                    }
                } else {
                    require(bucket > 0, "!existS");
                    unchecked {
                        bucket--;
                    }
                }
            }
        }
    }

    function getBucket(BitMap storage bitmap, uint256 bucket)
        internal
        view
        returns (uint256)
    {
        return bitmap._data[bucket];
    }
}

File 25 of 35 : ERC721PsiRandomSeedReveal.sol
// SPDX-License-Identifier: MIT
/**
  ______ _____   _____ ______ ___  __ _  _  _ 
 |  ____|  __ \ / ____|____  |__ \/_ | || || |
 | |__  | |__) | |        / /   ) || | \| |/ |
 |  __| |  _  /| |       / /   / / | |\_   _/ 
 | |____| | \ \| |____  / /   / /_ | |  | |   
 |______|_|  \_\\_____|/_/   |____||_|  |_|
 */
pragma solidity ^0.8.0;

import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
import "./interfaces/IERC721RandomSeed.sol";
import "./BitMaps.sol";
import "./ERC721PsiBatchMetaData.sol";

abstract contract ERC721PsiRandomSeedReveal is
    IERC721RandomSeed,
    ERC721PsiBatchMetaData,
    VRFConsumerBaseV2
{
    // Chainklink VRF V2
    VRFCoordinatorV2Interface immutable COORDINATOR;
    uint32 immutable callbackGasLimit;
    uint16 immutable requestConfirmations;
    uint16 constant numWords = 1;

    // requestId => genId
    mapping(uint256 => uint256) private requestIdToGenId;

    // genId => seed
    mapping(uint256 => uint256) private genSeed;

    // batchHeadTokenId => genId
    mapping(uint256 => uint256) private _batchHeadtokenGen;

    // current genId for minting
    uint256 private currentGen = 1;

    event RandomnessRequest(uint256 requestId);

    constructor(
        address coordinator,
        uint32 _callbackGasLimit,
        uint16 _requestConfirmations
    ) VRFConsumerBaseV2(coordinator) {
        COORDINATOR = VRFCoordinatorV2Interface(coordinator);
        callbackGasLimit = _callbackGasLimit;
        requestConfirmations = _requestConfirmations;
    }

    /**
     * Callback function used by VRF Coordinator
     */
    function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords)
        internal
        override
    {
        uint256 randomness = randomWords[0];
        uint256 genId = requestIdToGenId[requestId];
        delete requestIdToGenId[genId];
        genSeed[genId] = randomness;
        _processRandomnessFulfillment(requestId, genId, randomness);
    }

    function _safeMint(
        address to,
        uint256 quantity,
        bytes memory _data
    ) internal virtual override {
        uint256 tokenIdHead = _minted;
        _batchHeadtokenGen[tokenIdHead] = currentGen;
        super._safeMint(to, quantity, _data);
    }

    /**
        @dev Query the generation of `tokenId`.
     */
    function _tokenGen(uint256 tokenId) internal view returns (uint256) {
        require(_exists(tokenId), "!exists");
        return _batchHeadtokenGen[_getMetaDataBatchHead(tokenId)];
    }

    /**
        @dev Request the randomess for the tokens of the current generation.
     */
    function _reveal() internal virtual {
        uint256 requestId = COORDINATOR.requestRandomWords(
            _keyHash(),
            _subscriptionId(),
            requestConfirmations,
            callbackGasLimit,
            numWords
        );
        emit RandomnessRequest(requestId);
        requestIdToGenId[requestId] = currentGen;
        _processRandomnessRequest(requestId, currentGen);
        currentGen++;
    }

    /**
        @dev Return the random seed of `tokenId`.
        Revert when the randomness hasn't been fulfilled.
     */
    function seed(uint256 tokenId)
        public
        view
        virtual
        override
        returns (uint256)
    {
        require(_exists(tokenId), "!exists");

        unchecked {
            uint256 _genSeed = genSeed[_tokenGen(tokenId)];
            require(_genSeed != 0, "!fullfilled");
            return uint256(keccak256(abi.encode(_genSeed, tokenId)));
        }
    }

    /** 
        @dev Override the function to provide the corrosponding keyHash for the Chainlink VRF V2.

        see also: https://docs.chain.link/docs/vrf-contracts/
     */
    function _keyHash() internal virtual returns (bytes32);

    /** 
        @dev Override the function to provide the corrosponding subscription id for the Chainlink VRF V2.

        see also: https://docs.chain.link/docs/get-a-random-number/#create-and-fund-a-subscription
     */
    function _subscriptionId() internal virtual returns (uint64);

    function _processRandomnessRequest(uint256 requestId, uint256 genId)
        internal
    {}

    function _processRandomnessFulfillment(
        uint256 requestId,
        uint256 genId,
        uint256 randomness
    ) internal {}
}

File 26 of 35 : BitScan.sol
// SPDX-License-Identifier: MIT
/**
  ______ _____   _____ ______ ___  __ _  _  _ 
 |  ____|  __ \ / ____|____  |__ \/_ | || || |
 | |__  | |__) | |        / /   ) || | \| |/ |
 |  __| |  _  /| |       / /   / / | |\_   _/ 
 | |____| | \ \| |____  / /   / /_ | |  | |   
 |______|_|  \_\\_____|/_/   |____||_|  |_|   
                                              
                                            
 */

pragma solidity ^0.8.0;

library BitScan {
    uint256 private constant DEBRUIJN_256 =
        0x818283848586878898a8b8c8d8e8f929395969799a9b9d9e9faaeb6bedeeff;
    bytes private constant LOOKUP_TABLE_256 =
        hex"0001020903110a19042112290b311a3905412245134d2a550c5d32651b6d3a7506264262237d468514804e8d2b95569d0d495ea533a966b11c886eb93bc176c9071727374353637324837e9b47af86c7155181ad4fd18ed32c9096db57d59ee30e2e4a6a5f92a6be3498aae067ddb2eb1d5989b56fd7baf33ca0c2ee77e5caf7ff0810182028303840444c545c646c7425617c847f8c949c48a4a8b087b8c0c816365272829aaec650acd0d28fdad4e22d6991bd97dfdcea58b4d6f29fede4f6fe0f1f2f3f4b5b6b607b8b93a3a7b7bf357199c5abcfd9e168bcdee9b3f1ecf5fd1e3e5a7a8aa2b670c4ced8bbe8f0f4fc3d79a1c3cde7effb78cce6facbf9f8";

    function isolateLSB256(uint256 bb) internal pure returns (uint256) {
        require(bb > 0);
        unchecked {
            return bb & (0 - bb);
        }
    }

    function isolateMSB256(uint256 bb) internal pure returns (uint256) {
        require(bb > 0);
        unchecked {
            bb |= bb >> 256;
            bb |= bb >> 128;
            bb |= bb >> 64;
            bb |= bb >> 32;
            bb |= bb >> 16;
            bb |= bb >> 8;
            bb |= bb >> 4;
            bb |= bb >> 2;
            bb |= bb >> 1;

            return (bb >> 1) + 1;
        }
    }

    function bitScanForward256(uint256 bb) internal pure returns (uint8) {
        unchecked {
            return
                uint8(
                    LOOKUP_TABLE_256[(isolateLSB256(bb) * DEBRUIJN_256) >> 248]
                );
        }
    }

    function bitScanReverse256(uint256 bb) internal pure returns (uint8) {
        unchecked {
            return
                255 -
                uint8(
                    LOOKUP_TABLE_256[
                        ((isolateMSB256(bb) * DEBRUIJN_256) >> 248)
                    ]
                );
        }
    }
}

File 27 of 35 : VRFCoordinatorV2Interface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface VRFCoordinatorV2Interface {
  /**
   * @notice Get configuration relevant for making requests
   * @return minimumRequestConfirmations global min for request confirmations
   * @return maxGasLimit global max for request gas limit
   * @return s_provingKeyHashes list of registered key hashes
   */
  function getRequestConfig()
    external
    view
    returns (
      uint16,
      uint32,
      bytes32[] memory
    );

  /**
   * @notice Request a set of random words.
   * @param keyHash - Corresponds to a particular oracle job which uses
   * that key for generating the VRF proof. Different keyHash's have different gas price
   * ceilings, so you can select a specific one to bound your maximum per request cost.
   * @param subId  - The ID of the VRF subscription. Must be funded
   * with the minimum subscription balance required for the selected keyHash.
   * @param minimumRequestConfirmations - How many blocks you'd like the
   * oracle to wait before responding to the request. See SECURITY CONSIDERATIONS
   * for why you may want to request more. The acceptable range is
   * [minimumRequestBlockConfirmations, 200].
   * @param callbackGasLimit - How much gas you'd like to receive in your
   * fulfillRandomWords callback. Note that gasleft() inside fulfillRandomWords
   * may be slightly less than this amount because of gas used calling the function
   * (argument decoding etc.), so you may need to request slightly more than you expect
   * to have inside fulfillRandomWords. The acceptable range is
   * [0, maxGasLimit]
   * @param numWords - The number of uint256 random values you'd like to receive
   * in your fulfillRandomWords callback. Note these numbers are expanded in a
   * secure way by the VRFCoordinator from a single random value supplied by the oracle.
   * @return requestId - A unique identifier of the request. Can be used to match
   * a request to a response in fulfillRandomWords.
   */
  function requestRandomWords(
    bytes32 keyHash,
    uint64 subId,
    uint16 minimumRequestConfirmations,
    uint32 callbackGasLimit,
    uint32 numWords
  ) external returns (uint256 requestId);

  /**
   * @notice Create a VRF subscription.
   * @return subId - A unique subscription id.
   * @dev You can manage the consumer set dynamically with addConsumer/removeConsumer.
   * @dev Note to fund the subscription, use transferAndCall. For example
   * @dev  LINKTOKEN.transferAndCall(
   * @dev    address(COORDINATOR),
   * @dev    amount,
   * @dev    abi.encode(subId));
   */
  function createSubscription() external returns (uint64 subId);

  /**
   * @notice Get a VRF subscription.
   * @param subId - ID of the subscription
   * @return balance - LINK balance of the subscription in juels.
   * @return reqCount - number of requests for this subscription, determines fee tier.
   * @return owner - owner of the subscription.
   * @return consumers - list of consumer address which are able to use this subscription.
   */
  function getSubscription(uint64 subId)
    external
    view
    returns (
      uint96 balance,
      uint64 reqCount,
      address owner,
      address[] memory consumers
    );

  /**
   * @notice Request subscription owner transfer.
   * @param subId - ID of the subscription
   * @param newOwner - proposed new owner of the subscription
   */
  function requestSubscriptionOwnerTransfer(uint64 subId, address newOwner) external;

  /**
   * @notice Request subscription owner transfer.
   * @param subId - ID of the subscription
   * @dev will revert if original owner of subId has
   * not requested that msg.sender become the new owner.
   */
  function acceptSubscriptionOwnerTransfer(uint64 subId) external;

  /**
   * @notice Add a consumer to a VRF subscription.
   * @param subId - ID of the subscription
   * @param consumer - New consumer which can use the subscription
   */
  function addConsumer(uint64 subId, address consumer) external;

  /**
   * @notice Remove a consumer from a VRF subscription.
   * @param subId - ID of the subscription
   * @param consumer - Consumer to remove from the subscription
   */
  function removeConsumer(uint64 subId, address consumer) external;

  /**
   * @notice Cancel a subscription
   * @param subId - ID of the subscription
   * @param to - Where to send the remaining LINK to
   */
  function cancelSubscription(uint64 subId, address to) external;
}

File 28 of 35 : VRFConsumerBaseV2.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/** ****************************************************************************
 * @notice Interface for contracts using VRF randomness
 * *****************************************************************************
 * @dev PURPOSE
 *
 * @dev Reggie the Random Oracle (not his real job) wants to provide randomness
 * @dev to Vera the verifier in such a way that Vera can be sure he's not
 * @dev making his output up to suit himself. Reggie provides Vera a public key
 * @dev to which he knows the secret key. Each time Vera provides a seed to
 * @dev Reggie, he gives back a value which is computed completely
 * @dev deterministically from the seed and the secret key.
 *
 * @dev Reggie provides a proof by which Vera can verify that the output was
 * @dev correctly computed once Reggie tells it to her, but without that proof,
 * @dev the output is indistinguishable to her from a uniform random sample
 * @dev from the output space.
 *
 * @dev The purpose of this contract is to make it easy for unrelated contracts
 * @dev to talk to Vera the verifier about the work Reggie is doing, to provide
 * @dev simple access to a verifiable source of randomness. It ensures 2 things:
 * @dev 1. The fulfillment came from the VRFCoordinator
 * @dev 2. The consumer contract implements fulfillRandomWords.
 * *****************************************************************************
 * @dev USAGE
 *
 * @dev Calling contracts must inherit from VRFConsumerBase, and can
 * @dev initialize VRFConsumerBase's attributes in their constructor as
 * @dev shown:
 *
 * @dev   contract VRFConsumer {
 * @dev     constructor(<other arguments>, address _vrfCoordinator, address _link)
 * @dev       VRFConsumerBase(_vrfCoordinator) public {
 * @dev         <initialization with other arguments goes here>
 * @dev       }
 * @dev   }
 *
 * @dev The oracle will have given you an ID for the VRF keypair they have
 * @dev committed to (let's call it keyHash). Create subscription, fund it
 * @dev and your consumer contract as a consumer of it (see VRFCoordinatorInterface
 * @dev subscription management functions).
 * @dev Call requestRandomWords(keyHash, subId, minimumRequestConfirmations,
 * @dev callbackGasLimit, numWords),
 * @dev see (VRFCoordinatorInterface for a description of the arguments).
 *
 * @dev Once the VRFCoordinator has received and validated the oracle's response
 * @dev to your request, it will call your contract's fulfillRandomWords method.
 *
 * @dev The randomness argument to fulfillRandomWords is a set of random words
 * @dev generated from your requestId and the blockHash of the request.
 *
 * @dev If your contract could have concurrent requests open, you can use the
 * @dev requestId returned from requestRandomWords to track which response is associated
 * @dev with which randomness request.
 * @dev See "SECURITY CONSIDERATIONS" for principles to keep in mind,
 * @dev if your contract could have multiple requests in flight simultaneously.
 *
 * @dev Colliding `requestId`s are cryptographically impossible as long as seeds
 * @dev differ.
 *
 * *****************************************************************************
 * @dev SECURITY CONSIDERATIONS
 *
 * @dev A method with the ability to call your fulfillRandomness method directly
 * @dev could spoof a VRF response with any random value, so it's critical that
 * @dev it cannot be directly called by anything other than this base contract
 * @dev (specifically, by the VRFConsumerBase.rawFulfillRandomness method).
 *
 * @dev For your users to trust that your contract's random behavior is free
 * @dev from malicious interference, it's best if you can write it so that all
 * @dev behaviors implied by a VRF response are executed *during* your
 * @dev fulfillRandomness method. If your contract must store the response (or
 * @dev anything derived from it) and use it later, you must ensure that any
 * @dev user-significant behavior which depends on that stored value cannot be
 * @dev manipulated by a subsequent VRF request.
 *
 * @dev Similarly, both miners and the VRF oracle itself have some influence
 * @dev over the order in which VRF responses appear on the blockchain, so if
 * @dev your contract could have multiple VRF requests in flight simultaneously,
 * @dev you must ensure that the order in which the VRF responses arrive cannot
 * @dev be used to manipulate your contract's user-significant behavior.
 *
 * @dev Since the block hash of the block which contains the requestRandomness
 * @dev call is mixed into the input to the VRF *last*, a sufficiently powerful
 * @dev miner could, in principle, fork the blockchain to evict the block
 * @dev containing the request, forcing the request to be included in a
 * @dev different block with a different hash, and therefore a different input
 * @dev to the VRF. However, such an attack would incur a substantial economic
 * @dev cost. This cost scales with the number of blocks the VRF oracle waits
 * @dev until it calls responds to a request. It is for this reason that
 * @dev that you can signal to an oracle you'd like them to wait longer before
 * @dev responding to the request (however this is not enforced in the contract
 * @dev and so remains effective only in the case of unmodified oracle software).
 */
abstract contract VRFConsumerBaseV2 {
  error OnlyCoordinatorCanFulfill(address have, address want);
  address private immutable vrfCoordinator;

  /**
   * @param _vrfCoordinator address of VRFCoordinator contract
   */
  constructor(address _vrfCoordinator) {
    vrfCoordinator = _vrfCoordinator;
  }

  /**
   * @notice fulfillRandomness handles the VRF response. Your contract must
   * @notice implement it. See "SECURITY CONSIDERATIONS" above for important
   * @notice principles to keep in mind when implementing your fulfillRandomness
   * @notice method.
   *
   * @dev VRFConsumerBaseV2 expects its subcontracts to have a method with this
   * @dev signature, and will call it once it has verified the proof
   * @dev associated with the randomness. (It is triggered via a call to
   * @dev rawFulfillRandomness, below.)
   *
   * @param requestId The Id initially returned by requestRandomness
   * @param randomWords the VRF output expanded to the requested number of words
   */
  function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal virtual;

  // rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF
  // proof. rawFulfillRandomness then calls fulfillRandomness, after validating
  // the origin of the call
  function rawFulfillRandomWords(uint256 requestId, uint256[] memory randomWords) external {
    if (msg.sender != vrfCoordinator) {
      revert OnlyCoordinatorCanFulfill(msg.sender, vrfCoordinator);
    }
    fulfillRandomWords(requestId, randomWords);
  }
}

File 29 of 35 : IERC721RandomSeed.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IERC721RandomSeed {
    function seed(uint256 tokenId) external view returns (uint256);
}

File 30 of 35 : ERC721PsiBatchMetaData.sol
// SPDX-License-Identifier: MIT
/**
  ______ _____   _____ ______ ___  __ _  _  _ 
 |  ____|  __ \ / ____|____  |__ \/_ | || || |
 | |__  | |__) | |        / /   ) || | \| |/ |
 |  __| |  _  /| |       / /   / / | |\_   _/ 
 | |____| | \ \| |____  / /   / /_ | |  | |   
 |______|_|  \_\\_____|/_/   |____||_|  |_|   
                                              
                                            
 */

pragma solidity ^0.8.0;

import "./ERC721Psi.sol";
import "./BitMaps.sol";

abstract contract ERC721PsiBatchMetaData is ERC721Psi {
    using BitMaps for BitMaps.BitMap;
    BitMaps.BitMap private _metaDataBatchHead;

    function _safeMint(
        address to,
        uint256 quantity,
        bytes memory _data
    ) internal virtual override {
        uint256 tokenIdBatchHead = _minted;
        _metaDataBatchHead.set(tokenIdBatchHead);
        super._safeMint(to, quantity, _data);
    }

    /**
     *  @dev Return the batch head tokenId where the on-chain metadata is stored during minting.
     *
     *  The returned tokenId will remain the same after the token transfer.
     */
    function _getMetaDataBatchHead(uint256 tokenId)
        internal
        view
        returns (uint256 tokenIdMetaDataBatchHead)
    {
        tokenIdMetaDataBatchHead = _metaDataBatchHead.scanForward(tokenId);
    }
}

File 31 of 35 : ERC721Psi.sol
// SPDX-License-Identifier: MIT
/**
  ______ _____   _____ ______ ___  __ _  _  _
 |  ____|  __ \ / ____|____  |__ \/_ | || || |
 | |__  | |__) | |        / /   ) || | \| |/ |
 |  __| |  _  /| |       / /   / / | |\_   _/
 | |____| | \ \| |____  / /   / /_ | |  | |
 |______|_|  \_\\_____|/_/   |____||_|  |_|
 */

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "./BitMaps.sol";
import "./Address.sol";

contract ERC721Psi is
    Context,
    ERC165,
    IERC721,
    IERC721Metadata,
    IERC721Enumerable
{
    using Address for address;
    using Strings for uint256;
    using BitMaps for BitMaps.BitMap;

    BitMaps.BitMap private _batchHead;

    string private _name;
    string private _symbol;

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

    mapping(uint256 => address) private _tokenApprovals;
    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 ||
            interfaceId == type(IERC721Enumerable).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC721-balanceOf}.
     */
    function balanceOf(address owner)
        public
        view
        virtual
        override
        returns (uint256)
    {
        require(owner != address(0), "zero address");

        uint256 count;
        for (uint256 i; i < _minted; ++i) {
            if (_exists(i)) {
                if (owner == ownerOf(i)) {
                    ++count;
                }
            }
        }
        return count;
    }

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId)
        public
        view
        virtual
        override
        returns (address)
    {
        (address owner, uint256 tokenIdBatchHead) = _ownerAndBatchHeadOf(
            tokenId
        );
        return owner;
    }

    function _ownerAndBatchHeadOf(uint256 tokenId)
        internal
        view
        returns (address owner, uint256 tokenIdBatchHead)
    {
        require(_exists(tokenId), "!exists");
        tokenIdBatchHead = _getBatchHead(tokenId);
        owner = _owners[tokenIdBatchHead];
    }

    /**
     * @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), "!exists");

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

    /**
     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
     * token will be the concatenation of the `baseURI` and the `tokenId`. 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 = ownerOf(tokenId);
        require(to != owner, "!approval");

        require(
            _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
            "!approved"
        );

        _approve(to, tokenId);
    }

    /**
     * @dev See {IERC721-getApproved}.
     */
    function getApproved(uint256 tokenId)
        public
        view
        virtual
        override
        returns (address)
    {
        require(_exists(tokenId), "!exists");

        return _tokenApprovals[tokenId];
    }

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

        _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), "!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), "!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),
            "!ERC721Receiver"
        );
    }

    /**
     * @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`).
     */
    function _exists(uint256 tokenId) internal view virtual returns (bool) {
        return tokenId < _minted;
    }

    /**
     * @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), "!exist");
        address owner = ownerOf(tokenId);
        return (spender == owner ||
            getApproved(tokenId) == spender ||
            isApprovedForAll(owner, spender));
    }

    /**
     * @dev Safely mints `quantity` tokens and transfers them to `to`.
     *
     * Requirements:
     *
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
     * - `quantity` must be greater than 0.
     *
     * Emits a {Transfer} event.
     */
    function _safeMint(address to, uint256 quantity) internal virtual {
        _safeMint(to, quantity, "");
    }

    function _safeMint(
        address to,
        uint256 quantity,
        bytes memory _data
    ) internal virtual {
        uint256 tokenIdBatchHead = _minted;

        require(quantity > 0, "zero");
        require(to != address(0), "!zeroaddress");

        _beforeTokenTransfers(address(0), to, tokenIdBatchHead, quantity);
        for (uint256 i = 0; i < quantity; i++) {
            uint256 tokenId = tokenIdBatchHead + i;
            emit Transfer(address(0), to, tokenId);
            require(
                _checkOnERC721Received(address(0), to, tokenId, _data),
                "!ERC721Receiver"
            );
        }

        _owners[tokenIdBatchHead] = to;
        _batchHead.set(tokenIdBatchHead);
        _minted += quantity;

        _afterTokenTransfers(address(0), to, tokenIdBatchHead, quantity);
    }

    /**
     * @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 {
        (address owner, uint256 tokenIdBatchHead) = _ownerAndBatchHeadOf(
            tokenId
        );

        require(owner == from, "notown");
        require(to != address(0), "zeroaddress");

        _beforeTokenTransfers(from, to, tokenId, 1);

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

        uint256 nextTokenId = tokenId + 1;

        if (!_batchHead.get(nextTokenId) && nextTokenId < _minted) {
            _owners[nextTokenId] = from;
            _batchHead.set(nextTokenId);
        }

        _owners[tokenId] = to;
        if (tokenId != tokenIdBatchHead) {
            _batchHead.set(tokenId);
        }

        emit Transfer(from, to, tokenId);

        _afterTokenTransfers(from, to, tokenId, 1);
    }

    /**
     * @dev Approve `to` to operate on `tokenId`
     *
     * Emits a {Approval} event.
     */
    function _approve(address to, uint256 tokenId) internal virtual {
        _tokenApprovals[tokenId] = to;
        emit Approval(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.onERC721Received.selector;
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert("!ERC721Receiver");
                } else {
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        } else {
            return true;
        }
    }

    function _getBatchHead(uint256 tokenId)
        internal
        view
        returns (uint256 tokenIdBatchHead)
    {
        tokenIdBatchHead = _batchHead.scanForward(tokenId);
    }

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

    /**
     * @dev See {IERC721Enumerable-tokenByIndex}.
     */
    function tokenByIndex(uint256 index)
        public
        view
        virtual
        override
        returns (uint256)
    {
        require(index < totalSupply(), "oob");

        uint256 count;
        for (uint256 i; i < _minted; i++) {
            if (_exists(i)) {
                if (count == index) return i;
                else count++;
            }
        }
    }

    /**
     * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index)
        public
        view
        virtual
        override
        returns (uint256 tokenId)
    {
        uint256 count;
        for (uint256 i; i < _minted; i++) {
            if (_exists(i) && owner == ownerOf(i)) {
                if (count == index) return i;
                else count++;
            }
        }

        revert("oob");
    }

    /**
     * @dev Hook that is called before a set of serially-ordered token ids are about to be transferred. This includes minting.
     *
     * startTokenId - the first token id to be transferred
     * quantity - the amount to be transferred
     *
     * 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`.
     */
    function _beforeTokenTransfers(
        address from,
        address to,
        uint256 startTokenId,
        uint256 quantity
    ) internal virtual {}

    /**
     * @dev Hook that is called after a set of serially-ordered token ids have been transferred. This includes
     * minting.
     *
     * startTokenId - the first token id to be transferred
     * quantity - the amount to be transferred
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero.
     * - `from` and `to` are never both zero.
     */
    function _afterTokenTransfers(
        address from,
        address to,
        uint256 startTokenId,
        uint256 quantity
    ) internal virtual {}
}

File 32 of 35 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)

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

File 33 of 35 : IERC721Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)

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 34 of 35 : IERC721Enumerable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)

pragma solidity ^0.8.0;

import "../IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Enumerable is IERC721 {
    /**
     * @dev Returns the total amount of tokens stored by the contract.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
     * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);

    /**
     * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
     * Use along with {totalSupply} to enumerate all tokens.
     */
    function tokenByIndex(uint256 index) external view returns (uint256);
}

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

pragma solidity ^0.8.9;

library Address {
    function isContract(address account) internal view returns (bool) {
        uint size;
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 550,
    "details": {
      "yul": false
    }
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_vrfV2Coordinator","type":"address"},{"internalType":"bytes32","name":"keyHash_","type":"bytes32"},{"internalType":"uint64","name":"subscriptionId_","type":"uint64"},{"internalType":"address","name":"_accessPassContract","type":"address"},{"internalType":"address","name":"_factionContract","type":"address"},{"internalType":"address","name":"_renderingContract","type":"address"},{"internalType":"address","name":"_vendorContract","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidItemType","type":"error"},{"inputs":[],"name":"InvalidLength","type":"error"},{"inputs":[],"name":"InvalidOwner","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidString","type":"error"},{"inputs":[],"name":"InvalidTokenIds","type":"error"},{"inputs":[],"name":"InvalidValue","type":"error"},{"inputs":[],"name":"ItemRequiresMoreXP","type":"error"},{"inputs":[{"internalType":"address","name":"have","type":"address"},{"internalType":"address","name":"want","type":"address"}],"name":"OnlyCoordinatorCanFulfill","type":"error"},{"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":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ClaimedTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"string","name":"typeOf","type":"string"},{"indexed":false,"internalType":"uint256","name":"itemTokenId","type":"uint256"}],"name":"Equipped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"string","name":"lore","type":"string"}],"name":"LoreChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"string","name":"name","type":"string"}],"name":"NameChanged","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":false,"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"RandomnessRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"currentTokenId","type":"uint256"}],"name":"Revealed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"approvedContract","type":"address"}],"name":"TokenLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"approvedContract","type":"address"}],"name":"TokenUnlocked","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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"UnStaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"string","name":"typeOf","type":"string"},{"indexed":false,"internalType":"uint256","name":"itemTokenId","type":"uint256"}],"name":"Unequipped","type":"event"},{"inputs":[],"name":"DEAD_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accessPassContract","outputs":[{"internalType":"contract IERC721","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"addXP","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"addressToMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":"","type":"address"}],"name":"approvedContract","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","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":"_tokenIds","type":"uint256[]"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"typeOf","type":"string"},{"internalType":"uint256","name":"itemTokenId","type":"uint256"}],"name":"equip","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factionContract","outputs":[{"internalType":"contract IBrawlerBearzFaction","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"contractAddress","type":"address"}],"name":"freeId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"getAddressMintsRemaining","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":"tokenId","type":"uint256"}],"name":"getMetadata","outputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"lore","type":"string"},{"internalType":"uint256","name":"background","type":"uint256"},{"internalType":"uint256","name":"head","type":"uint256"},{"internalType":"uint256","name":"weapon","type":"uint256"},{"internalType":"uint256","name":"armor","type":"uint256"},{"internalType":"uint256","name":"faceArmor","type":"uint256"},{"internalType":"uint256","name":"eyewear","type":"uint256"},{"internalType":"uint256","name":"misc","type":"uint256"},{"internalType":"uint256","name":"xp","type":"uint256"},{"internalType":"bool","name":"isUnlocked","type":"bool"},{"internalType":"uint256","name":"faction","type":"uint256"}],"internalType":"struct IBrawlerBearzCommon.CustomMetadata","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"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":[],"name":"isPublicLive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isRevealed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"isUnlocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isWhitelistLive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keyHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liveAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"lockCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"lockId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"lockMap","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"lockMapIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxPerWallet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"merkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"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":"price","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256[]","name":"randomWords","type":"uint256[]"}],"name":"rawFulfillRandomWords","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renderer","outputs":[{"internalType":"contract IBrawlerBearzRenderer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reveal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"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":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"seed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isRevealed","type":"bool"}],"name":"setIsRevealed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_liveAt","type":"uint256"}],"name":"setLiveAt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"lore","type":"string"}],"name":"setLore","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxPerWallet","type":"uint256"}],"name":"setMaxPerWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxSupply","type":"uint256"}],"name":"setMaxSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"}],"name":"setMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"name","type":"string"}],"name":"setName","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_price","type":"uint256"}],"name":"setPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_renderingContractAddress","type":"address"}],"name":"setRenderingContractAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isShopDropEnabled","type":"bool"}],"name":"setShopDropEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vendorContractAddress","type":"address"}],"name":"setVendorContractAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_whitelistLiveAt","type":"uint256"}],"name":"setWhitelistLiveAt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"subscriptionId","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"subtractXP","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":[],"name":"teamMintAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"}],"name":"teamMints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"view","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":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"typeOf","type":"string"}],"name":"unequip","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"unlockId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_contracts","type":"address[]"},{"internalType":"bool[]","name":"_values","type":"bool[]"}],"name":"updateApprovedContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vendorContract","outputs":[{"internalType":"contract IBrawlerBearzDynamicItems","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"walletOfOwner","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"whitelistLiveAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"}],"name":"whitelistMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6101406040526001600b8190556080601455601580546001600160a01b0319167339bfa2b4319581bc885a2d4b9f0c90c2e1c24b871790556363248160601655636324e3d0601755610d07601855669fdf42f6e480006019556003601a55601b805461ffff191690911790553480156200007857600080fd5b5060405162006a0a38038062006a0a8339810160408190526200009b9162000763565b8662061a806003826040518060400160405280600d81526020016c213930bbb632b9102132b0b93d60991b81525060405180604001604052806002815260200161212160f11b8152508160019080519060200190620000fc92919062000653565b5080516200011290600290602084019062000653565b5050506001600160a01b039081166080529290921660a05263ffffffff1660c05261ffff1660e052620001453362000207565b60016012556101008690526001600160401b038516610120526200016b60003362000259565b620001977fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e3362000259565b602080546001600160a01b038681166001600160a01b03199283161783556022805487831690841617905560218054868316908416179055601f80549185169190921617905560408051918201905260008152620001fa90339060019062000269565b5050505050505062000a52565b600d80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b620002658282620002a8565b5050565b60006004549050600b54600a600083815260200190815260200160002081905550620002a28484846200033260201b620033a51760201c565b50505050565b620002b4828262000366565b620002655760008281526013602090815260408083206001600160a01b03851684529091529020805460ff19166001179055620002ee3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6004546200034e60078262000393602090811b620033d517901c565b620002a2848484620003bf60201b620034011760201c565b60008281526013602090815260408083206001600160a01b038516845290915290205460ff165b92915050565b600881901c600090815260209290925260409091208054600160ff1b60ff9093169290921c9091179055565b60045482620003eb5760405162461bcd60e51b8152600401620003e29062000830565b60405180910390fd5b6001600160a01b038416620004145760405162461bcd60e51b8152600401620003e29062000866565b60005b83811015620004ad5760006200042e82846200088e565b60405190915081906001600160a01b038816906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a46200047860008783876200051d565b620004975760405162461bcd60e51b8152600401620003e290620008d0565b5080620004a481620008e2565b91505062000417565b506000818152600360209081526040822080546001600160a01b0319166001600160a01b038816179055620004ee9190839062000393811b620033d517901c565b82600460008282546200050291906200088e565b90915550620002a2905060008583866001600160e01b038516565b60006200053e846001600160a01b03166200064d60201b6200353f1760201c565b156200064157604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290620005789033908990889088906004016200097c565b602060405180830381600087803b1580156200059357600080fd5b505af1925050508015620005c6575060408051601f3d908101601f19168201909252620005c391810190620009e6565b60015b62000626573d808015620005f7576040519150601f19603f3d011682016040523d82523d6000602084013e620005fc565b606091505b5080516200061e5760405162461bcd60e51b8152600401620003e290620008d0565b805181602001fd5b6001600160e01b031916630a85bd0160e11b14905062000645565b5060015b949350505050565b3b151590565b828054620006619062000a21565b90600052602060002090601f016020900481019282620006855760008555620006d0565b82601f10620006a057805160ff1916838001178555620006d0565b82800160010185558215620006d0579182015b82811115620006d0578251825591602001919060010190620006b3565b50620006de929150620006e2565b5090565b5b80821115620006de5760008155600101620006e3565b60006001600160a01b0382166200038d565b6200071681620006f9565b81146200072257600080fd5b50565b80516200038d816200070b565b8062000716565b80516200038d8162000732565b6001600160401b03811662000716565b80516200038d8162000746565b600080600080600080600060e0888a031215620007835762000783600080fd5b6000620007918a8a62000725565b9750506020620007a48a828b0162000739565b9650506040620007b78a828b0162000756565b9550506060620007ca8a828b0162000725565b9450506080620007dd8a828b0162000725565b93505060a0620007f08a828b0162000725565b92505060c0620008038a828b0162000725565b91505092959891949750929550565b60048152600060208201637a65726f60e01b815291505b5060200190565b602080825281016200038d8162000812565b600c81526000602082016b217a65726f6164647265737360a01b8152915062000829565b602080825281016200038d8162000842565b634e487b7160e01b600052601160045260246000fd5b60008219821115620008a457620008a462000878565b500190565b600f81526000602082016e10a2a9219b9918a932b1b2b4bb32b960891b8152915062000829565b602080825281016200038d81620008a9565b6000600019821415620008f957620008f962000878565b5060010190565b6200090b81620006f9565b82525050565b806200090b565b60005b83811015620009355781810151838201526020016200091b565b83811115620002a25750506000910152565b600062000952825190565b8084526020840193506200096b81856020860162000918565b601f01601f19169290920192915050565b608081016200098c828762000900565b6200099b602083018662000900565b620009aa604083018562000911565b8181036060830152620009be818462000947565b9695505050505050565b6001600160e01b0319811662000716565b80516200038d81620009c8565b600060208284031215620009fd57620009fd600080fd5b6000620006458484620009d9565b634e487b7160e01b600052602260045260246000fd5b60028104600182168062000a3657607f821691505b6020821081141562000a4c5762000a4c62000a0b565b50919050565b60805160a05160c05160e0516101005161012051615f5362000ab7600039600081816105be0152613da001526000818161096c0152613d7e01526000613dc201526000613de401526000613d4901526000818161112901526111510152615f536000f3fe60806040526004361061048e5760003560e01c80636f8b44b011610265578063a574cea411610154578063d2cab056116100d1578063e268e4d311610095578063f0f442601161006f578063f0f4426014610ef2578063f2fde38b14610f12578063fe55932a14610f3257600080fd5b8063e268e4d314610e69578063e985e9c514610e89578063ea07e68a14610ed257600080fd5b8063d2cab05614610de0578063d50efd7014610df3578063d547741f14610e13578063d5abeb0114610e33578063d6257bb814610e4957600080fd5b8063b7b2040411610118578063b7b2040414610d4a578063b88d4fde14610d60578063c87b56dd14610d80578063ca2eb5ae14610da0578063cbcc418814610dc057600080fd5b8063a574cea414610c97578063a9cdd60d14610cc4578063ac52e64414610ce4578063b1a6505f14610d04578063b4bc159a14610d3457600080fd5b806394d216d6116101e2578063a035b1fe116101a6578063a035b1fe14610c24578063a0712d6814610c3a578063a217fddf14610c4d578063a22cb46514610c62578063a475b5dd14610c8257600080fd5b806394d216d614610b825780639556483714610ba257806395d89b4114610bc25780639a9e2e4a14610bd75780639ec00c9514610bf757600080fd5b80638984cbb0116102295780638984cbb014610abe5780638ada6b0f14610ade5780638da5cb5b14610afe57806391b7f5ed14610b1c57806391d1485414610b3c57600080fd5b80636f8b44b014610a1b57806370a0823114610a3b578063715018a614610a5b57806372abc8b714610a705780637cb6475914610a9e57600080fd5b80633ccfd60b116103815780634f6ccce7116102fe57806361728f39116102c257806361728f391461095a57806361d027b31461098e5780636352211e146109ae578063650b00f6146109ce5780636ba4c138146109fb57600080fd5b80634f6ccce7146108ce5780635146ea0e146108ee57806353f8bb9a1461090e57806354214f69146109245780635e5f3ce41461094357600080fd5b8063453c231011610345578063453c23101461084257806349a5980a146108585780634aa0acc0146108785780634e6fd6c4146108985780634f09cd52146108ae57600080fd5b80633ccfd60b146107a05780633ef628a3146107b557806340a9c8df146107d557806342842e0e146107f5578063438b63001461081557600080fd5b806323b872dd1161040f5780632f2ff15d116103d35780632f2ff15d146107095780632f745c59146107295780633281fa3f14610749578063334d6e8b1461076057806336568abe1461078057600080fd5b806323b872dd14610642578063248a9ca3146106625780632799cde0146106925780632cba8123146106b25780632eb4a7ab146106f357600080fd5b8063095ea7b311610456578063095ea7b31461058a57806309c1ba2e146105ac57806312b40a9f146105ed57806318160ddd1461060d5780631fe543e31461062257600080fd5b806301ffc9a71461049357806306a9a164146104c957806306fdde03146104f6578063081812fc1461051857806309308e5d14610545575b600080fd5b34801561049f57600080fd5b506104b36104ae36600461478b565b610f52565b6040516104c091906147b6565b60405180910390f35b3480156104d557600080fd5b506020546104e9906001600160a01b031681565b6040516104c09190614806565b34801561050257600080fd5b5061050b610f63565b6040516104c09190614874565b34801561052457600080fd5b50610538610533366004614896565b610ff5565b6040516104c091906148d1565b34801561055157600080fd5b5061057d6105603660046148f3565b601160209081526000928352604080842090915290825290205481565b6040516104c09190614936565b34801561059657600080fd5b506105aa6105a5366004614944565b611041565b005b3480156105b857600080fd5b506105e07f000000000000000000000000000000000000000000000000000000000000000081565b6040516104c09190614987565b3480156105f957600080fd5b506105aa610608366004614995565b6110c7565b34801561061957600080fd5b5061057d611102565b34801561062e57600080fd5b506105aa61063d366004614ab8565b61111e565b34801561064e57600080fd5b506105aa61065d366004614b06565b611199565b34801561066e57600080fd5b5061057d61067d366004614896565b60009081526013602052604090206001015490565b34801561069e57600080fd5b506105aa6106ad366004614896565b6111d0565b3480156106be57600080fd5b506105386106cd366004614b56565b60106020908152600092835260408084209091529082529020546001600160a01b031681565b3480156106ff57600080fd5b5061057d601c5481565b34801561071557600080fd5b506105aa6107243660046148f3565b611228565b34801561073557600080fd5b5061057d610744366004614944565b61124d565b34801561075557600080fd5b5060165442116104b3565b34801561076c57600080fd5b506105aa61077b366004614bca565b6112da565b34801561078c57600080fd5b506105aa61079b3660046148f3565b61192b565b3480156107ac57600080fd5b506105aa61195d565b3480156107c157600080fd5b506105aa6107d0366004614c3a565b6119f6565b3480156107e157600080fd5b506105aa6107f0366004614896565b611bcf565b34801561080157600080fd5b506105aa610810366004614b06565b611c27565b34801561082157600080fd5b50610835610830366004614995565b611c42565b6040516104c09190614cf3565b34801561084e57600080fd5b5061057d601a5481565b34801561086457600080fd5b506105aa610873366004614d17565b611cfb565b34801561088457600080fd5b506105aa610893366004614b56565b611d2e565b3480156108a457600080fd5b5061053861dead81565b3480156108ba57600080fd5b506105aa6108c9366004614995565b611d83565b3480156108da57600080fd5b5061057d6108e9366004614896565b611de2565b3480156108fa57600080fd5b506105aa610909366004614b56565b611e5c565b34801561091a57600080fd5b5061057d60175481565b34801561093057600080fd5b50601b546104b390610100900460ff1681565b34801561094f57600080fd5b5060175442116104b3565b34801561096657600080fd5b5061057d7f000000000000000000000000000000000000000000000000000000000000000081565b34801561099a57600080fd5b50601554610538906001600160a01b031681565b3480156109ba57600080fd5b506105386109c9366004614896565b611ea7565b3480156109da57600080fd5b5061057d6109e9366004614896565b600f6020526000908152604090205481565b348015610a0757600080fd5b506105aa610a16366004614d83565b611ebe565b348015610a2757600080fd5b506105aa610a36366004614896565b611fc7565b348015610a4757600080fd5b5061057d610a56366004614995565b611fe5565b348015610a6757600080fd5b506105aa61206e565b348015610a7c57600080fd5b506104b3610a8b366004614896565b6000908152600f60205260409020541590565b348015610aaa57600080fd5b506105aa610ab9366004614896565b6120a4565b348015610aca57600080fd5b506105aa610ad9366004614896565b6120c2565b348015610aea57600080fd5b506021546104e9906001600160a01b031681565b348015610b0a57600080fd5b50600d546001600160a01b0316610538565b348015610b2857600080fd5b506105aa610b37366004614896565b6120e0565b348015610b4857600080fd5b506104b3610b573660046148f3565b60009182526013602090815260408084206001600160a01b0393909316845291905290205460ff1690565b348015610b8e57600080fd5b506105aa610b9d3660046148f3565b6120fe565b348015610bae57600080fd5b5061057d610bbd366004614896565b612157565b348015610bce57600080fd5b5061050b6121f1565b348015610be357600080fd5b506022546104e9906001600160a01b031681565b348015610c0357600080fd5b5061057d610c12366004614995565b601e6020526000908152604090205481565b348015610c3057600080fd5b5061057d60195481565b6105aa610c48366004614896565b612200565b348015610c5957600080fd5b5061057d600081565b348015610c6e57600080fd5b506105aa610c7d366004614dcb565b6122fd565b348015610c8e57600080fd5b506105aa612395565b348015610ca357600080fd5b50610cb7610cb2366004614896565b6123f6565b6040516104c09190614ef9565b348015610cd057600080fd5b506105aa610cdf366004614995565b612631565b348015610cf057600080fd5b506105aa610cff366004614f0a565b61266c565b348015610d1057600080fd5b506104b3610d1f366004614995565b600e6020526000908152604090205460ff1681565b348015610d4057600080fd5b5061057d60145481565b348015610d5657600080fd5b5061057d60165481565b348015610d6c57600080fd5b506105aa610d7b366004615012565b612753565b348015610d8c57600080fd5b5061050b610d9b366004614896565b612791565b348015610dac57600080fd5b5061057d610dbb366004614995565b612b37565b348015610dcc57600080fd5b506105aa610ddb366004614d17565b612b69565b6105aa610dee366004615085565b612b95565b348015610dff57600080fd5b506105aa610e0e366004614c3a565b612db8565b348015610e1f57600080fd5b506105aa610e2e3660046148f3565b6130cd565b348015610e3f57600080fd5b5061057d60185481565b348015610e5557600080fd5b506105aa610e64366004614896565b6130f2565b348015610e7557600080fd5b506105aa610e84366004614896565b613110565b348015610e9557600080fd5b506104b3610ea43660046150d5565b6001600160a01b03918216600090815260066020908152604080832093909416825291909152205460ff1690565b348015610ede57600080fd5b50601f546104e9906001600160a01b031681565b348015610efe57600080fd5b506105aa610f0d366004614995565b61312e565b348015610f1e57600080fd5b506105aa610f2d366004614995565b613169565b348015610f3e57600080fd5b506105aa610f4d366004614c3a565b6131c2565b6000610f5d82613545565b92915050565b606060018054610f729061510d565b80601f0160208091040260200160405190810160405280929190818152602001828054610f9e9061510d565b8015610feb5780601f10610fc057610100808354040283529160200191610feb565b820191906000526020600020905b815481529060010190602001808311610fce57829003601f168201915b5050505050905090565b60006110008261356a565b6110255760405162461bcd60e51b815260040161101c9061515b565b60405180910390fd5b506000908152600560205260409020546001600160a01b031690565b600061104c82611ea7565b9050806001600160a01b0316836001600160a01b031614156110805760405162461bcd60e51b815260040161101c9061518b565b336001600160a01b038216148061109c575061109c8133610ea4565b6110b85760405162461bcd60e51b815260040161101c906151bb565b6110c283836135a1565b505050565b600080516020615dfe8339815191526110df8161360f565b50602180546001600160a01b0319166001600160a01b0392909216919091179055565b600061110c613619565b60045461111991906151e1565b905090565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461118b57337f000000000000000000000000000000000000000000000000000000000000000060405163073e64fd60e21b815260040161101c9291906151f8565b6111958282613679565b5050565b6000818152600f6020526040902054156111c55760405162461bcd60e51b815260040161101c9061522e565b6110c28383836136c3565b7ff11b02a75234472a5060a94045900fd33989cb6e8ec8dd50e38ed9a49356cba46111fa8161360f565b6112038261356a565b61121f5760405162461bcd60e51b815260040161101c90615256565b611195826136f4565b6000828152601360205260409020600101546112438161360f565b6110c28383613804565b60008060005b6004548110156112c1576112668161356a565b801561128b575061127681611ea7565b6001600160a01b0316856001600160a01b0316145b156112af57838214156112a1579150610f5d9050565b816112ab81615266565b9250505b806112b981615266565b915050611253565b5060405162461bcd60e51b815260040161101c9061529b565b83336112e582611ea7565b6001600160a01b03161461130c576040516349e27cff60e01b815260040160405180910390fd5b601f54604051627eeac760e11b815283916001600160a01b03169062fdd58e9061133c90339085906004016152ab565b60206040518083038186803b15801561135457600080fd5b505afa158015611368573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138c91906152d1565b6113a9576040516349e27cff60e01b815260040160405180910390fd5b8285858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050601f5460405163c19a4ef560e01b81526001600160a01b03909116925063c19a4ef59150611410908590600401614936565b60006040518083038186803b15801561142857600080fd5b505afa15801561143c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611464919081019061534a565b60405160200161147491906153a7565b604051602081830303815290604052805190602001208160405160200161149b91906153a7565b60405160208183030381529060405280519060200120146114cf57604051631e4cbc7f60e21b815260040160405180910390fd5b601f5460405163adc0f74560e01b815286918a916001600160a01b039091169063adc0f74590611503908590600401614936565b60206040518083038186803b15801561151b57600080fd5b505afa15801561152f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061155391906152d1565b6000828152601d6020526040902060090154101561158457604051636e7e5ecf60e01b815260040160405180910390fd5b600260125414156115a75760405162461bcd60e51b815260040161101c906153e7565b60026012556040516000906115c2908b908b9060200161540a565b60408051601f19818403018152828252805160209182012060008f8152601d835292909220919350909183916115f89101615417565b604051602081830303815290604052805190602001201415611642576004810154156116365760405162461bcd60e51b815260040161101c90615447565b60048101899055611877565b816040516020016116529061546b565b60405160208183030381529060405280519060200120141561169c576003810154156116905760405162461bcd60e51b815260040161101c90615447565b60038101899055611877565b816040516020016116ac90615476565b6040516020818303038152906040528051906020012014156116f6576005810154156116ea5760405162461bcd60e51b815260040161101c90615447565b60058101899055611877565b81604051602001611706906154a6565b604051602081830303815290604052805190602001201415611750576002810154156117445760405162461bcd60e51b815260040161101c90615447565b60028101899055611877565b81604051602001611760906154c8565b6040516020818303038152906040528051906020012014156117aa5760068101541561179e5760405162461bcd60e51b815260040161101c90615447565b60068101899055611877565b816040516020016117ba906154d3565b604051602081830303815290604052805190602001201415611804576007810154156117f85760405162461bcd60e51b815260040161101c90615447565b60078101899055611877565b81604051602001611814906154fc565b60405160208183030381529060405280519060200120141561185e576008810154156118525760405162461bcd60e51b815260040161101c90615447565b60088101899055611877565b604051631e4cbc7f60e21b815260040160405180910390fd5b601f546001600160a01b0316639eef4aa68a6001336040518463ffffffff1660e01b81526004016118aa9392919061551c565b600060405180830381600087803b1580156118c457600080fd5b505af11580156118d8573d6000803e3d6000fd5b505050508b7f913887fd0b468ebff22eac13535c8b5a656d89040bff7d16d7d4531bf27030d68c8c8c60405161191093929190615567565b60405180910390a25050600160125550505050505050505050565b6001600160a01b03811633146119535760405162461bcd60e51b815260040161101c906155e5565b61119582826138a6565b600080516020615dfe8339815191526119758161360f565b6015546040516000916001600160a01b0316904790611993906155f5565b60006040518083038185875af1925050503d80600081146119d0576040519150601f19603f3d011682016040523d82523d6000602084013e6119d5565b606091505b50509050806111955760405162461bcd60e51b815260040161101c9061561a565b8233611a0182611ea7565b6001600160a01b031614611a28576040516349e27cff60e01b815260040160405180910390fd5b8282600082828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509394505050505b8151811015611ae3576000828281518110611a8257611a8261562a565b01602001516001600160f81b0319169050601160f91b811480611ab25750601760fa1b6001600160f81b03198216145b15611ad057604051630ec0325960e21b815260040160405180910390fd5b5080611adb81615266565b915050611a65565b50600086868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052508c8152601d6020526040908190209051949550611b3f946001909101935091506156ae9050565b604051809103902081805190602001201415611b6e57604051632a9ffab760e21b815260040160405180910390fd5b6000888152601d60205260409020611b8a9060010188886146d0565b50877f1d83c2282d074aad212f8c5d02271066bf42c603a85c4c9e4f07d1eb8c1998218888604051611bbd9291906156ba565b60405180910390a25050505050505050565b7ff11b02a75234472a5060a94045900fd33989cb6e8ec8dd50e38ed9a49356cba4611bf98161360f565b611c028261356a565b611c1e5760405162461bcd60e51b815260040161101c90615256565b61119582613929565b6110c283838360405180602001604052806000815250612753565b60606000611c4f83611fe5565b905080611c705760408051600080825260208201909252905b509392505050565b60008167ffffffffffffffff811115611c8b57611c8b6149b6565b604051908082528060200260200182016040528015611cb4578160200160208202803683370190505b50905060005b82811015611c6857611ccc858261124d565b828281518110611cde57611cde61562a565b602090810291909101015280611cf381615266565b915050611cba565b600080516020615dfe833981519152611d138161360f565b50601b80549115156101000261ff0019909216919091179055565b7ff11b02a75234472a5060a94045900fd33989cb6e8ec8dd50e38ed9a49356cba4611d588161360f565b6000838152601d602052604081206009018054849290611d799084906151e1565b9091555050505050565b600080516020615dfe833981519152611d9b8161360f565b600060145411611dbd5760405162461bcd60e51b815260040161101c906156e5565b611dd98260145460405180602001604052806000815250613a96565b50506000601455565b6000611dec611102565b8210611e0a5760405162461bcd60e51b815260040161101c9061529b565b6000805b600454811015611e5557611e218161356a565b15611e435783821415611e35579392505050565b81611e3f81615266565b9250505b80611e4d81615266565b915050611e0e565b5050919050565b7ff11b02a75234472a5060a94045900fd33989cb6e8ec8dd50e38ed9a49356cba4611e868161360f565b6000838152601d602052604081206009018054849290611d799084906156f5565b6000806000611eb584613ab6565b50949350505050565b60026012541415611ee15760405162461bcd60e51b815260040161101c906153e7565b60026012556017544211611f075760405162461bcd60e51b815260040161101c90615256565b60005b81811015611fa3576020546001600160a01b03166323b872dd3361dead868686818110611f3957611f3961562a565b905060200201356040518463ffffffff1660e01b8152600401611f5e9392919061570d565b600060405180830381600087803b158015611f7857600080fd5b505af1158015611f8c573d6000803e3d6000fd5b505050508080611f9b90615266565b915050611f0a565b50611fbe336040805160208101909152600081528390613a96565b50506001601255565b600080516020615dfe833981519152611fdf8161360f565b50601855565b60006001600160a01b03821661200d5760405162461bcd60e51b815260040161101c90615758565b6000805b600454811015612067576120248161356a565b156120575761203281611ea7565b6001600160a01b0316846001600160a01b031614156120575761205482615266565b91505b61206081615266565b9050612011565b5092915050565b600d546001600160a01b031633146120985760405162461bcd60e51b815260040161101c9061579a565b6120a26000613b08565b565b600080516020615dfe8339815191526120bc8161360f565b50601c55565b600080516020615dfe8339815191526120da8161360f565b50601755565b600080516020615dfe8339815191526120f88161360f565b50601955565b7ff11b02a75234472a5060a94045900fd33989cb6e8ec8dd50e38ed9a49356cba46121288161360f565b6121318361356a565b61214d5760405162461bcd60e51b815260040161101c90615256565b6110c28383613b5a565b60006121628261356a565b61217e5760405162461bcd60e51b815260040161101c9061515b565b60006009600061218d85613ced565b815260200190815260200160002054905080600014156121bf5760405162461bcd60e51b815260040161101c906157cc565b80836040516020016121d29291906157dc565b60408051601f1981840301815291905280516020909101209392505050565b606060028054610f729061510d565b60175442116122215760405162461bcd60e51b815260040161101c90615256565b6018548161222d611102565b61223791906156f5565b106122545760405162461bcd60e51b815260040161101c90615802565b6019546122619082615812565b3410156122805760405162461bcd60e51b815260040161101c90615849565b601a54336000908152601e602052604090205461229e9083906156f5565b106122bb5760405162461bcd60e51b815260040161101c90615871565b336000908152601e6020526040812080548392906122da9084906156f5565b909155506122fa9050338260405180602001604052806000815250613a96565b50565b6001600160a01b0382163314156123265760405162461bcd60e51b815260040161101c906158a0565b3360008181526006602090815260408083206001600160a01b038716808552925291829020805460ff191685151517905590519091907f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31906123899085906147b6565b60405180910390a35050565b600080516020615dfe8339815191526123ad8161360f565b6123b5613d37565b7f15120e52505e619cbf6c2af910d5cf7f9ee1befa55801b078c33e93880b2d6096123de611102565b6040516123eb9190614936565b60405180910390a150565b61245c60405180610180016040528060608152602001606081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600015158152602001600081525090565b6124658261356a565b6124815760405162461bcd60e51b815260040161101c90615256565b6000828152601d602052604090819020815161018081019092528054829082906124aa9061510d565b80601f01602080910402602001604051908101604052809291908181526020018280546124d69061510d565b80156125235780601f106124f857610100808354040283529160200191612523565b820191906000526020600020905b81548152906001019060200180831161250657829003601f168201915b5050505050815260200160018201805461253c9061510d565b80601f01602080910402602001604051908101604052809291908181526020018280546125689061510d565b80156125b55780601f1061258a576101008083540402835291602001916125b5565b820191906000526020600020905b81548152906001019060200180831161259857829003601f168201915b505050918352505060028201546020820152600382015460408201526004820154606082015260058201546080820152600682015460a0820152600782015460c0820152600882015460e08201526009820154610100820152600a82015460ff161515610120820152600b909101546101409091015292915050565b600080516020615dfe8339815191526126498161360f565b50601f80546001600160a01b0319166001600160a01b0392909216919091179055565b600d546001600160a01b031633146126965760405162461bcd60e51b815260040161101c9061579a565b8281146126b55760405162461bcd60e51b815260040161101c906158ce565b60005b8381101561274c578282828181106126d2576126d261562a565b90506020020160208101906126e79190614d17565b600e60008787858181106126fd576126fd61562a565b90506020020160208101906127129190614995565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790558061274481615266565b9150506126b8565b5050505050565b6000828152600f60205260409020541561277f5760405162461bcd60e51b815260040161101c9061522e565b61278b84848484613ec4565b50505050565b601b54606090610100900460ff1661282757602154604051632914130560e01b81526001600160a01b03909116906329141305906127d3908590600401614936565b60006040518083038186803b1580156127eb57600080fd5b505afa1580156127ff573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f5d919081019061534a565b6128308261356a565b61284c5760405162461bcd60e51b815260040161101c90615256565b6000828152601d6020526040808220815161018081019092528054829082906128749061510d565b80601f01602080910402602001604051908101604052809291908181526020018280546128a09061510d565b80156128ed5780601f106128c2576101008083540402835291602001916128ed565b820191906000526020600020905b8154815290600101906020018083116128d057829003601f168201915b505050505081526020016001820180546129069061510d565b80601f01602080910402602001604051908101604052809291908181526020018280546129329061510d565b801561297f5780601f106129545761010080835404028352916020019161297f565b820191906000526020600020905b81548152906001019060200180831161296257829003601f168201915b505050918352505060028201546020820152600382015460408201526004820154606082015260058201546080820152600682015460a0820152600782015460c0820152600882015460e08201526009820154610100820152600a82015460ff161515610120820152600b90910154610140909101529050612a0e836000908152600f60205260409020541590565b15156101408201526022546001600160a01b031663de325b8f612a3085611ea7565b6040518263ffffffff1660e01b8152600401612a4c91906148d1565b60206040518083038186803b158015612a6457600080fd5b505afa158015612a78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a9c91906152d1565b6101608201526021546001600160a01b031663f3b95d0384612abd81612157565b846040518463ffffffff1660e01b8152600401612adc939291906158de565b60006040518083038186803b158015612af457600080fd5b505afa158015612b08573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612b30919081019061534a565b9392505050565b6001600160a01b0381166000908152601e6020526040812054601a54600191612b5f916151e1565b610f5d91906151e1565b600080516020615dfe833981519152612b818161360f565b50601b805460ff1916911515919091179055565b60026012541415612bb85760405162461bcd60e51b815260040161101c906153e7565b60026012556016544211612bde5760405162461bcd60e51b815260040161101c90615256565b60185483612bea611102565b612bf491906156f5565b10612c115760405162461bcd60e51b815260040161101c90615802565b601954612c1e9084615812565b341015612c3d5760405162461bcd60e51b815260040161101c90615849565b601a54336000908152601e6020526040902054612c5b9085906156f5565b10612c785760405162461bcd60e51b815260040161101c90615871565b600033604051602001612c8b919061593c565b604051602081830303815290604052805190602001209050612ce483838080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050601c549150849050613ef6565b612d005760405162461bcd60e51b815260040161101c90615969565b336000908152601e602052604081208054869290612d1f9084906156f5565b90915550612d3f9050338560405180602001604052806000815250613a96565b601b5460ff1615612dad57601f546001600160a01b0316633cbf48e933866040518363ffffffff1660e01b8152600401612d7a9291906152ab565b600060405180830381600087803b158015612d9457600080fd5b505af1158015612da8573d6000803e3d6000fd5b505050505b505060016012555050565b8233612dc382611ea7565b6001600160a01b031614612dea576040516349e27cff60e01b815260040160405180910390fd5b60026012541415612e0d5760405162461bcd60e51b815260040161101c906153e7565b60026012556040516000908190612e2a908690869060200161540a565b60408051601f19818403018152828252805160209182012060008a8152601d83529290922091935090918391612e609101615417565b604051602081830303815290604052805190602001201415612e8e5760048101805460009091559250612ffe565b81604051602001612e9e9061546b565b604051602081830303815290604052805190602001201415612ecc5760038101805460009091559250612ffe565b81604051602001612edc90615476565b604051602081830303815290604052805190602001201415612f0a5760058101805460009091559250612ffe565b81604051602001612f1a906154a6565b604051602081830303815290604052805190602001201415612f485760028101805460009091559250612ffe565b81604051602001612f58906154c8565b604051602081830303815290604052805190602001201415612f865760068101805460009091559250612ffe565b81604051602001612f96906154d3565b604051602081830303815290604052805190602001201415612fc45760078101805460009091559250612ffe565b81604051602001612fd4906154fc565b60405160208183030381529060405280519060200120141561185e57600881018054600090915592505b6000831161301e5760405162461bcd60e51b815260040161101c90615994565b601f546001600160a01b031663466e79eb846001336040518463ffffffff1660e01b81526004016130519392919061551c565b600060405180830381600087803b15801561306b57600080fd5b505af115801561307f573d6000803e3d6000fd5b50505050867fd4596d80f81394606eec2500c28df457c069fe45c83d304190e97e0a8061d6b78787866040516130b793929190615567565b60405180910390a2505060016012555050505050565b6000828152601360205260409020600101546130e88161360f565b6110c283836138a6565b600080516020615dfe83398151915261310a8161360f565b50601655565b600080516020615dfe8339815191526131288161360f565b50601a55565b600080516020615dfe8339815191526131468161360f565b50601580546001600160a01b0319166001600160a01b0392909216919091179055565b600d546001600160a01b031633146131935760405162461bcd60e51b815260040161101c9061579a565b6001600160a01b0381166131b95760405162461bcd60e51b815260040161101c906159e7565b6122fa81613b08565b82336131cd82611ea7565b6001600160a01b0316146131f4576040516349e27cff60e01b815260040160405180910390fd5b8282600082828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509394505050505b81518110156132af57600082828151811061324e5761324e61562a565b01602001516001600160f81b0319169050601160f91b81148061327e5750601760fa1b6001600160f81b03198216145b1561329c57604051630ec0325960e21b815260040160405180910390fd5b50806132a781615266565b915050613231565b50600086868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050825192935050506019101561330e5760405163251f56a160e21b815260040160405180910390fd5b6000888152601d602052604090819020905161332a91906156ae565b60405180910390208180519060200120141561335957604051632a9ffab760e21b815260040160405180910390fd5b6000888152601d602052604090206133729088886146d0565b50877f8edfa912e70e283a8ef6d6f52cd1faef9690ff989eff2f11a134e8478ba7b28b8888604051611bbd9291906156ba565b600454600881901c60009081526007602052604090208054600160ff1b60ff84161c17905561278b848484613401565b600881901c600090815260209290925260409091208054600160ff1b60ff9093169290921c9091179055565b600454826134215760405162461bcd60e51b815260040161101c90615a12565b6001600160a01b0384166134475760405162461bcd60e51b815260040161101c90615a45565b60005b838110156134d557600061345e82846156f5565b60405190915081906001600160a01b038816906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a46134a66000878387613f0c565b6134c25760405162461bcd60e51b815260040161101c90615a89565b50806134cd81615266565b91505061344a565b50600081815260036020908152604080832080546001600160a01b0319166001600160a01b038916179055600884901c83529082905290208054600160ff1b60ff84161c179055826004600082825461352e91906156f5565b9091555061278b9050600085838684565b3b151590565b60006001600160e01b03198216637965db0b60e01b1480610f5d5750610f5d8261401a565b600881901c6000908152600c6020526040812054600160ff1b60ff84161c161561359657506000919050565b610f5d826004541190565b600081815260056020526040902080546001600160a01b0319166001600160a01b03841690811790915581906135d682611ea7565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6122fa8133614085565b6000806008600454901c600161362f91906156f5565b905060005b81811015613674576000818152600c602052604090205461365481614105565b61365e90856156f5565b935050808061366c90615266565b915050613634565b505090565b60008160008151811061368e5761368e61562a565b60209081029190910181015160008581526008835260408082205480835281832083905560099094529020819055915061278b565b6136cd3382614124565b6136e95760405162461bcd60e51b815260040161101c906151bb565b6110c28383836141c5565b336000908152600e602052604090205460ff166137235760405162461bcd60e51b815260040161101c90615acd565b60008181526011602090815260408083203384529091529020541561375a5760405162461bcd60e51b815260040161101c90615b11565b6000818152600f60205260408120546137749060016156f5565b6000838152601060209081526040808320848452825280832080546001600160a01b03191633908117909155868452601183528184209084528252808320849055858352600f90915281208054929350906137ce83615266565b9091555050604051339083907f9ecfd70e9ff36df72989324a49559383d39f9290d700b10cf5ac10dcb68d264390600090a35050565b60008281526013602090815260408083206001600160a01b038516845290915290205460ff166111955760008281526013602090815260408083206001600160a01b03851684529091529020805460ff191660011790556138623390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60008281526013602090815260408083206001600160a01b038516845290915290205460ff16156111955760008281526013602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b336000908152600e602052604090205460ff166139585760405162461bcd60e51b815260040161101c90615acd565b60008181526011602090815260408083203384529091529020548061398f5760405162461bcd60e51b815260040161101c90615b55565b6000828152600f6020526040902054818114613a055760008381526010602090815260408083208484528252808320805486855282852080546001600160a01b03199081166001600160a01b03909316928317909155825416909155868452601183528184209084529091529020829055613a2d565b6000838152601060209081526040808320858452909152902080546001600160a01b03191690555b60008381526011602090815260408083203384528252808320839055858352600f9091528120805491613a5f83615b65565b9091555050604051339084907f0fe7d9801197f79ef3b1595d19379eb58f0fff5f98b0f6d6f34c03cae5306c3790600090a3505050565b600454600b546000828152600a602052604090205561278b8484846133a5565b600080613ac28361356a565b613ade5760405162461bcd60e51b815260040161101c9061515b565b613ae78361435a565b6000818152600360205260409020546001600160a01b031694909350915050565b600d80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b0381166000908152600e602052604090205460ff1615613b935760405162461bcd60e51b815260040161101c90615acd565b60008281526011602090815260408083206001600160a01b038516845290915290205480613bd35760405162461bcd60e51b815260040161101c90615bb0565b6000838152600f6020526040902054818114613c495760008481526010602090815260408083208484528252808320805486855282852080546001600160a01b03199081166001600160a01b03909316928317909155825416909155878452601183528184209084529091529020829055613c71565b6000848152601060209081526040808320858452909152902080546001600160a01b03191690555b60008481526011602090815260408083206001600160a01b03871684528252808320839055868352600f9091528120805491613cac83615b65565b90915550506040516001600160a01b0384169085907f0fe7d9801197f79ef3b1595d19379eb58f0fff5f98b0f6d6f34c03cae5306c3790600090a350505050565b6000613cf88261356a565b613d145760405162461bcd60e51b815260040161101c9061515b565b600a6000613d2184614366565b8152602001908152602001600020549050919050565b6040516305d3b1d360e41b81526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635d3b1d3090613e0f907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000907f000000000000000000000000000000000000000000000000000000000000000090600190600401615beb565b602060405180830381600087803b158015613e2957600080fd5b505af1158015613e3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e6191906152d1565b90507f76421cb080d40e8a03ba462b500012451ba59bdebc46694dc458807c1d754b6281604051613e929190614936565b60405180910390a1600b54600082815260086020526040902055600b8054906000613ebc83615266565b919050555050565b613ece3383614124565b613eea5760405162461bcd60e51b815260040161101c906151bb565b61278b84848484614373565b600082613f0385846143a6565b14949350505050565b60006001600160a01b0384163b1561400e57604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290613f50903390899088908890600401615c37565b602060405180830381600087803b158015613f6a57600080fd5b505af1925050508015613f9a575060408051601f3d908101601f19168201909252613f9791810190615c7c565b60015b613ff4573d808015613fc8576040519150601f19603f3d011682016040523d82523d6000602084013e613fcd565b606091505b508051613fec5760405162461bcd60e51b815260040161101c90615a89565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050614012565b5060015b949350505050565b60006001600160e01b031982166380ac58cd60e01b148061404b57506001600160e01b03198216635b5e139f60e01b145b8061406657506001600160e01b0319821663780e9d6360e01b145b80610f5d57506301ffc9a760e01b6001600160e01b0319831614610f5d565b60008281526013602090815260408083206001600160a01b038516845290915290205460ff16611195576140c3816001600160a01b03166014614412565b6140ce836020614412565b6040516020016140df929190615c9d565b60408051601f198184030181529082905262461bcd60e51b825261101c91600401614874565b60005b811561411f57600019820190911690600101614108565b919050565b600061412f8261356a565b61414b5760405162461bcd60e51b815260040161101c90615d1e565b600061415683611ea7565b9050806001600160a01b0316846001600160a01b031614806141915750836001600160a01b031661418684610ff5565b6001600160a01b0316145b8061401257506001600160a01b0380821660009081526006602090815260408083209388168352929052205460ff16614012565b6000806141d183613ab6565b91509150846001600160a01b0316826001600160a01b0316146142065760405162461bcd60e51b815260040161101c90615d4b565b6001600160a01b03841661422c5760405162461bcd60e51b815260040161101c90615d7d565b6142376000846135a1565b60006142448460016156f5565b600881901c600090815260208190526040902054909150600160ff1b60ff83161c16158015614274575060045481105b156142c057600081815260036020908152604080832080546001600160a01b0319166001600160a01b038b16179055600884901c83529082905290208054600160ff1b60ff84161c1790555b600084815260036020526040902080546001600160a01b0319166001600160a01b03871617905581841461431157600884901c60009081526020819052604090208054600160ff1b60ff87161c1790555b83856001600160a01b0316876001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050505050565b6000610f5d818361458b565b6000610f5d60078361458b565b61437e8484846141c5565b61438a84848484613f0c565b61278b5760405162461bcd60e51b815260040161101c90615a89565b600081815b8451811015611c685760008582815181106143c8576143c861562a565b602002602001015190508083116143ee57600083815260208290526040902092506143ff565b600081815260208490526040902092505b508061440a81615266565b9150506143ab565b60606000614421836002615812565b61442c9060026156f5565b67ffffffffffffffff811115614444576144446149b6565b6040519080825280601f01601f19166020018201604052801561446e576020820181803683370190505b509050600360fc1b816000815181106144895761448961562a565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106144b8576144b861562a565b60200101906001600160f81b031916908160001a90535060006144dc846002615812565b6144e79060016156f5565b90505b600181111561456c577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106145285761452861562a565b1a60f81b82828151811061453e5761453e61562a565b60200101906001600160f81b031916908160001a90535060049490941c9361456581615b65565b90506144ea565b508315612b305760405162461bcd60e51b815260040161101c90615dbf565b600881901c60008181526020849052604081205490919060ff8085169190821890811c80156145d3576145bd8161464e565b60ff168303600885901b17945050505050610f5d565b600084116145f35760405162461bcd60e51b815260040161101c9061515b565b6000199093019260ff9250600091505b506000838152602087905260409020548015614622576145bd8161464e565b600084116146425760405162461bcd60e51b815260040161101c90615ded565b60001990930192614603565b60006040518061012001604052806101008152602001615e1e610100913960f87e818283848586878898a8b8c8d8e8f929395969799a9b9d9e9faaeb6bedeeff614697856146b8565b02901c815181106146aa576146aa61562a565b016020015160f81c92915050565b60008082116146c657600080fd5b5060008190031690565b8280546146dc9061510d565b90600052602060002090601f0160209004810192826146fe5760008555614744565b82601f106147175782800160ff19823516178555614744565b82800160010185558215614744579182015b82811115614744578235825591602001919060010190614729565b50614750929150614754565b5090565b5b808211156147505760008155600101614755565b6001600160e01b031981165b81146122fa57600080fd5b8035610f5d81614769565b6000602082840312156147a0576147a0600080fd5b60006140128484614780565b8015155b82525050565b60208101610f5d82846147ac565b6000610f5d6001600160a01b0383166147db565b90565b6001600160a01b031690565b6000610f5d826147c4565b6000610f5d826147e7565b6147b0816147f2565b60208101610f5d82846147fd565b60005b8381101561482f578181015183820152602001614817565b8381111561278b5750506000910152565b600061484a825190565b808452602084019350614861818560208601614814565b601f19601f8201165b9093019392505050565b60208082528101612b308184614840565b80614775565b8035610f5d81614885565b6000602082840312156148ab576148ab600080fd5b6000614012848461488b565b60006001600160a01b038216610f5d565b6147b0816148b7565b60208101610f5d82846148c8565b614775816148b7565b8035610f5d816148df565b6000806040838503121561490957614909600080fd5b6000614915858561488b565b9250506020614926858286016148e8565b9150509250929050565b806147b0565b60208101610f5d8284614930565b6000806040838503121561495a5761495a600080fd5b600061496685856148e8565b92505060206149268582860161488b565b67ffffffffffffffff81166147b0565b60208101610f5d8284614977565b6000602082840312156149aa576149aa600080fd5b600061401284846148e8565b634e487b7160e01b600052604160045260246000fd5b601f19601f830116810181811067ffffffffffffffff821117156149f2576149f26149b6565b6040525050565b6000614a0460405190565b905061411f82826149cc565b600067ffffffffffffffff821115614a2a57614a2a6149b6565b5060209081020190565b6000614a47614a4284614a10565b6149f9565b83815290506020808201908402830185811115614a6657614a66600080fd5b835b81811015614a8a5780614a7b888261488b565b84525060209283019201614a68565b5050509392505050565b600082601f830112614aa857614aa8600080fd5b8135614012848260208601614a34565b60008060408385031215614ace57614ace600080fd5b6000614ada858561488b565b925050602083013567ffffffffffffffff811115614afa57614afa600080fd5b61492685828601614a94565b600080600060608486031215614b1e57614b1e600080fd5b6000614b2a86866148e8565b9350506020614b3b868287016148e8565b9250506040614b4c8682870161488b565b9150509250925092565b60008060408385031215614b6c57614b6c600080fd5b6000614966858561488b565b60008083601f840112614b8d57614b8d600080fd5b50813567ffffffffffffffff811115614ba857614ba8600080fd5b602083019150836001820283011115614bc357614bc3600080fd5b9250929050565b60008060008060608587031215614be357614be3600080fd5b6000614bef878761488b565b945050602085013567ffffffffffffffff811115614c0f57614c0f600080fd5b614c1b87828801614b78565b93509350506040614c2e8782880161488b565b91505092959194509250565b600080600060408486031215614c5257614c52600080fd5b6000614c5e868661488b565b935050602084013567ffffffffffffffff811115614c7e57614c7e600080fd5b614c8a86828701614b78565b92509250509250925092565b6000614ca28383614930565b505060200190565b6000614cb4825190565b80845260209384019383018060005b83811015614ce8578151614cd78882614c96565b975060208301925050600101614cc3565b509495945050505050565b60208082528101612b308184614caa565b801515614775565b8035610f5d81614d04565b600060208284031215614d2c57614d2c600080fd5b60006140128484614d0c565b60008083601f840112614d4d57614d4d600080fd5b50813567ffffffffffffffff811115614d6857614d68600080fd5b602083019150836020820283011115614bc357614bc3600080fd5b60008060208385031215614d9957614d99600080fd5b823567ffffffffffffffff811115614db357614db3600080fd5b614dbf85828601614d38565b92509250509250929050565b60008060408385031215614de157614de1600080fd5b6000614ded85856148e8565b925050602061492685828601614d0c565b805161018080845260009190840190614e178282614840565b91505060208301518482036020860152614e318282614840565b9150506040830151614e466040860182614930565b506060830151614e596060860182614930565b506080830151614e6c6080860182614930565b5060a0830151614e7f60a0860182614930565b5060c0830151614e9260c0860182614930565b5060e0830151614ea560e0860182614930565b50610100830151614eba610100860182614930565b50610120830151614ecf610120860182614930565b50610140830151614ee46101408601826147ac565b50610160830151611c68610160860182614930565b60208082528101612b308184614dfe565b60008060008060408587031215614f2357614f23600080fd5b843567ffffffffffffffff811115614f3d57614f3d600080fd5b614f4987828801614d38565b9450945050602085013567ffffffffffffffff811115614f6b57614f6b600080fd5b614f7787828801614d38565b95989497509550505050565b600067ffffffffffffffff821115614f9d57614f9d6149b6565b601f19601f83011660200192915050565b82818337506000910152565b6000614fc8614a4284614f83565b905082815260208101848484011115614fe357614fe3600080fd5b611c68848285614fae565b600082601f83011261500257615002600080fd5b8135614012848260208601614fba565b6000806000806080858703121561502b5761502b600080fd5b600061503787876148e8565b9450506020615048878288016148e8565b93505060406150598782880161488b565b925050606085013567ffffffffffffffff81111561507957615079600080fd5b614c2e87828801614fee565b60008060006040848603121561509d5761509d600080fd5b60006150a9868661488b565b935050602084013567ffffffffffffffff8111156150c9576150c9600080fd5b614c8a86828701614d38565b600080604083850312156150eb576150eb600080fd5b600061491585856148e8565b634e487b7160e01b600052602260045260246000fd5b60028104600182168061512157607f821691505b60208210811415615134576151346150f7565b50919050565b60078152600060208201662165786973747360c81b815291505b5060200190565b60208082528101610f5d8161513a565b600981526000602082016808585c1c1c9bdd985b60ba1b81529150615154565b60208082528101610f5d8161516b565b600981526000602082016808585c1c1c9bdd995960ba1b81529150615154565b60208082528101610f5d8161519b565b634e487b7160e01b600052601160045260246000fd5b6000828210156151f3576151f36151cb565b500390565b6040810161520682856148c8565b612b3060208301846148c8565b60048152600060208201633133333760e01b81529150615154565b60208082528101610f5d81615213565b60018152600060208201600360fc1b81529150615154565b60208082528101610f5d8161523e565b600060001982141561527a5761527a6151cb565b5060010190565b600381526000602082016237b7b160e91b81529150615154565b60208082528101610f5d81615281565b604081016152b982856148c8565b612b306020830184614930565b8051610f5d81614885565b6000602082840312156152e6576152e6600080fd5b600061401284846152c6565b6000615300614a4284614f83565b90508281526020810184848401111561531b5761531b600080fd5b611c68848285614814565b600082601f83011261533a5761533a600080fd5b81516140128482602086016152f2565b60006020828403121561535f5761535f600080fd5b815167ffffffffffffffff81111561537957615379600080fd5b61401284828501615326565b600061538f825190565b61539d818560208601614814565b9290920192915050565b6000612b308284615385565b601f81526000602082017f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0081529150615154565b60208082528101610f5d816153b3565b6000615404838584614fae565b50500190565b60006140128284866153f7565b652ba2a0a827a760d11b8152600060068201610f5d565b60028152600060208201611c9b60f11b81529150615154565b60208082528101610f5d8161542e565b631211505160e21b815260005b5060040190565b6000610f5d82615457565b6420a926a7a960d91b8152600060058201610f5d565b69109050d2d1d493d5539160b21b815260005b50600a0190565b6000610f5d8261548c565b692320a1a2afa0a926a7a960b11b8152600061549f565b6000610f5d826154b1565b6622aca2aba2a0a960c91b8152600060078201610f5d565b634d49534360e01b81526000615464565b6000610f5d826154eb565b6000610f5d6147d88381565b6147b081615507565b6060810161552a8286614930565b6155376020830185615513565b61401260408301846148c8565b818352600060208401935061555a838584614fae565b601f19601f84011661486a565b60408082528101615579818587615544565b90506140126020830184614930565b602f81526000602082017f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636581527f20726f6c657320666f722073656c660000000000000000000000000000000000602082015291505b5060400190565b60208082528101610f5d81615588565b6000610f5d826147d8565b600381526000602082016239393960e81b81529150615154565b60208082528101610f5d81615600565b634e487b7160e01b600052603260045260246000fd5b6000815461564d8161510d565b6001821680156156645760018114615675576156a5565b60ff198316865281860193506156a5565b60008581526020902060005b8381101561569d57815488820152600190910190602001615681565b838801955050505b50505092915050565b6000612b308284615640565b60208082528101614012818486615544565b6002815260006020820161363960f01b81529150615154565b60208082528101610f5d816156cc565b60008219821115615708576157086151cb565b500190565b6060810161571b82866148c8565b61572860208301856148c8565b6140126040830184614930565b600c81526000602082016b7a65726f206164647265737360a01b81529150615154565b60208082528101610f5d81615735565b60208082527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657291019081526000615154565b60208082528101610f5d81615768565b600b81526000602082016a08599d5b1b199a5b1b195960aa1b81529150615154565b60208082528101610f5d816157aa565b604081016152b98285614930565b60018152600060208201603960f81b81529150615154565b60208082528101610f5d816157ea565b600081600019048311821515161561582c5761582c6151cb565b500290565b60018152600060208201603160f81b81529150615154565b60208082528101610f5d81615831565b60018152600060208201601960f91b81529150615154565b60208082528101610f5d81615859565b600881526000602082016721617070726f766560c01b81529150615154565b60208082528101610f5d81615881565b6007815260006020820166042d8cadccee8d60cb1b81529150615154565b60208082528101610f5d816158b0565b606081016158ec8286614930565b6158f96020830185614930565b818103604083015261590b8184614dfe565b95945050505050565b6000610f5d8260601b90565b6000610f5d82615914565b6147b0615937826148b7565b615920565b6000615948828461592b565b50601401919050565b60018152600060208201600d60fa1b81529150615154565b60208082528101610f5d81615951565b60048152600060208201633639363960e01b81529150615154565b60208082528101610f5d81615979565b602681526000602082017f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015291506155de565b60208082528101610f5d816159a4565b60048152600060208201637a65726f60e01b81529150615154565b60208082528101610f5d816159f7565b600c81526000602082016b217a65726f6164647265737360a01b81529150615154565b60208082528101610f5d81615a22565b600f81526000602082017f214552433732315265636569766572000000000000000000000000000000000081529150615154565b60208082528101610f5d81615a55565b601181526000602082017f43616e6e6f7420757064617465206d617000000000000000000000000000000081529150615154565b60208082528101610f5d81615a99565b601b81526000602082017f494420616c7265616479206c6f636b65642062792063616c6c6572000000000081529150615154565b60208082528101610f5d81615add565b601781526000602082017f4944206e6f74206c6f636b65642062792063616c6c657200000000000000000081529150615154565b60208082528101610f5d81615b21565b600081615b7457615b746151cb565b506000190190565b600d81526000602082017f4944206e6f74206c6f636b65640000000000000000000000000000000000000081529150615154565b60208082528101610f5d81615b7c565b61ffff81166147b0565b63ffffffff81166147b0565b600061ffff8216610f5d565b6147b081615bd6565b60a08101615bf98288614930565b615c066020830187614977565b615c136040830186615bc0565b615c206060830185615bca565b615c2d6080830184615be2565b9695505050505050565b60808101615c4582876148c8565b615c5260208301866148c8565b615c5f6040830185614930565b8181036060830152615c2d8184614840565b8051610f5d81614769565b600060208284031215615c9157615c91600080fd5b60006140128484615c71565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526017016000615ccf8285615385565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000815260110191506140128284615385565b600681526000602082016508595e1a5cdd60d21b81529150615154565b60208082528101610f5d81615d01565b60068152600060208201653737ba37bbb760d11b81529150615154565b60208082528101610f5d81615d2e565b600b81526000602082016a7a65726f6164647265737360a81b81529150615154565b60208082528101610f5d81615d5b565b60208082527f537472696e67733a20686578206c656e67746820696e73756666696369656e7491019081526000615154565b60208082528101610f5d81615d8d565b60078152600060208201662165786973745360c81b81529150615154565b60208082528101610f5d81615dcf56feb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e0001020903110a19042112290b311a3905412245134d2a550c5d32651b6d3a7506264262237d468514804e8d2b95569d0d495ea533a966b11c886eb93bc176c9071727374353637324837e9b47af86c7155181ad4fd18ed32c9096db57d59ee30e2e4a6a5f92a6be3498aae067ddb2eb1d5989b56fd7baf33ca0c2ee77e5caf7ff0810182028303840444c545c646c7425617c847f8c949c48a4a8b087b8c0c816365272829aaec650acd0d28fdad4e22d6991bd97dfdcea58b4d6f29fede4f6fe0f1f2f3f4b5b6b607b8b93a3a7b7bf357199c5abcfd9e168bcdee9b3f1ecf5fd1e3e5a7a8aa2b670c4ced8bbe8f0f4fc3d79a1c3cde7effb78cce6facbf9f8a26469706673582212200a69d5a5a7edc680d1e1a299af104003cfb32e049d1009510bb21d5ab5ecdf6864736f6c63430008090033000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e699098af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef00000000000000000000000000000000000000000000000000000000000001850000000000000000000000000e223db582e3fc2c47ba39f67a1e55b7a75f09fd0000000000000000000000005e2454f33c3da3aa30eabc502255f66a6d72adc8000000000000000000000000e9b41d92c64b4b088a6ddf55057f60195b90e09f000000000000000000000000bd24a76f4135f930f5c49f6c30e0e30a61b97537

Deployed Bytecode

0x60806040526004361061048e5760003560e01c80636f8b44b011610265578063a574cea411610154578063d2cab056116100d1578063e268e4d311610095578063f0f442601161006f578063f0f4426014610ef2578063f2fde38b14610f12578063fe55932a14610f3257600080fd5b8063e268e4d314610e69578063e985e9c514610e89578063ea07e68a14610ed257600080fd5b8063d2cab05614610de0578063d50efd7014610df3578063d547741f14610e13578063d5abeb0114610e33578063d6257bb814610e4957600080fd5b8063b7b2040411610118578063b7b2040414610d4a578063b88d4fde14610d60578063c87b56dd14610d80578063ca2eb5ae14610da0578063cbcc418814610dc057600080fd5b8063a574cea414610c97578063a9cdd60d14610cc4578063ac52e64414610ce4578063b1a6505f14610d04578063b4bc159a14610d3457600080fd5b806394d216d6116101e2578063a035b1fe116101a6578063a035b1fe14610c24578063a0712d6814610c3a578063a217fddf14610c4d578063a22cb46514610c62578063a475b5dd14610c8257600080fd5b806394d216d614610b825780639556483714610ba257806395d89b4114610bc25780639a9e2e4a14610bd75780639ec00c9514610bf757600080fd5b80638984cbb0116102295780638984cbb014610abe5780638ada6b0f14610ade5780638da5cb5b14610afe57806391b7f5ed14610b1c57806391d1485414610b3c57600080fd5b80636f8b44b014610a1b57806370a0823114610a3b578063715018a614610a5b57806372abc8b714610a705780637cb6475914610a9e57600080fd5b80633ccfd60b116103815780634f6ccce7116102fe57806361728f39116102c257806361728f391461095a57806361d027b31461098e5780636352211e146109ae578063650b00f6146109ce5780636ba4c138146109fb57600080fd5b80634f6ccce7146108ce5780635146ea0e146108ee57806353f8bb9a1461090e57806354214f69146109245780635e5f3ce41461094357600080fd5b8063453c231011610345578063453c23101461084257806349a5980a146108585780634aa0acc0146108785780634e6fd6c4146108985780634f09cd52146108ae57600080fd5b80633ccfd60b146107a05780633ef628a3146107b557806340a9c8df146107d557806342842e0e146107f5578063438b63001461081557600080fd5b806323b872dd1161040f5780632f2ff15d116103d35780632f2ff15d146107095780632f745c59146107295780633281fa3f14610749578063334d6e8b1461076057806336568abe1461078057600080fd5b806323b872dd14610642578063248a9ca3146106625780632799cde0146106925780632cba8123146106b25780632eb4a7ab146106f357600080fd5b8063095ea7b311610456578063095ea7b31461058a57806309c1ba2e146105ac57806312b40a9f146105ed57806318160ddd1461060d5780631fe543e31461062257600080fd5b806301ffc9a71461049357806306a9a164146104c957806306fdde03146104f6578063081812fc1461051857806309308e5d14610545575b600080fd5b34801561049f57600080fd5b506104b36104ae36600461478b565b610f52565b6040516104c091906147b6565b60405180910390f35b3480156104d557600080fd5b506020546104e9906001600160a01b031681565b6040516104c09190614806565b34801561050257600080fd5b5061050b610f63565b6040516104c09190614874565b34801561052457600080fd5b50610538610533366004614896565b610ff5565b6040516104c091906148d1565b34801561055157600080fd5b5061057d6105603660046148f3565b601160209081526000928352604080842090915290825290205481565b6040516104c09190614936565b34801561059657600080fd5b506105aa6105a5366004614944565b611041565b005b3480156105b857600080fd5b506105e07f000000000000000000000000000000000000000000000000000000000000018581565b6040516104c09190614987565b3480156105f957600080fd5b506105aa610608366004614995565b6110c7565b34801561061957600080fd5b5061057d611102565b34801561062e57600080fd5b506105aa61063d366004614ab8565b61111e565b34801561064e57600080fd5b506105aa61065d366004614b06565b611199565b34801561066e57600080fd5b5061057d61067d366004614896565b60009081526013602052604090206001015490565b34801561069e57600080fd5b506105aa6106ad366004614896565b6111d0565b3480156106be57600080fd5b506105386106cd366004614b56565b60106020908152600092835260408084209091529082529020546001600160a01b031681565b3480156106ff57600080fd5b5061057d601c5481565b34801561071557600080fd5b506105aa6107243660046148f3565b611228565b34801561073557600080fd5b5061057d610744366004614944565b61124d565b34801561075557600080fd5b5060165442116104b3565b34801561076c57600080fd5b506105aa61077b366004614bca565b6112da565b34801561078c57600080fd5b506105aa61079b3660046148f3565b61192b565b3480156107ac57600080fd5b506105aa61195d565b3480156107c157600080fd5b506105aa6107d0366004614c3a565b6119f6565b3480156107e157600080fd5b506105aa6107f0366004614896565b611bcf565b34801561080157600080fd5b506105aa610810366004614b06565b611c27565b34801561082157600080fd5b50610835610830366004614995565b611c42565b6040516104c09190614cf3565b34801561084e57600080fd5b5061057d601a5481565b34801561086457600080fd5b506105aa610873366004614d17565b611cfb565b34801561088457600080fd5b506105aa610893366004614b56565b611d2e565b3480156108a457600080fd5b5061053861dead81565b3480156108ba57600080fd5b506105aa6108c9366004614995565b611d83565b3480156108da57600080fd5b5061057d6108e9366004614896565b611de2565b3480156108fa57600080fd5b506105aa610909366004614b56565b611e5c565b34801561091a57600080fd5b5061057d60175481565b34801561093057600080fd5b50601b546104b390610100900460ff1681565b34801561094f57600080fd5b5060175442116104b3565b34801561096657600080fd5b5061057d7f8af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef81565b34801561099a57600080fd5b50601554610538906001600160a01b031681565b3480156109ba57600080fd5b506105386109c9366004614896565b611ea7565b3480156109da57600080fd5b5061057d6109e9366004614896565b600f6020526000908152604090205481565b348015610a0757600080fd5b506105aa610a16366004614d83565b611ebe565b348015610a2757600080fd5b506105aa610a36366004614896565b611fc7565b348015610a4757600080fd5b5061057d610a56366004614995565b611fe5565b348015610a6757600080fd5b506105aa61206e565b348015610a7c57600080fd5b506104b3610a8b366004614896565b6000908152600f60205260409020541590565b348015610aaa57600080fd5b506105aa610ab9366004614896565b6120a4565b348015610aca57600080fd5b506105aa610ad9366004614896565b6120c2565b348015610aea57600080fd5b506021546104e9906001600160a01b031681565b348015610b0a57600080fd5b50600d546001600160a01b0316610538565b348015610b2857600080fd5b506105aa610b37366004614896565b6120e0565b348015610b4857600080fd5b506104b3610b573660046148f3565b60009182526013602090815260408084206001600160a01b0393909316845291905290205460ff1690565b348015610b8e57600080fd5b506105aa610b9d3660046148f3565b6120fe565b348015610bae57600080fd5b5061057d610bbd366004614896565b612157565b348015610bce57600080fd5b5061050b6121f1565b348015610be357600080fd5b506022546104e9906001600160a01b031681565b348015610c0357600080fd5b5061057d610c12366004614995565b601e6020526000908152604090205481565b348015610c3057600080fd5b5061057d60195481565b6105aa610c48366004614896565b612200565b348015610c5957600080fd5b5061057d600081565b348015610c6e57600080fd5b506105aa610c7d366004614dcb565b6122fd565b348015610c8e57600080fd5b506105aa612395565b348015610ca357600080fd5b50610cb7610cb2366004614896565b6123f6565b6040516104c09190614ef9565b348015610cd057600080fd5b506105aa610cdf366004614995565b612631565b348015610cf057600080fd5b506105aa610cff366004614f0a565b61266c565b348015610d1057600080fd5b506104b3610d1f366004614995565b600e6020526000908152604090205460ff1681565b348015610d4057600080fd5b5061057d60145481565b348015610d5657600080fd5b5061057d60165481565b348015610d6c57600080fd5b506105aa610d7b366004615012565b612753565b348015610d8c57600080fd5b5061050b610d9b366004614896565b612791565b348015610dac57600080fd5b5061057d610dbb366004614995565b612b37565b348015610dcc57600080fd5b506105aa610ddb366004614d17565b612b69565b6105aa610dee366004615085565b612b95565b348015610dff57600080fd5b506105aa610e0e366004614c3a565b612db8565b348015610e1f57600080fd5b506105aa610e2e3660046148f3565b6130cd565b348015610e3f57600080fd5b5061057d60185481565b348015610e5557600080fd5b506105aa610e64366004614896565b6130f2565b348015610e7557600080fd5b506105aa610e84366004614896565b613110565b348015610e9557600080fd5b506104b3610ea43660046150d5565b6001600160a01b03918216600090815260066020908152604080832093909416825291909152205460ff1690565b348015610ede57600080fd5b50601f546104e9906001600160a01b031681565b348015610efe57600080fd5b506105aa610f0d366004614995565b61312e565b348015610f1e57600080fd5b506105aa610f2d366004614995565b613169565b348015610f3e57600080fd5b506105aa610f4d366004614c3a565b6131c2565b6000610f5d82613545565b92915050565b606060018054610f729061510d565b80601f0160208091040260200160405190810160405280929190818152602001828054610f9e9061510d565b8015610feb5780601f10610fc057610100808354040283529160200191610feb565b820191906000526020600020905b815481529060010190602001808311610fce57829003601f168201915b5050505050905090565b60006110008261356a565b6110255760405162461bcd60e51b815260040161101c9061515b565b60405180910390fd5b506000908152600560205260409020546001600160a01b031690565b600061104c82611ea7565b9050806001600160a01b0316836001600160a01b031614156110805760405162461bcd60e51b815260040161101c9061518b565b336001600160a01b038216148061109c575061109c8133610ea4565b6110b85760405162461bcd60e51b815260040161101c906151bb565b6110c283836135a1565b505050565b600080516020615dfe8339815191526110df8161360f565b50602180546001600160a01b0319166001600160a01b0392909216919091179055565b600061110c613619565b60045461111991906151e1565b905090565b336001600160a01b037f000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e69909161461118b57337f000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e6990960405163073e64fd60e21b815260040161101c9291906151f8565b6111958282613679565b5050565b6000818152600f6020526040902054156111c55760405162461bcd60e51b815260040161101c9061522e565b6110c28383836136c3565b7ff11b02a75234472a5060a94045900fd33989cb6e8ec8dd50e38ed9a49356cba46111fa8161360f565b6112038261356a565b61121f5760405162461bcd60e51b815260040161101c90615256565b611195826136f4565b6000828152601360205260409020600101546112438161360f565b6110c28383613804565b60008060005b6004548110156112c1576112668161356a565b801561128b575061127681611ea7565b6001600160a01b0316856001600160a01b0316145b156112af57838214156112a1579150610f5d9050565b816112ab81615266565b9250505b806112b981615266565b915050611253565b5060405162461bcd60e51b815260040161101c9061529b565b83336112e582611ea7565b6001600160a01b03161461130c576040516349e27cff60e01b815260040160405180910390fd5b601f54604051627eeac760e11b815283916001600160a01b03169062fdd58e9061133c90339085906004016152ab565b60206040518083038186803b15801561135457600080fd5b505afa158015611368573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138c91906152d1565b6113a9576040516349e27cff60e01b815260040160405180910390fd5b8285858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050601f5460405163c19a4ef560e01b81526001600160a01b03909116925063c19a4ef59150611410908590600401614936565b60006040518083038186803b15801561142857600080fd5b505afa15801561143c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611464919081019061534a565b60405160200161147491906153a7565b604051602081830303815290604052805190602001208160405160200161149b91906153a7565b60405160208183030381529060405280519060200120146114cf57604051631e4cbc7f60e21b815260040160405180910390fd5b601f5460405163adc0f74560e01b815286918a916001600160a01b039091169063adc0f74590611503908590600401614936565b60206040518083038186803b15801561151b57600080fd5b505afa15801561152f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061155391906152d1565b6000828152601d6020526040902060090154101561158457604051636e7e5ecf60e01b815260040160405180910390fd5b600260125414156115a75760405162461bcd60e51b815260040161101c906153e7565b60026012556040516000906115c2908b908b9060200161540a565b60408051601f19818403018152828252805160209182012060008f8152601d835292909220919350909183916115f89101615417565b604051602081830303815290604052805190602001201415611642576004810154156116365760405162461bcd60e51b815260040161101c90615447565b60048101899055611877565b816040516020016116529061546b565b60405160208183030381529060405280519060200120141561169c576003810154156116905760405162461bcd60e51b815260040161101c90615447565b60038101899055611877565b816040516020016116ac90615476565b6040516020818303038152906040528051906020012014156116f6576005810154156116ea5760405162461bcd60e51b815260040161101c90615447565b60058101899055611877565b81604051602001611706906154a6565b604051602081830303815290604052805190602001201415611750576002810154156117445760405162461bcd60e51b815260040161101c90615447565b60028101899055611877565b81604051602001611760906154c8565b6040516020818303038152906040528051906020012014156117aa5760068101541561179e5760405162461bcd60e51b815260040161101c90615447565b60068101899055611877565b816040516020016117ba906154d3565b604051602081830303815290604052805190602001201415611804576007810154156117f85760405162461bcd60e51b815260040161101c90615447565b60078101899055611877565b81604051602001611814906154fc565b60405160208183030381529060405280519060200120141561185e576008810154156118525760405162461bcd60e51b815260040161101c90615447565b60088101899055611877565b604051631e4cbc7f60e21b815260040160405180910390fd5b601f546001600160a01b0316639eef4aa68a6001336040518463ffffffff1660e01b81526004016118aa9392919061551c565b600060405180830381600087803b1580156118c457600080fd5b505af11580156118d8573d6000803e3d6000fd5b505050508b7f913887fd0b468ebff22eac13535c8b5a656d89040bff7d16d7d4531bf27030d68c8c8c60405161191093929190615567565b60405180910390a25050600160125550505050505050505050565b6001600160a01b03811633146119535760405162461bcd60e51b815260040161101c906155e5565b61119582826138a6565b600080516020615dfe8339815191526119758161360f565b6015546040516000916001600160a01b0316904790611993906155f5565b60006040518083038185875af1925050503d80600081146119d0576040519150601f19603f3d011682016040523d82523d6000602084013e6119d5565b606091505b50509050806111955760405162461bcd60e51b815260040161101c9061561a565b8233611a0182611ea7565b6001600160a01b031614611a28576040516349e27cff60e01b815260040160405180910390fd5b8282600082828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509394505050505b8151811015611ae3576000828281518110611a8257611a8261562a565b01602001516001600160f81b0319169050601160f91b811480611ab25750601760fa1b6001600160f81b03198216145b15611ad057604051630ec0325960e21b815260040160405180910390fd5b5080611adb81615266565b915050611a65565b50600086868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052508c8152601d6020526040908190209051949550611b3f946001909101935091506156ae9050565b604051809103902081805190602001201415611b6e57604051632a9ffab760e21b815260040160405180910390fd5b6000888152601d60205260409020611b8a9060010188886146d0565b50877f1d83c2282d074aad212f8c5d02271066bf42c603a85c4c9e4f07d1eb8c1998218888604051611bbd9291906156ba565b60405180910390a25050505050505050565b7ff11b02a75234472a5060a94045900fd33989cb6e8ec8dd50e38ed9a49356cba4611bf98161360f565b611c028261356a565b611c1e5760405162461bcd60e51b815260040161101c90615256565b61119582613929565b6110c283838360405180602001604052806000815250612753565b60606000611c4f83611fe5565b905080611c705760408051600080825260208201909252905b509392505050565b60008167ffffffffffffffff811115611c8b57611c8b6149b6565b604051908082528060200260200182016040528015611cb4578160200160208202803683370190505b50905060005b82811015611c6857611ccc858261124d565b828281518110611cde57611cde61562a565b602090810291909101015280611cf381615266565b915050611cba565b600080516020615dfe833981519152611d138161360f565b50601b80549115156101000261ff0019909216919091179055565b7ff11b02a75234472a5060a94045900fd33989cb6e8ec8dd50e38ed9a49356cba4611d588161360f565b6000838152601d602052604081206009018054849290611d799084906151e1565b9091555050505050565b600080516020615dfe833981519152611d9b8161360f565b600060145411611dbd5760405162461bcd60e51b815260040161101c906156e5565b611dd98260145460405180602001604052806000815250613a96565b50506000601455565b6000611dec611102565b8210611e0a5760405162461bcd60e51b815260040161101c9061529b565b6000805b600454811015611e5557611e218161356a565b15611e435783821415611e35579392505050565b81611e3f81615266565b9250505b80611e4d81615266565b915050611e0e565b5050919050565b7ff11b02a75234472a5060a94045900fd33989cb6e8ec8dd50e38ed9a49356cba4611e868161360f565b6000838152601d602052604081206009018054849290611d799084906156f5565b6000806000611eb584613ab6565b50949350505050565b60026012541415611ee15760405162461bcd60e51b815260040161101c906153e7565b60026012556017544211611f075760405162461bcd60e51b815260040161101c90615256565b60005b81811015611fa3576020546001600160a01b03166323b872dd3361dead868686818110611f3957611f3961562a565b905060200201356040518463ffffffff1660e01b8152600401611f5e9392919061570d565b600060405180830381600087803b158015611f7857600080fd5b505af1158015611f8c573d6000803e3d6000fd5b505050508080611f9b90615266565b915050611f0a565b50611fbe336040805160208101909152600081528390613a96565b50506001601255565b600080516020615dfe833981519152611fdf8161360f565b50601855565b60006001600160a01b03821661200d5760405162461bcd60e51b815260040161101c90615758565b6000805b600454811015612067576120248161356a565b156120575761203281611ea7565b6001600160a01b0316846001600160a01b031614156120575761205482615266565b91505b61206081615266565b9050612011565b5092915050565b600d546001600160a01b031633146120985760405162461bcd60e51b815260040161101c9061579a565b6120a26000613b08565b565b600080516020615dfe8339815191526120bc8161360f565b50601c55565b600080516020615dfe8339815191526120da8161360f565b50601755565b600080516020615dfe8339815191526120f88161360f565b50601955565b7ff11b02a75234472a5060a94045900fd33989cb6e8ec8dd50e38ed9a49356cba46121288161360f565b6121318361356a565b61214d5760405162461bcd60e51b815260040161101c90615256565b6110c28383613b5a565b60006121628261356a565b61217e5760405162461bcd60e51b815260040161101c9061515b565b60006009600061218d85613ced565b815260200190815260200160002054905080600014156121bf5760405162461bcd60e51b815260040161101c906157cc565b80836040516020016121d29291906157dc565b60408051601f1981840301815291905280516020909101209392505050565b606060028054610f729061510d565b60175442116122215760405162461bcd60e51b815260040161101c90615256565b6018548161222d611102565b61223791906156f5565b106122545760405162461bcd60e51b815260040161101c90615802565b6019546122619082615812565b3410156122805760405162461bcd60e51b815260040161101c90615849565b601a54336000908152601e602052604090205461229e9083906156f5565b106122bb5760405162461bcd60e51b815260040161101c90615871565b336000908152601e6020526040812080548392906122da9084906156f5565b909155506122fa9050338260405180602001604052806000815250613a96565b50565b6001600160a01b0382163314156123265760405162461bcd60e51b815260040161101c906158a0565b3360008181526006602090815260408083206001600160a01b038716808552925291829020805460ff191685151517905590519091907f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31906123899085906147b6565b60405180910390a35050565b600080516020615dfe8339815191526123ad8161360f565b6123b5613d37565b7f15120e52505e619cbf6c2af910d5cf7f9ee1befa55801b078c33e93880b2d6096123de611102565b6040516123eb9190614936565b60405180910390a150565b61245c60405180610180016040528060608152602001606081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600015158152602001600081525090565b6124658261356a565b6124815760405162461bcd60e51b815260040161101c90615256565b6000828152601d602052604090819020815161018081019092528054829082906124aa9061510d565b80601f01602080910402602001604051908101604052809291908181526020018280546124d69061510d565b80156125235780601f106124f857610100808354040283529160200191612523565b820191906000526020600020905b81548152906001019060200180831161250657829003601f168201915b5050505050815260200160018201805461253c9061510d565b80601f01602080910402602001604051908101604052809291908181526020018280546125689061510d565b80156125b55780601f1061258a576101008083540402835291602001916125b5565b820191906000526020600020905b81548152906001019060200180831161259857829003601f168201915b505050918352505060028201546020820152600382015460408201526004820154606082015260058201546080820152600682015460a0820152600782015460c0820152600882015460e08201526009820154610100820152600a82015460ff161515610120820152600b909101546101409091015292915050565b600080516020615dfe8339815191526126498161360f565b50601f80546001600160a01b0319166001600160a01b0392909216919091179055565b600d546001600160a01b031633146126965760405162461bcd60e51b815260040161101c9061579a565b8281146126b55760405162461bcd60e51b815260040161101c906158ce565b60005b8381101561274c578282828181106126d2576126d261562a565b90506020020160208101906126e79190614d17565b600e60008787858181106126fd576126fd61562a565b90506020020160208101906127129190614995565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790558061274481615266565b9150506126b8565b5050505050565b6000828152600f60205260409020541561277f5760405162461bcd60e51b815260040161101c9061522e565b61278b84848484613ec4565b50505050565b601b54606090610100900460ff1661282757602154604051632914130560e01b81526001600160a01b03909116906329141305906127d3908590600401614936565b60006040518083038186803b1580156127eb57600080fd5b505afa1580156127ff573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f5d919081019061534a565b6128308261356a565b61284c5760405162461bcd60e51b815260040161101c90615256565b6000828152601d6020526040808220815161018081019092528054829082906128749061510d565b80601f01602080910402602001604051908101604052809291908181526020018280546128a09061510d565b80156128ed5780601f106128c2576101008083540402835291602001916128ed565b820191906000526020600020905b8154815290600101906020018083116128d057829003601f168201915b505050505081526020016001820180546129069061510d565b80601f01602080910402602001604051908101604052809291908181526020018280546129329061510d565b801561297f5780601f106129545761010080835404028352916020019161297f565b820191906000526020600020905b81548152906001019060200180831161296257829003601f168201915b505050918352505060028201546020820152600382015460408201526004820154606082015260058201546080820152600682015460a0820152600782015460c0820152600882015460e08201526009820154610100820152600a82015460ff161515610120820152600b90910154610140909101529050612a0e836000908152600f60205260409020541590565b15156101408201526022546001600160a01b031663de325b8f612a3085611ea7565b6040518263ffffffff1660e01b8152600401612a4c91906148d1565b60206040518083038186803b158015612a6457600080fd5b505afa158015612a78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a9c91906152d1565b6101608201526021546001600160a01b031663f3b95d0384612abd81612157565b846040518463ffffffff1660e01b8152600401612adc939291906158de565b60006040518083038186803b158015612af457600080fd5b505afa158015612b08573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612b30919081019061534a565b9392505050565b6001600160a01b0381166000908152601e6020526040812054601a54600191612b5f916151e1565b610f5d91906151e1565b600080516020615dfe833981519152612b818161360f565b50601b805460ff1916911515919091179055565b60026012541415612bb85760405162461bcd60e51b815260040161101c906153e7565b60026012556016544211612bde5760405162461bcd60e51b815260040161101c90615256565b60185483612bea611102565b612bf491906156f5565b10612c115760405162461bcd60e51b815260040161101c90615802565b601954612c1e9084615812565b341015612c3d5760405162461bcd60e51b815260040161101c90615849565b601a54336000908152601e6020526040902054612c5b9085906156f5565b10612c785760405162461bcd60e51b815260040161101c90615871565b600033604051602001612c8b919061593c565b604051602081830303815290604052805190602001209050612ce483838080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050601c549150849050613ef6565b612d005760405162461bcd60e51b815260040161101c90615969565b336000908152601e602052604081208054869290612d1f9084906156f5565b90915550612d3f9050338560405180602001604052806000815250613a96565b601b5460ff1615612dad57601f546001600160a01b0316633cbf48e933866040518363ffffffff1660e01b8152600401612d7a9291906152ab565b600060405180830381600087803b158015612d9457600080fd5b505af1158015612da8573d6000803e3d6000fd5b505050505b505060016012555050565b8233612dc382611ea7565b6001600160a01b031614612dea576040516349e27cff60e01b815260040160405180910390fd5b60026012541415612e0d5760405162461bcd60e51b815260040161101c906153e7565b60026012556040516000908190612e2a908690869060200161540a565b60408051601f19818403018152828252805160209182012060008a8152601d83529290922091935090918391612e609101615417565b604051602081830303815290604052805190602001201415612e8e5760048101805460009091559250612ffe565b81604051602001612e9e9061546b565b604051602081830303815290604052805190602001201415612ecc5760038101805460009091559250612ffe565b81604051602001612edc90615476565b604051602081830303815290604052805190602001201415612f0a5760058101805460009091559250612ffe565b81604051602001612f1a906154a6565b604051602081830303815290604052805190602001201415612f485760028101805460009091559250612ffe565b81604051602001612f58906154c8565b604051602081830303815290604052805190602001201415612f865760068101805460009091559250612ffe565b81604051602001612f96906154d3565b604051602081830303815290604052805190602001201415612fc45760078101805460009091559250612ffe565b81604051602001612fd4906154fc565b60405160208183030381529060405280519060200120141561185e57600881018054600090915592505b6000831161301e5760405162461bcd60e51b815260040161101c90615994565b601f546001600160a01b031663466e79eb846001336040518463ffffffff1660e01b81526004016130519392919061551c565b600060405180830381600087803b15801561306b57600080fd5b505af115801561307f573d6000803e3d6000fd5b50505050867fd4596d80f81394606eec2500c28df457c069fe45c83d304190e97e0a8061d6b78787866040516130b793929190615567565b60405180910390a2505060016012555050505050565b6000828152601360205260409020600101546130e88161360f565b6110c283836138a6565b600080516020615dfe83398151915261310a8161360f565b50601655565b600080516020615dfe8339815191526131288161360f565b50601a55565b600080516020615dfe8339815191526131468161360f565b50601580546001600160a01b0319166001600160a01b0392909216919091179055565b600d546001600160a01b031633146131935760405162461bcd60e51b815260040161101c9061579a565b6001600160a01b0381166131b95760405162461bcd60e51b815260040161101c906159e7565b6122fa81613b08565b82336131cd82611ea7565b6001600160a01b0316146131f4576040516349e27cff60e01b815260040160405180910390fd5b8282600082828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509394505050505b81518110156132af57600082828151811061324e5761324e61562a565b01602001516001600160f81b0319169050601160f91b81148061327e5750601760fa1b6001600160f81b03198216145b1561329c57604051630ec0325960e21b815260040160405180910390fd5b50806132a781615266565b915050613231565b50600086868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050825192935050506019101561330e5760405163251f56a160e21b815260040160405180910390fd5b6000888152601d602052604090819020905161332a91906156ae565b60405180910390208180519060200120141561335957604051632a9ffab760e21b815260040160405180910390fd5b6000888152601d602052604090206133729088886146d0565b50877f8edfa912e70e283a8ef6d6f52cd1faef9690ff989eff2f11a134e8478ba7b28b8888604051611bbd9291906156ba565b600454600881901c60009081526007602052604090208054600160ff1b60ff84161c17905561278b848484613401565b600881901c600090815260209290925260409091208054600160ff1b60ff9093169290921c9091179055565b600454826134215760405162461bcd60e51b815260040161101c90615a12565b6001600160a01b0384166134475760405162461bcd60e51b815260040161101c90615a45565b60005b838110156134d557600061345e82846156f5565b60405190915081906001600160a01b038816906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a46134a66000878387613f0c565b6134c25760405162461bcd60e51b815260040161101c90615a89565b50806134cd81615266565b91505061344a565b50600081815260036020908152604080832080546001600160a01b0319166001600160a01b038916179055600884901c83529082905290208054600160ff1b60ff84161c179055826004600082825461352e91906156f5565b9091555061278b9050600085838684565b3b151590565b60006001600160e01b03198216637965db0b60e01b1480610f5d5750610f5d8261401a565b600881901c6000908152600c6020526040812054600160ff1b60ff84161c161561359657506000919050565b610f5d826004541190565b600081815260056020526040902080546001600160a01b0319166001600160a01b03841690811790915581906135d682611ea7565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6122fa8133614085565b6000806008600454901c600161362f91906156f5565b905060005b81811015613674576000818152600c602052604090205461365481614105565b61365e90856156f5565b935050808061366c90615266565b915050613634565b505090565b60008160008151811061368e5761368e61562a565b60209081029190910181015160008581526008835260408082205480835281832083905560099094529020819055915061278b565b6136cd3382614124565b6136e95760405162461bcd60e51b815260040161101c906151bb565b6110c28383836141c5565b336000908152600e602052604090205460ff166137235760405162461bcd60e51b815260040161101c90615acd565b60008181526011602090815260408083203384529091529020541561375a5760405162461bcd60e51b815260040161101c90615b11565b6000818152600f60205260408120546137749060016156f5565b6000838152601060209081526040808320848452825280832080546001600160a01b03191633908117909155868452601183528184209084528252808320849055858352600f90915281208054929350906137ce83615266565b9091555050604051339083907f9ecfd70e9ff36df72989324a49559383d39f9290d700b10cf5ac10dcb68d264390600090a35050565b60008281526013602090815260408083206001600160a01b038516845290915290205460ff166111955760008281526013602090815260408083206001600160a01b03851684529091529020805460ff191660011790556138623390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60008281526013602090815260408083206001600160a01b038516845290915290205460ff16156111955760008281526013602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b336000908152600e602052604090205460ff166139585760405162461bcd60e51b815260040161101c90615acd565b60008181526011602090815260408083203384529091529020548061398f5760405162461bcd60e51b815260040161101c90615b55565b6000828152600f6020526040902054818114613a055760008381526010602090815260408083208484528252808320805486855282852080546001600160a01b03199081166001600160a01b03909316928317909155825416909155868452601183528184209084529091529020829055613a2d565b6000838152601060209081526040808320858452909152902080546001600160a01b03191690555b60008381526011602090815260408083203384528252808320839055858352600f9091528120805491613a5f83615b65565b9091555050604051339084907f0fe7d9801197f79ef3b1595d19379eb58f0fff5f98b0f6d6f34c03cae5306c3790600090a3505050565b600454600b546000828152600a602052604090205561278b8484846133a5565b600080613ac28361356a565b613ade5760405162461bcd60e51b815260040161101c9061515b565b613ae78361435a565b6000818152600360205260409020546001600160a01b031694909350915050565b600d80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b0381166000908152600e602052604090205460ff1615613b935760405162461bcd60e51b815260040161101c90615acd565b60008281526011602090815260408083206001600160a01b038516845290915290205480613bd35760405162461bcd60e51b815260040161101c90615bb0565b6000838152600f6020526040902054818114613c495760008481526010602090815260408083208484528252808320805486855282852080546001600160a01b03199081166001600160a01b03909316928317909155825416909155878452601183528184209084529091529020829055613c71565b6000848152601060209081526040808320858452909152902080546001600160a01b03191690555b60008481526011602090815260408083206001600160a01b03871684528252808320839055868352600f9091528120805491613cac83615b65565b90915550506040516001600160a01b0384169085907f0fe7d9801197f79ef3b1595d19379eb58f0fff5f98b0f6d6f34c03cae5306c3790600090a350505050565b6000613cf88261356a565b613d145760405162461bcd60e51b815260040161101c9061515b565b600a6000613d2184614366565b8152602001908152602001600020549050919050565b6040516305d3b1d360e41b81526000907f000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e699096001600160a01b031690635d3b1d3090613e0f907f8af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef907f0000000000000000000000000000000000000000000000000000000000000185907f0000000000000000000000000000000000000000000000000000000000000003907f0000000000000000000000000000000000000000000000000000000000061a8090600190600401615beb565b602060405180830381600087803b158015613e2957600080fd5b505af1158015613e3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e6191906152d1565b90507f76421cb080d40e8a03ba462b500012451ba59bdebc46694dc458807c1d754b6281604051613e929190614936565b60405180910390a1600b54600082815260086020526040902055600b8054906000613ebc83615266565b919050555050565b613ece3383614124565b613eea5760405162461bcd60e51b815260040161101c906151bb565b61278b84848484614373565b600082613f0385846143a6565b14949350505050565b60006001600160a01b0384163b1561400e57604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290613f50903390899088908890600401615c37565b602060405180830381600087803b158015613f6a57600080fd5b505af1925050508015613f9a575060408051601f3d908101601f19168201909252613f9791810190615c7c565b60015b613ff4573d808015613fc8576040519150601f19603f3d011682016040523d82523d6000602084013e613fcd565b606091505b508051613fec5760405162461bcd60e51b815260040161101c90615a89565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050614012565b5060015b949350505050565b60006001600160e01b031982166380ac58cd60e01b148061404b57506001600160e01b03198216635b5e139f60e01b145b8061406657506001600160e01b0319821663780e9d6360e01b145b80610f5d57506301ffc9a760e01b6001600160e01b0319831614610f5d565b60008281526013602090815260408083206001600160a01b038516845290915290205460ff16611195576140c3816001600160a01b03166014614412565b6140ce836020614412565b6040516020016140df929190615c9d565b60408051601f198184030181529082905262461bcd60e51b825261101c91600401614874565b60005b811561411f57600019820190911690600101614108565b919050565b600061412f8261356a565b61414b5760405162461bcd60e51b815260040161101c90615d1e565b600061415683611ea7565b9050806001600160a01b0316846001600160a01b031614806141915750836001600160a01b031661418684610ff5565b6001600160a01b0316145b8061401257506001600160a01b0380821660009081526006602090815260408083209388168352929052205460ff16614012565b6000806141d183613ab6565b91509150846001600160a01b0316826001600160a01b0316146142065760405162461bcd60e51b815260040161101c90615d4b565b6001600160a01b03841661422c5760405162461bcd60e51b815260040161101c90615d7d565b6142376000846135a1565b60006142448460016156f5565b600881901c600090815260208190526040902054909150600160ff1b60ff83161c16158015614274575060045481105b156142c057600081815260036020908152604080832080546001600160a01b0319166001600160a01b038b16179055600884901c83529082905290208054600160ff1b60ff84161c1790555b600084815260036020526040902080546001600160a01b0319166001600160a01b03871617905581841461431157600884901c60009081526020819052604090208054600160ff1b60ff87161c1790555b83856001600160a01b0316876001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050505050565b6000610f5d818361458b565b6000610f5d60078361458b565b61437e8484846141c5565b61438a84848484613f0c565b61278b5760405162461bcd60e51b815260040161101c90615a89565b600081815b8451811015611c685760008582815181106143c8576143c861562a565b602002602001015190508083116143ee57600083815260208290526040902092506143ff565b600081815260208490526040902092505b508061440a81615266565b9150506143ab565b60606000614421836002615812565b61442c9060026156f5565b67ffffffffffffffff811115614444576144446149b6565b6040519080825280601f01601f19166020018201604052801561446e576020820181803683370190505b509050600360fc1b816000815181106144895761448961562a565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106144b8576144b861562a565b60200101906001600160f81b031916908160001a90535060006144dc846002615812565b6144e79060016156f5565b90505b600181111561456c577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106145285761452861562a565b1a60f81b82828151811061453e5761453e61562a565b60200101906001600160f81b031916908160001a90535060049490941c9361456581615b65565b90506144ea565b508315612b305760405162461bcd60e51b815260040161101c90615dbf565b600881901c60008181526020849052604081205490919060ff8085169190821890811c80156145d3576145bd8161464e565b60ff168303600885901b17945050505050610f5d565b600084116145f35760405162461bcd60e51b815260040161101c9061515b565b6000199093019260ff9250600091505b506000838152602087905260409020548015614622576145bd8161464e565b600084116146425760405162461bcd60e51b815260040161101c90615ded565b60001990930192614603565b60006040518061012001604052806101008152602001615e1e610100913960f87e818283848586878898a8b8c8d8e8f929395969799a9b9d9e9faaeb6bedeeff614697856146b8565b02901c815181106146aa576146aa61562a565b016020015160f81c92915050565b60008082116146c657600080fd5b5060008190031690565b8280546146dc9061510d565b90600052602060002090601f0160209004810192826146fe5760008555614744565b82601f106147175782800160ff19823516178555614744565b82800160010185558215614744579182015b82811115614744578235825591602001919060010190614729565b50614750929150614754565b5090565b5b808211156147505760008155600101614755565b6001600160e01b031981165b81146122fa57600080fd5b8035610f5d81614769565b6000602082840312156147a0576147a0600080fd5b60006140128484614780565b8015155b82525050565b60208101610f5d82846147ac565b6000610f5d6001600160a01b0383166147db565b90565b6001600160a01b031690565b6000610f5d826147c4565b6000610f5d826147e7565b6147b0816147f2565b60208101610f5d82846147fd565b60005b8381101561482f578181015183820152602001614817565b8381111561278b5750506000910152565b600061484a825190565b808452602084019350614861818560208601614814565b601f19601f8201165b9093019392505050565b60208082528101612b308184614840565b80614775565b8035610f5d81614885565b6000602082840312156148ab576148ab600080fd5b6000614012848461488b565b60006001600160a01b038216610f5d565b6147b0816148b7565b60208101610f5d82846148c8565b614775816148b7565b8035610f5d816148df565b6000806040838503121561490957614909600080fd5b6000614915858561488b565b9250506020614926858286016148e8565b9150509250929050565b806147b0565b60208101610f5d8284614930565b6000806040838503121561495a5761495a600080fd5b600061496685856148e8565b92505060206149268582860161488b565b67ffffffffffffffff81166147b0565b60208101610f5d8284614977565b6000602082840312156149aa576149aa600080fd5b600061401284846148e8565b634e487b7160e01b600052604160045260246000fd5b601f19601f830116810181811067ffffffffffffffff821117156149f2576149f26149b6565b6040525050565b6000614a0460405190565b905061411f82826149cc565b600067ffffffffffffffff821115614a2a57614a2a6149b6565b5060209081020190565b6000614a47614a4284614a10565b6149f9565b83815290506020808201908402830185811115614a6657614a66600080fd5b835b81811015614a8a5780614a7b888261488b565b84525060209283019201614a68565b5050509392505050565b600082601f830112614aa857614aa8600080fd5b8135614012848260208601614a34565b60008060408385031215614ace57614ace600080fd5b6000614ada858561488b565b925050602083013567ffffffffffffffff811115614afa57614afa600080fd5b61492685828601614a94565b600080600060608486031215614b1e57614b1e600080fd5b6000614b2a86866148e8565b9350506020614b3b868287016148e8565b9250506040614b4c8682870161488b565b9150509250925092565b60008060408385031215614b6c57614b6c600080fd5b6000614966858561488b565b60008083601f840112614b8d57614b8d600080fd5b50813567ffffffffffffffff811115614ba857614ba8600080fd5b602083019150836001820283011115614bc357614bc3600080fd5b9250929050565b60008060008060608587031215614be357614be3600080fd5b6000614bef878761488b565b945050602085013567ffffffffffffffff811115614c0f57614c0f600080fd5b614c1b87828801614b78565b93509350506040614c2e8782880161488b565b91505092959194509250565b600080600060408486031215614c5257614c52600080fd5b6000614c5e868661488b565b935050602084013567ffffffffffffffff811115614c7e57614c7e600080fd5b614c8a86828701614b78565b92509250509250925092565b6000614ca28383614930565b505060200190565b6000614cb4825190565b80845260209384019383018060005b83811015614ce8578151614cd78882614c96565b975060208301925050600101614cc3565b509495945050505050565b60208082528101612b308184614caa565b801515614775565b8035610f5d81614d04565b600060208284031215614d2c57614d2c600080fd5b60006140128484614d0c565b60008083601f840112614d4d57614d4d600080fd5b50813567ffffffffffffffff811115614d6857614d68600080fd5b602083019150836020820283011115614bc357614bc3600080fd5b60008060208385031215614d9957614d99600080fd5b823567ffffffffffffffff811115614db357614db3600080fd5b614dbf85828601614d38565b92509250509250929050565b60008060408385031215614de157614de1600080fd5b6000614ded85856148e8565b925050602061492685828601614d0c565b805161018080845260009190840190614e178282614840565b91505060208301518482036020860152614e318282614840565b9150506040830151614e466040860182614930565b506060830151614e596060860182614930565b506080830151614e6c6080860182614930565b5060a0830151614e7f60a0860182614930565b5060c0830151614e9260c0860182614930565b5060e0830151614ea560e0860182614930565b50610100830151614eba610100860182614930565b50610120830151614ecf610120860182614930565b50610140830151614ee46101408601826147ac565b50610160830151611c68610160860182614930565b60208082528101612b308184614dfe565b60008060008060408587031215614f2357614f23600080fd5b843567ffffffffffffffff811115614f3d57614f3d600080fd5b614f4987828801614d38565b9450945050602085013567ffffffffffffffff811115614f6b57614f6b600080fd5b614f7787828801614d38565b95989497509550505050565b600067ffffffffffffffff821115614f9d57614f9d6149b6565b601f19601f83011660200192915050565b82818337506000910152565b6000614fc8614a4284614f83565b905082815260208101848484011115614fe357614fe3600080fd5b611c68848285614fae565b600082601f83011261500257615002600080fd5b8135614012848260208601614fba565b6000806000806080858703121561502b5761502b600080fd5b600061503787876148e8565b9450506020615048878288016148e8565b93505060406150598782880161488b565b925050606085013567ffffffffffffffff81111561507957615079600080fd5b614c2e87828801614fee565b60008060006040848603121561509d5761509d600080fd5b60006150a9868661488b565b935050602084013567ffffffffffffffff8111156150c9576150c9600080fd5b614c8a86828701614d38565b600080604083850312156150eb576150eb600080fd5b600061491585856148e8565b634e487b7160e01b600052602260045260246000fd5b60028104600182168061512157607f821691505b60208210811415615134576151346150f7565b50919050565b60078152600060208201662165786973747360c81b815291505b5060200190565b60208082528101610f5d8161513a565b600981526000602082016808585c1c1c9bdd985b60ba1b81529150615154565b60208082528101610f5d8161516b565b600981526000602082016808585c1c1c9bdd995960ba1b81529150615154565b60208082528101610f5d8161519b565b634e487b7160e01b600052601160045260246000fd5b6000828210156151f3576151f36151cb565b500390565b6040810161520682856148c8565b612b3060208301846148c8565b60048152600060208201633133333760e01b81529150615154565b60208082528101610f5d81615213565b60018152600060208201600360fc1b81529150615154565b60208082528101610f5d8161523e565b600060001982141561527a5761527a6151cb565b5060010190565b600381526000602082016237b7b160e91b81529150615154565b60208082528101610f5d81615281565b604081016152b982856148c8565b612b306020830184614930565b8051610f5d81614885565b6000602082840312156152e6576152e6600080fd5b600061401284846152c6565b6000615300614a4284614f83565b90508281526020810184848401111561531b5761531b600080fd5b611c68848285614814565b600082601f83011261533a5761533a600080fd5b81516140128482602086016152f2565b60006020828403121561535f5761535f600080fd5b815167ffffffffffffffff81111561537957615379600080fd5b61401284828501615326565b600061538f825190565b61539d818560208601614814565b9290920192915050565b6000612b308284615385565b601f81526000602082017f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0081529150615154565b60208082528101610f5d816153b3565b6000615404838584614fae565b50500190565b60006140128284866153f7565b652ba2a0a827a760d11b8152600060068201610f5d565b60028152600060208201611c9b60f11b81529150615154565b60208082528101610f5d8161542e565b631211505160e21b815260005b5060040190565b6000610f5d82615457565b6420a926a7a960d91b8152600060058201610f5d565b69109050d2d1d493d5539160b21b815260005b50600a0190565b6000610f5d8261548c565b692320a1a2afa0a926a7a960b11b8152600061549f565b6000610f5d826154b1565b6622aca2aba2a0a960c91b8152600060078201610f5d565b634d49534360e01b81526000615464565b6000610f5d826154eb565b6000610f5d6147d88381565b6147b081615507565b6060810161552a8286614930565b6155376020830185615513565b61401260408301846148c8565b818352600060208401935061555a838584614fae565b601f19601f84011661486a565b60408082528101615579818587615544565b90506140126020830184614930565b602f81526000602082017f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636581527f20726f6c657320666f722073656c660000000000000000000000000000000000602082015291505b5060400190565b60208082528101610f5d81615588565b6000610f5d826147d8565b600381526000602082016239393960e81b81529150615154565b60208082528101610f5d81615600565b634e487b7160e01b600052603260045260246000fd5b6000815461564d8161510d565b6001821680156156645760018114615675576156a5565b60ff198316865281860193506156a5565b60008581526020902060005b8381101561569d57815488820152600190910190602001615681565b838801955050505b50505092915050565b6000612b308284615640565b60208082528101614012818486615544565b6002815260006020820161363960f01b81529150615154565b60208082528101610f5d816156cc565b60008219821115615708576157086151cb565b500190565b6060810161571b82866148c8565b61572860208301856148c8565b6140126040830184614930565b600c81526000602082016b7a65726f206164647265737360a01b81529150615154565b60208082528101610f5d81615735565b60208082527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657291019081526000615154565b60208082528101610f5d81615768565b600b81526000602082016a08599d5b1b199a5b1b195960aa1b81529150615154565b60208082528101610f5d816157aa565b604081016152b98285614930565b60018152600060208201603960f81b81529150615154565b60208082528101610f5d816157ea565b600081600019048311821515161561582c5761582c6151cb565b500290565b60018152600060208201603160f81b81529150615154565b60208082528101610f5d81615831565b60018152600060208201601960f91b81529150615154565b60208082528101610f5d81615859565b600881526000602082016721617070726f766560c01b81529150615154565b60208082528101610f5d81615881565b6007815260006020820166042d8cadccee8d60cb1b81529150615154565b60208082528101610f5d816158b0565b606081016158ec8286614930565b6158f96020830185614930565b818103604083015261590b8184614dfe565b95945050505050565b6000610f5d8260601b90565b6000610f5d82615914565b6147b0615937826148b7565b615920565b6000615948828461592b565b50601401919050565b60018152600060208201600d60fa1b81529150615154565b60208082528101610f5d81615951565b60048152600060208201633639363960e01b81529150615154565b60208082528101610f5d81615979565b602681526000602082017f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015291506155de565b60208082528101610f5d816159a4565b60048152600060208201637a65726f60e01b81529150615154565b60208082528101610f5d816159f7565b600c81526000602082016b217a65726f6164647265737360a01b81529150615154565b60208082528101610f5d81615a22565b600f81526000602082017f214552433732315265636569766572000000000000000000000000000000000081529150615154565b60208082528101610f5d81615a55565b601181526000602082017f43616e6e6f7420757064617465206d617000000000000000000000000000000081529150615154565b60208082528101610f5d81615a99565b601b81526000602082017f494420616c7265616479206c6f636b65642062792063616c6c6572000000000081529150615154565b60208082528101610f5d81615add565b601781526000602082017f4944206e6f74206c6f636b65642062792063616c6c657200000000000000000081529150615154565b60208082528101610f5d81615b21565b600081615b7457615b746151cb565b506000190190565b600d81526000602082017f4944206e6f74206c6f636b65640000000000000000000000000000000000000081529150615154565b60208082528101610f5d81615b7c565b61ffff81166147b0565b63ffffffff81166147b0565b600061ffff8216610f5d565b6147b081615bd6565b60a08101615bf98288614930565b615c066020830187614977565b615c136040830186615bc0565b615c206060830185615bca565b615c2d6080830184615be2565b9695505050505050565b60808101615c4582876148c8565b615c5260208301866148c8565b615c5f6040830185614930565b8181036060830152615c2d8184614840565b8051610f5d81614769565b600060208284031215615c9157615c91600080fd5b60006140128484615c71565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526017016000615ccf8285615385565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000815260110191506140128284615385565b600681526000602082016508595e1a5cdd60d21b81529150615154565b60208082528101610f5d81615d01565b60068152600060208201653737ba37bbb760d11b81529150615154565b60208082528101610f5d81615d2e565b600b81526000602082016a7a65726f6164647265737360a81b81529150615154565b60208082528101610f5d81615d5b565b60208082527f537472696e67733a20686578206c656e67746820696e73756666696369656e7491019081526000615154565b60208082528101610f5d81615d8d565b60078152600060208201662165786973745360c81b81529150615154565b60208082528101610f5d81615dcf56feb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e0001020903110a19042112290b311a3905412245134d2a550c5d32651b6d3a7506264262237d468514804e8d2b95569d0d495ea533a966b11c886eb93bc176c9071727374353637324837e9b47af86c7155181ad4fd18ed32c9096db57d59ee30e2e4a6a5f92a6be3498aae067ddb2eb1d5989b56fd7baf33ca0c2ee77e5caf7ff0810182028303840444c545c646c7425617c847f8c949c48a4a8b087b8c0c816365272829aaec650acd0d28fdad4e22d6991bd97dfdcea58b4d6f29fede4f6fe0f1f2f3f4b5b6b607b8b93a3a7b7bf357199c5abcfd9e168bcdee9b3f1ecf5fd1e3e5a7a8aa2b670c4ced8bbe8f0f4fc3d79a1c3cde7effb78cce6facbf9f8a26469706673582212200a69d5a5a7edc680d1e1a299af104003cfb32e049d1009510bb21d5ab5ecdf6864736f6c63430008090033

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

000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e699098af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef00000000000000000000000000000000000000000000000000000000000001850000000000000000000000000e223db582e3fc2c47ba39f67a1e55b7a75f09fd0000000000000000000000005e2454f33c3da3aa30eabc502255f66a6d72adc8000000000000000000000000e9b41d92c64b4b088a6ddf55057f60195b90e09f000000000000000000000000bd24a76f4135f930f5c49f6c30e0e30a61b97537

-----Decoded View---------------
Arg [0] : _vrfV2Coordinator (address): 0x271682DEB8C4E0901D1a1550aD2e64D568E69909
Arg [1] : keyHash_ (bytes32): 0x8af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef
Arg [2] : subscriptionId_ (uint64): 389
Arg [3] : _accessPassContract (address): 0x0E223db582e3fc2c47bA39f67A1E55B7a75F09fD
Arg [4] : _factionContract (address): 0x5E2454F33c3da3Aa30EabC502255f66A6d72aDc8
Arg [5] : _renderingContract (address): 0xE9B41D92C64B4b088A6ddF55057F60195b90e09f
Arg [6] : _vendorContract (address): 0xbd24A76F4135F930F5c49f6c30e0E30A61b97537

-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e69909
Arg [1] : 8af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000185
Arg [3] : 0000000000000000000000000e223db582e3fc2c47ba39f67a1e55b7a75f09fd
Arg [4] : 0000000000000000000000005e2454f33c3da3aa30eabc502255f66a6d72adc8
Arg [5] : 000000000000000000000000e9b41d92c64b4b088a6ddf55057f60195b90e09f
Arg [6] : 000000000000000000000000bd24a76f4135f930f5c49f6c30e0e30a61b97537


Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.