ETH Price: $3,225.87 (-1.59%)

Contract

0x1F4660301EF69Ca42bd9d36D5Fc32a4cF563428a
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ERC721Facet

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
No with 200 runs

Other Settings:
paris EvmVersion
File 1 of 36 : ERC721Facet.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;

// Import necessary libraries and contracts
import { AccessControlInternal } from "@solidstate/contracts/access/access_control/AccessControlInternal.sol";
import { ERC165BaseInternal } from "@solidstate/contracts/introspection/ERC165/base/ERC165BaseInternal.sol";
import { ERC721Base } from "@solidstate/contracts/token/ERC721/base/ERC721Base.sol";
import { ERC721BaseInternal } from "@solidstate/contracts/token/ERC721/base/ERC721BaseInternal.sol";
import { ERC721Enumerable } from "@solidstate/contracts/token/ERC721/enumerable/ERC721Enumerable.sol";
import { ERC721Metadata } from "@solidstate/contracts/token/ERC721/metadata/ERC721Metadata.sol";
import { PartiallyPausableInternal } from "@solidstate/contracts/security/partially_pausable/PartiallyPausableInternal.sol";
import { PausableInternal } from "@solidstate/contracts/security/pausable/PausableInternal.sol";
import "../libraries/LibSilksHorseDiamond.sol";

/**
 * @title ERC721Facet
 * @dev A Solidity smart contract representing the ERC721 facet of the SilksHorseDiamond contract.
 * This facet provides functionality for purchasing and airdropping NFTs (horses) and handles pausing functionality.
 */
contract ERC721Facet is
    AccessControlInternal,
    ERC165BaseInternal,
    ERC721Base,
    ERC721Enumerable,
    ERC721Metadata,
    PartiallyPausableInternal,
    PausableInternal
{
    using EnumerableSet for EnumerableSet.UintSet;
    
    event HorseMinted(
        MintMethod indexed method,
        uint256 indexed seasonId,
        uint256 indexed payoutTier,
        address to,
        uint256 tokenId
    );
    
    /**
     * @dev Purchase horses by providing season, payout tier, and quantity.
     * @param _seasonId The ID of the season from which to purchase horses.
     * @param _payoutTier The ID of the payout tier for the purchase.
     * @param _quantity The quantity of horses to purchase.
     */
    function purchase(
        uint256 _seasonId,
        uint256 _payoutTier,
        uint256 _quantity
    )
    public
    payable
    whenNotPaused
    whenNotPartiallyPaused(HORSE_PURCHASING_PAUSED)
    {
        // Check if the sent Ether amount is valid
        PayoutTier storage payoutTier = LibSilksHorseDiamond.layout().payoutTiers[_payoutTier];
        uint256 expectedEthTotal = payoutTier.price * _quantity;
        if (expectedEthTotal != msg.value){
            revert InvalidIntValue(
                "INV_ETH_TOTAL",
                msg.value,
                expectedEthTotal
            );
        }
        
        // Check if the purchase quantity is within the allowed limit per transaction
        if (payoutTier.maxPerTx != 0 && _quantity > payoutTier.maxPerTx){
            revert InvalidIntValue(
                "PER_TX_ERROR",
                _quantity,
                payoutTier.maxPerTx
            );
        }
        
        // Mint the specified quantity of horses to the sender
        _mintHorses(_seasonId, _payoutTier, _quantity, MintMethod.PURCHASE, msg.sender);
    }
    
    /**
     * @dev Airdrop horses by providing season, payout tier, quantity, and the recipient address.
     * @param _seasonId The ID of the season for the airdrop.
     * @param _payoutTier The ID of the payout tier for the airdrop.
     * @param _quantity The quantity of horses to airdrop.
     * @param _to The address to receive the airdropped horses.
     */
    function airdrop(
        uint256 _seasonId,
        uint256 _payoutTier,
        uint256 _quantity,
        address _to
    )
    public
    onlyRole(MINT_ADMIN_ROLE)
    {
        // Mint the specified quantity of horses and send them to the specified recipient
        _mintHorses(_seasonId, _payoutTier, _quantity, MintMethod.AIRDROP, _to);
    }
    
    /**
    * @dev Allows an external address to mint horses by providing season, payout tier, quantity, and the recipient address.
    * Checks if the calling address is in the allowed list of external mint addresses before minting.
    * @param _seasonId The ID of the season for the minted horses.
    * @param _payoutTier The ID of the payout tier for the minted horses.
    * @param _quantity The quantity of horses to mint.
    * @param _to The address to receive the minted horses.
    */
    function externalMint(
        uint256 _seasonId,
        uint256 _payoutTier,
        uint256 _quantity,
        address _to
    ) external
    {
        // Check if the calling address is in the list of allowed external mint addresses
        bool inAllowedList = LibSilksHorseDiamond.layout().allowedExternalMintAddresses[msg.sender];
        if (!inAllowedList){
            revert InvalidExternalMintAddress(
                msg.sender
            );
        }
        
        // Call the internal function to mint the horses
        _mintHorses(_seasonId, _payoutTier, _quantity, MintMethod.EXTERNAL_MINT, _to);
    }
    
    /**
     * @dev Mint horses based on season, payout tier, quantity, minting method, and recipient address.
     * @param _seasonId The ID of the season for minting horses.
     * @param _payoutTier The ID of the payout tier for minting horses.
     * @param _quantity The quantity of horses to mint.
     * @param _method The minting method used for the horses.
     * @param _to The address to receive the minted horses.
     * @dev This function is used to mint a specified quantity of horse tokens and associate them with a season and payout tier.
     * The minted horse tokens are then assigned to the provided recipient address. The function performs various checks
     * to ensure the specified season and payout tier are valid and not paused. It also checks for successful association of
     * horse tokens with the season and logs minting events.
     * @dev Emits a HorseMinted event upon successful minting.
     * @dev Reverts with specific error messages in case of invalid or paused season, invalid or paused payout tier,
     * failed association of tokens with the season, or any other minting failure.
     */
    function _mintHorses(
        uint256 _seasonId,
        uint256 _payoutTier,
        uint256 _quantity,
        MintMethod _method,
        address _to
    )
    private
    {
        // Check if the _quantity being minted will cause the maximum number of assets in wallet to be exceeded
        uint256 maxHorsesPerWallet = LibSilksHorseDiamond.layout().maxHorsesPerWallet;
        if (maxHorsesPerWallet > 0 &&( _balanceOf(_to) + _quantity) > maxHorsesPerWallet){
            revert MaxHorsesPerWalletExceeded(
                _to
            );
        }
        
        // Check if the specified season and payout tier are valid and not paused
        SeasonInfo storage seasonInfo = LibSilksHorseDiamond.layout().seasonInfos[_seasonId];
        if (seasonInfo.paused || !seasonInfo.valid){
            revert InvalidSeason(
                _seasonId
            );
        }
        
        PayoutTier storage payoutTier = LibSilksHorseDiamond.layout().payoutTiers[_payoutTier];
        if (payoutTier.paused || !payoutTier.valid){
            revert InvalidPayoutTier(
                _payoutTier
            );
        }
        
        LibSilksHorseDiamond.Layout storage lsh = LibSilksHorseDiamond.layout();
        
        EnumerableSet.UintSet storage payoutTierHorses = lsh.payoutTierHorses[_payoutTier];
        if (payoutTier.maxSupply > 0 && (payoutTierHorses.length() + _quantity) > payoutTier.maxSupply){
            revert PayoutTierMaxSupplyExceeded(
                _payoutTier
            );
        }
    
        EnumerableSet.UintSet storage seasonHorses = lsh.seasonHorses[_seasonId];
        uint256 nextAvailableTokenId = lsh.nextAvailableTokenId;
        uint256 i = 0;
        // Mint the specified quantity of horses, associate them with the season, and set payout percentages
        for (; i < _quantity;) {
            uint256 _newTokenId = nextAvailableTokenId + i;
            if (!seasonHorses.add(_newTokenId)){
                revert MintFailed(
                    "TOKEN_CROP_ASSOCIATION_ERROR",
                    _seasonId,
                    _payoutTier,
                    _quantity,
                    _method,
                    _to
                );
            }
            if (!payoutTierHorses.add(_newTokenId)){
                revert MintFailed(
                    "TOKEN_PAYOUT_TIER_ASSOCIATION_ERROR",
                    _seasonId,
                    _payoutTier,
                    _quantity,
                    _method,
                    _to
                );
            }
            lsh.horsePayoutTier[_newTokenId] = payoutTier;
            lsh.horseSeasonInfo[_newTokenId] = seasonInfo;
            _safeMint(_to, _newTokenId);
            emit HorseMinted(_method, _seasonId, _payoutTier, _to, _newTokenId);
            unchecked {
                i++;
            }
        }
        lsh.nextAvailableTokenId = nextAvailableTokenId + i;
    }
    
    /**
     * @dev Hook function called before token transfer, inherited from ERC721Metadata.
     * @param from The sender of the tokens.
     * @param to The recipient of the tokens.
     * @param tokenId The ID of the token being transferred.
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    )
    internal
    virtual
    override(
        ERC721Metadata,
        ERC721BaseInternal
    )
    {
        super._beforeTokenTransfer(from, to, tokenId);
    }
    
    /**
     * @notice query whether contract has registered support for given interface
     * @param interfaceId interface id
     * @return bool whether interface is supported
     */
    function supportsInterface(
        bytes4 interfaceId
    )
    external
    view
    returns (
        bool
    )
    {
        return super._supportsInterface(interfaceId);
    }
}

File 2 of 36 : AccessControlInternal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { EnumerableSet } from '../../data/EnumerableSet.sol';
import { AddressUtils } from '../../utils/AddressUtils.sol';
import { UintUtils } from '../../utils/UintUtils.sol';
import { IAccessControlInternal } from './IAccessControlInternal.sol';
import { AccessControlStorage } from './AccessControlStorage.sol';

/**
 * @title Role-based access control system
 * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license)
 */
abstract contract AccessControlInternal is IAccessControlInternal {
    using AddressUtils for address;
    using EnumerableSet for EnumerableSet.AddressSet;
    using UintUtils for uint256;

    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    /*
     * @notice query whether role is assigned to account
     * @param role role to query
     * @param account account to query
     * @return whether role is assigned to account
     */
    function _hasRole(
        bytes32 role,
        address account
    ) internal view virtual returns (bool) {
        return
            AccessControlStorage.layout().roles[role].members.contains(account);
    }

    /**
     * @notice revert if sender does not have given role
     * @param role role to query
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, msg.sender);
    }

    /**
     * @notice revert if given account does not have given role
     * @param role role to query
     * @param account to query
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!_hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        'AccessControl: account ',
                        account.toString(),
                        ' is missing role ',
                        uint256(role).toHexString(32)
                    )
                )
            );
        }
    }

    /*
     * @notice query admin role for given role
     * @param role role to query
     * @return admin role
     */
    function _getRoleAdmin(
        bytes32 role
    ) internal view virtual returns (bytes32) {
        return AccessControlStorage.layout().roles[role].adminRole;
    }

    /**
     * @notice set role as admin role
     * @param role role to set
     * @param adminRole admin role to set
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = _getRoleAdmin(role);
        AccessControlStorage.layout().roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /*
     * @notice assign role to given account
     * @param role role to assign
     * @param account recipient of role assignment
     */
    function _grantRole(bytes32 role, address account) internal virtual {
        AccessControlStorage.layout().roles[role].members.add(account);
        emit RoleGranted(role, account, msg.sender);
    }

    /*
     * @notice unassign role from given account
     * @param role role to unassign
     * @parm account
     */
    function _revokeRole(bytes32 role, address account) internal virtual {
        AccessControlStorage.layout().roles[role].members.remove(account);
        emit RoleRevoked(role, account, msg.sender);
    }

    /**
     * @notice relinquish role
     * @param role role to relinquish
     */
    function _renounceRole(bytes32 role) internal virtual {
        _revokeRole(role, msg.sender);
    }

    /**
     * @notice query role for member at given index
     * @param role role to query
     * @param index index to query
     */
    function _getRoleMember(
        bytes32 role,
        uint256 index
    ) internal view virtual returns (address) {
        return AccessControlStorage.layout().roles[role].members.at(index);
    }

    /**
     * @notice query role for member count
     * @param role role to query
     */
    function _getRoleMemberCount(
        bytes32 role
    ) internal view virtual returns (uint256) {
        return AccessControlStorage.layout().roles[role].members.length();
    }
}

File 3 of 36 : AccessControlStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { EnumerableSet } from '../../data/EnumerableSet.sol';

library AccessControlStorage {
    struct RoleData {
        EnumerableSet.AddressSet members;
        bytes32 adminRole;
    }

    struct Layout {
        mapping(bytes32 => RoleData) roles;
    }

    bytes32 internal constant DEFAULT_ADMIN_ROLE = 0x00;

    bytes32 internal constant STORAGE_SLOT =
        keccak256('solidstate.contracts.storage.AccessControl');

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = STORAGE_SLOT;
        assembly {
            l.slot := slot
        }
    }
}

File 4 of 36 : IAccessControlInternal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @title Partial AccessControl interface needed by internal functions
 */
interface IAccessControlInternal {
    event RoleAdminChanged(
        bytes32 indexed role,
        bytes32 indexed previousAdminRole,
        bytes32 indexed newAdminRole
    );

    event RoleGranted(
        bytes32 indexed role,
        address indexed account,
        address indexed sender
    );

    event RoleRevoked(
        bytes32 indexed role,
        address indexed account,
        address indexed sender
    );
}

File 5 of 36 : EnumerableMap.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

/**
 * @title Map implementation with enumeration functions
 * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license)
 */
library EnumerableMap {
    error EnumerableMap__IndexOutOfBounds();
    error EnumerableMap__NonExistentKey();

    struct MapEntry {
        bytes32 _key;
        bytes32 _value;
    }

    struct Map {
        MapEntry[] _entries;
        // 1-indexed to allow 0 to signify nonexistence
        mapping(bytes32 => uint256) _indexes;
    }

    struct AddressToAddressMap {
        Map _inner;
    }

    struct UintToAddressMap {
        Map _inner;
    }

    function at(
        AddressToAddressMap storage map,
        uint256 index
    ) internal view returns (address, address) {
        (bytes32 key, bytes32 value) = _at(map._inner, index);

        return (
            address(uint160(uint256(key))),
            address(uint160(uint256(value)))
        );
    }

    function at(
        UintToAddressMap storage map,
        uint256 index
    ) internal view returns (uint256, address) {
        (bytes32 key, bytes32 value) = _at(map._inner, index);
        return (uint256(key), address(uint160(uint256(value))));
    }

    function contains(
        AddressToAddressMap storage map,
        address key
    ) internal view returns (bool) {
        return _contains(map._inner, bytes32(uint256(uint160(key))));
    }

    function contains(
        UintToAddressMap storage map,
        uint256 key
    ) internal view returns (bool) {
        return _contains(map._inner, bytes32(key));
    }

    function length(
        AddressToAddressMap storage map
    ) internal view returns (uint256) {
        return _length(map._inner);
    }

    function length(
        UintToAddressMap storage map
    ) internal view returns (uint256) {
        return _length(map._inner);
    }

    function get(
        AddressToAddressMap storage map,
        address key
    ) internal view returns (address) {
        return
            address(
                uint160(
                    uint256(_get(map._inner, bytes32(uint256(uint160(key)))))
                )
            );
    }

    function get(
        UintToAddressMap storage map,
        uint256 key
    ) internal view returns (address) {
        return address(uint160(uint256(_get(map._inner, bytes32(key)))));
    }

    function set(
        AddressToAddressMap storage map,
        address key,
        address value
    ) internal returns (bool) {
        return
            _set(
                map._inner,
                bytes32(uint256(uint160(key))),
                bytes32(uint256(uint160(value)))
            );
    }

    function set(
        UintToAddressMap storage map,
        uint256 key,
        address value
    ) internal returns (bool) {
        return _set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
    }

    function remove(
        AddressToAddressMap storage map,
        address key
    ) internal returns (bool) {
        return _remove(map._inner, bytes32(uint256(uint160(key))));
    }

    function remove(
        UintToAddressMap storage map,
        uint256 key
    ) internal returns (bool) {
        return _remove(map._inner, bytes32(key));
    }

    function toArray(
        AddressToAddressMap storage map
    )
        internal
        view
        returns (address[] memory keysOut, address[] memory valuesOut)
    {
        uint256 len = map._inner._entries.length;

        keysOut = new address[](len);
        valuesOut = new address[](len);

        unchecked {
            for (uint256 i; i < len; ++i) {
                keysOut[i] = address(
                    uint160(uint256(map._inner._entries[i]._key))
                );
                valuesOut[i] = address(
                    uint160(uint256(map._inner._entries[i]._value))
                );
            }
        }
    }

    function toArray(
        UintToAddressMap storage map
    )
        internal
        view
        returns (uint256[] memory keysOut, address[] memory valuesOut)
    {
        uint256 len = map._inner._entries.length;

        keysOut = new uint256[](len);
        valuesOut = new address[](len);

        unchecked {
            for (uint256 i; i < len; ++i) {
                keysOut[i] = uint256(map._inner._entries[i]._key);
                valuesOut[i] = address(
                    uint160(uint256(map._inner._entries[i]._value))
                );
            }
        }
    }

    function keys(
        AddressToAddressMap storage map
    ) internal view returns (address[] memory keysOut) {
        uint256 len = map._inner._entries.length;

        keysOut = new address[](len);

        unchecked {
            for (uint256 i; i < len; ++i) {
                keysOut[i] = address(
                    uint160(uint256(map._inner._entries[i]._key))
                );
            }
        }
    }

    function keys(
        UintToAddressMap storage map
    ) internal view returns (uint256[] memory keysOut) {
        uint256 len = map._inner._entries.length;

        keysOut = new uint256[](len);

        unchecked {
            for (uint256 i; i < len; ++i) {
                keysOut[i] = uint256(map._inner._entries[i]._key);
            }
        }
    }

    function values(
        AddressToAddressMap storage map
    ) internal view returns (address[] memory valuesOut) {
        uint256 len = map._inner._entries.length;

        valuesOut = new address[](len);

        unchecked {
            for (uint256 i; i < len; ++i) {
                valuesOut[i] = address(
                    uint160(uint256(map._inner._entries[i]._value))
                );
            }
        }
    }

    function values(
        UintToAddressMap storage map
    ) internal view returns (address[] memory valuesOut) {
        uint256 len = map._inner._entries.length;

        valuesOut = new address[](len);

        unchecked {
            for (uint256 i; i < len; ++i) {
                valuesOut[i] = address(
                    uint160(uint256(map._inner._entries[i]._value))
                );
            }
        }
    }

    function _at(
        Map storage map,
        uint256 index
    ) private view returns (bytes32, bytes32) {
        if (index >= map._entries.length)
            revert EnumerableMap__IndexOutOfBounds();

        MapEntry storage entry = map._entries[index];
        return (entry._key, entry._value);
    }

    function _contains(
        Map storage map,
        bytes32 key
    ) private view returns (bool) {
        return map._indexes[key] != 0;
    }

    function _length(Map storage map) private view returns (uint256) {
        return map._entries.length;
    }

    function _get(Map storage map, bytes32 key) private view returns (bytes32) {
        uint256 keyIndex = map._indexes[key];
        if (keyIndex == 0) revert EnumerableMap__NonExistentKey();
        unchecked {
            return map._entries[keyIndex - 1]._value;
        }
    }

    function _set(
        Map storage map,
        bytes32 key,
        bytes32 value
    ) private returns (bool) {
        uint256 keyIndex = map._indexes[key];

        if (keyIndex == 0) {
            map._entries.push(MapEntry({ _key: key, _value: value }));
            map._indexes[key] = map._entries.length;
            return true;
        } else {
            unchecked {
                map._entries[keyIndex - 1]._value = value;
            }
            return false;
        }
    }

    function _remove(Map storage map, bytes32 key) private returns (bool) {
        uint256 keyIndex = map._indexes[key];

        if (keyIndex != 0) {
            unchecked {
                MapEntry storage last = map._entries[map._entries.length - 1];

                // move last entry to now-vacant index
                map._entries[keyIndex - 1] = last;
                map._indexes[last._key] = keyIndex;
            }

            // clear last index
            map._entries.pop();
            delete map._indexes[key];

            return true;
        } else {
            return false;
        }
    }
}

File 6 of 36 : EnumerableSet.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

/**
 * @title Set implementation with enumeration functions
 * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license)
 */
library EnumerableSet {
    error EnumerableSet__IndexOutOfBounds();

    struct Set {
        bytes32[] _values;
        // 1-indexed to allow 0 to signify nonexistence
        mapping(bytes32 => uint256) _indexes;
    }

    struct Bytes32Set {
        Set _inner;
    }

    struct AddressSet {
        Set _inner;
    }

    struct UintSet {
        Set _inner;
    }

    function at(
        Bytes32Set storage set,
        uint256 index
    ) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    function at(
        AddressSet storage set,
        uint256 index
    ) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    function at(
        UintSet storage set,
        uint256 index
    ) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    function contains(
        Bytes32Set storage set,
        bytes32 value
    ) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    function contains(
        AddressSet storage set,
        address value
    ) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    function contains(
        UintSet storage set,
        uint256 value
    ) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    function indexOf(
        Bytes32Set storage set,
        bytes32 value
    ) internal view returns (uint256) {
        return _indexOf(set._inner, value);
    }

    function indexOf(
        AddressSet storage set,
        address value
    ) internal view returns (uint256) {
        return _indexOf(set._inner, bytes32(uint256(uint160(value))));
    }

    function indexOf(
        UintSet storage set,
        uint256 value
    ) internal view returns (uint256) {
        return _indexOf(set._inner, bytes32(value));
    }

    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    function add(
        Bytes32Set storage set,
        bytes32 value
    ) internal returns (bool) {
        return _add(set._inner, value);
    }

    function add(
        AddressSet storage set,
        address value
    ) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    function remove(
        Bytes32Set storage set,
        bytes32 value
    ) internal returns (bool) {
        return _remove(set._inner, value);
    }

    function remove(
        AddressSet storage set,
        address value
    ) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    function remove(
        UintSet storage set,
        uint256 value
    ) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    function toArray(
        Bytes32Set storage set
    ) internal view returns (bytes32[] memory) {
        return set._inner._values;
    }

    function toArray(
        AddressSet storage set
    ) internal view returns (address[] memory) {
        bytes32[] storage values = set._inner._values;
        address[] storage array;

        assembly {
            array.slot := values.slot
        }

        return array;
    }

    function toArray(
        UintSet storage set
    ) internal view returns (uint256[] memory) {
        bytes32[] storage values = set._inner._values;
        uint256[] storage array;

        assembly {
            array.slot := values.slot
        }

        return array;
    }

    function _at(
        Set storage set,
        uint256 index
    ) private view returns (bytes32) {
        if (index >= set._values.length)
            revert EnumerableSet__IndexOutOfBounds();
        return set._values[index];
    }

    function _contains(
        Set storage set,
        bytes32 value
    ) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    function _indexOf(
        Set storage set,
        bytes32 value
    ) private view returns (uint256) {
        unchecked {
            return set._indexes[value] - 1;
        }
    }

    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    function _add(
        Set storage set,
        bytes32 value
    ) private returns (bool status) {
        if (!_contains(set, value)) {
            set._values.push(value);
            set._indexes[value] = set._values.length;
            status = true;
        }
    }

    function _remove(
        Set storage set,
        bytes32 value
    ) private returns (bool status) {
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            unchecked {
                bytes32 last = set._values[set._values.length - 1];

                // move last value to now-vacant index

                set._values[valueIndex - 1] = last;
                set._indexes[last] = valueIndex;
            }
            // clear last index

            set._values.pop();
            delete set._indexes[value];

            status = true;
        }
    }
}

File 7 of 36 : IERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { IERC165Internal } from './IERC165Internal.sol';

/**
 * @title ERC165 interface registration interface
 * @dev see https://eips.ethereum.org/EIPS/eip-165
 */
interface IERC165 is IERC165Internal {
    /**
     * @notice query whether contract has registered support for given interface
     * @param interfaceId interface id
     * @return bool whether interface is supported
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 8 of 36 : IERC165Internal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

/**
 * @title ERC165 interface registration interface
 */
interface IERC165Internal {

}

File 9 of 36 : IERC721.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { IERC165 } from './IERC165.sol';
import { IERC721Internal } from './IERC721Internal.sol';

/**
 * @title ERC721 interface
 * @dev see https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721 is IERC721Internal, IERC165 {
    /**
     * @notice query the balance of given address
     * @return balance quantity of tokens held
     */
    function balanceOf(address account) external view returns (uint256 balance);

    /**
     * @notice query the owner of given token
     * @param tokenId token to query
     * @return owner token owner
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @notice transfer token between given addresses, checking for ERC721Receiver implementation if applicable
     * @param from sender of token
     * @param to receiver of token
     * @param tokenId token id
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external payable;

    /**
     * @notice transfer token between given addresses, checking for ERC721Receiver implementation if applicable
     * @param from sender of token
     * @param to receiver of token
     * @param tokenId token id
     * @param data data payload
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external payable;

    /**
     * @notice transfer token between given addresses, without checking for ERC721Receiver implementation if applicable
     * @param from sender of token
     * @param to receiver of token
     * @param tokenId token id
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external payable;

    /**
     * @notice grant approval to given account to spend token
     * @param operator address to be approved
     * @param tokenId token to approve
     */
    function approve(address operator, uint256 tokenId) external payable;

    /**
     * @notice get approval status for given token
     * @param tokenId token to query
     * @return operator address approved to spend token
     */
    function getApproved(
        uint256 tokenId
    ) external view returns (address operator);

    /**
     * @notice grant approval to or revoke approval from given account to spend all tokens held by sender
     * @param operator address to be approved
     * @param status approval status
     */
    function setApprovalForAll(address operator, bool status) external;

    /**
     * @notice query approval status of given operator with respect to given address
     * @param account address to query for approval granted
     * @param operator address to query for approval received
     * @return status whether operator is approved to spend tokens held by account
     */
    function isApprovedForAll(
        address account,
        address operator
    ) external view returns (bool status);
}

File 10 of 36 : IERC721Internal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

/**
 * @title Partial ERC721 interface needed by internal functions
 */
interface IERC721Internal {
    event Transfer(
        address indexed from,
        address indexed to,
        uint256 indexed tokenId
    );

    event Approval(
        address indexed owner,
        address indexed operator,
        uint256 indexed tokenId
    );

    event ApprovalForAll(
        address indexed owner,
        address indexed operator,
        bool approved
    );
}

File 11 of 36 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

interface IERC721Receiver {
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

File 12 of 36 : ERC165BaseInternal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { IERC165BaseInternal } from './IERC165BaseInternal.sol';
import { ERC165BaseStorage } from './ERC165BaseStorage.sol';

/**
 * @title ERC165 implementation
 */
abstract contract ERC165BaseInternal is IERC165BaseInternal {
    /**
     * @notice indicates whether an interface is already supported based on the interfaceId
     * @param interfaceId id of interface to check
     * @return bool indicating whether interface is supported
     */
    function _supportsInterface(
        bytes4 interfaceId
    ) internal view virtual returns (bool) {
        return ERC165BaseStorage.layout().supportedInterfaces[interfaceId];
    }

    /**
     * @notice sets status of interface support
     * @param interfaceId id of interface to set status for
     * @param status boolean indicating whether interface will be set as supported
     */
    function _setSupportsInterface(
        bytes4 interfaceId,
        bool status
    ) internal virtual {
        if (interfaceId == 0xffffffff) revert ERC165Base__InvalidInterfaceId();
        ERC165BaseStorage.layout().supportedInterfaces[interfaceId] = status;
    }
}

File 13 of 36 : ERC165BaseStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

library ERC165BaseStorage {
    struct Layout {
        mapping(bytes4 => bool) supportedInterfaces;
    }

    bytes32 internal constant STORAGE_SLOT =
        keccak256('solidstate.contracts.storage.ERC165Base');

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = STORAGE_SLOT;
        assembly {
            l.slot := slot
        }
    }
}

File 14 of 36 : IERC165BaseInternal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IERC165Internal } from '../../../interfaces/IERC165Internal.sol';

interface IERC165BaseInternal is IERC165Internal {
    error ERC165Base__InvalidInterfaceId();
}

File 15 of 36 : IPartiallyPausableInternal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

interface IPartiallyPausableInternal {
    error PartiallyPausable__PartiallyPaused();
    error PartiallyPausable__NotPartiallyPaused();

    event PartiallyPaused(address account, bytes32 key);
    event PartiallyUnpaused(address account, bytes32 key);
}

File 16 of 36 : PartiallyPausableInternal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { IPartiallyPausableInternal } from './IPartiallyPausableInternal.sol';
import { PartiallyPausableStorage } from './PartiallyPausableStorage.sol';

/**
 * @title Internal functions for PartiallyPausable security control module.
 */
abstract contract PartiallyPausableInternal is IPartiallyPausableInternal {
    modifier whenNotPartiallyPaused(bytes32 key) {
        if (_partiallyPaused(key)) revert PartiallyPausable__PartiallyPaused();
        _;
    }

    modifier whenPartiallyPaused(bytes32 key) {
        if (!_partiallyPaused(key))
            revert PartiallyPausable__NotPartiallyPaused();
        _;
    }

    /**
     * @notice query whether contract is paused in the scope of the given key
     * @return status whether contract is paused in the scope of the given key
     */
    function _partiallyPaused(
        bytes32 key
    ) internal view virtual returns (bool status) {
        status = PartiallyPausableStorage.layout().partiallyPaused[key];
    }

    /**
     * @notice pause contract in the scope of given key
     * @param key key whose scope to pause
     */
    function _partiallyPause(
        bytes32 key
    ) internal virtual whenNotPartiallyPaused(key) {
        PartiallyPausableStorage.layout().partiallyPaused[key] = true;
        emit PartiallyPaused(msg.sender, key);
    }

    /**
     * @notice unpause contract in the scope of given key
     * @param key key whose scope to unpause
     */
    function _partiallyUnpause(
        bytes32 key
    ) internal virtual whenPartiallyPaused(key) {
        delete PartiallyPausableStorage.layout().partiallyPaused[key];
        emit PartiallyUnpaused(msg.sender, key);
    }
}

File 17 of 36 : PartiallyPausableStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

library PartiallyPausableStorage {
    struct Layout {
        mapping(bytes32 => bool) partiallyPaused;
    }

    bytes32 internal constant STORAGE_SLOT =
        keccak256('solidstate.contracts.storage.PartiallyPausable');

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = STORAGE_SLOT;
        assembly {
            l.slot := slot
        }
    }
}

File 18 of 36 : IPausableInternal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

interface IPausableInternal {
    error Pausable__Paused();
    error Pausable__NotPaused();

    event Paused(address account);
    event Unpaused(address account);
}

File 19 of 36 : PausableInternal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { IPausableInternal } from './IPausableInternal.sol';
import { PausableStorage } from './PausableStorage.sol';

/**
 * @title Internal functions for Pausable security control module.
 */
abstract contract PausableInternal is IPausableInternal {
    modifier whenNotPaused() {
        if (_paused()) revert Pausable__Paused();
        _;
    }

    modifier whenPaused() {
        if (!_paused()) revert Pausable__NotPaused();
        _;
    }

    /**
     * @notice query whether contract is paused
     * @return status whether contract is paused
     */
    function _paused() internal view virtual returns (bool status) {
        status = PausableStorage.layout().paused;
    }

    /**
     * @notice Triggers paused state, when contract is unpaused.
     */
    function _pause() internal virtual whenNotPaused {
        PausableStorage.layout().paused = true;
        emit Paused(msg.sender);
    }

    /**
     * @notice Triggers unpaused state, when contract is paused.
     */
    function _unpause() internal virtual whenPaused {
        delete PausableStorage.layout().paused;
        emit Unpaused(msg.sender);
    }
}

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

pragma solidity ^0.8.8;

library PausableStorage {
    struct Layout {
        bool paused;
    }

    bytes32 internal constant STORAGE_SLOT =
        keccak256('solidstate.contracts.storage.Pausable');

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = STORAGE_SLOT;
        assembly {
            l.slot := slot
        }
    }
}

File 21 of 36 : ERC721Base.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { IERC721 } from '../../../interfaces/IERC721.sol';
import { IERC721Base } from './IERC721Base.sol';
import { ERC721BaseInternal } from './ERC721BaseInternal.sol';

/**
 * @title Base ERC721 implementation, excluding optional extensions
 * @dev inheritor must either implement ERC165 supportsInterface or inherit ERC165Base
 */
abstract contract ERC721Base is IERC721Base, ERC721BaseInternal {
    /**
     * @inheritdoc IERC721
     */
    function balanceOf(address account) external view returns (uint256) {
        return _balanceOf(account);
    }

    /**
     * @inheritdoc IERC721
     */
    function ownerOf(uint256 tokenId) external view returns (address) {
        return _ownerOf(tokenId);
    }

    /**
     * @inheritdoc IERC721
     */
    function getApproved(uint256 tokenId) external view returns (address) {
        return _getApproved(tokenId);
    }

    /**
     * @inheritdoc IERC721
     */
    function isApprovedForAll(
        address account,
        address operator
    ) external view returns (bool) {
        return _isApprovedForAll(account, operator);
    }

    /**
     * @inheritdoc IERC721
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external payable {
        _transferFrom(from, to, tokenId);
    }

    /**
     * @inheritdoc IERC721
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external payable {
        _safeTransferFrom(from, to, tokenId);
    }

    /**
     * @inheritdoc IERC721
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) external payable {
        _safeTransferFrom(from, to, tokenId, data);
    }

    /**
     * @inheritdoc IERC721
     */
    function approve(address operator, uint256 tokenId) external payable {
        _approve(operator, tokenId);
    }

    /**
     * @inheritdoc IERC721
     */
    function setApprovalForAll(address operator, bool status) external {
        _setApprovalForAll(operator, status);
    }
}

File 22 of 36 : ERC721BaseInternal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { IERC721Receiver } from '../../../interfaces/IERC721Receiver.sol';
import { EnumerableMap } from '../../../data/EnumerableMap.sol';
import { EnumerableSet } from '../../../data/EnumerableSet.sol';
import { AddressUtils } from '../../../utils/AddressUtils.sol';
import { IERC721BaseInternal } from './IERC721BaseInternal.sol';
import { ERC721BaseStorage } from './ERC721BaseStorage.sol';

/**
 * @title Base ERC721 internal functions
 */
abstract contract ERC721BaseInternal is IERC721BaseInternal {
    using AddressUtils for address;
    using EnumerableMap for EnumerableMap.UintToAddressMap;
    using EnumerableSet for EnumerableSet.UintSet;

    function _balanceOf(
        address account
    ) internal view virtual returns (uint256) {
        if (account == address(0)) revert ERC721Base__BalanceQueryZeroAddress();
        return ERC721BaseStorage.layout().holderTokens[account].length();
    }

    function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
        address owner = ERC721BaseStorage.layout().tokenOwners.get(tokenId);
        if (owner == address(0)) revert ERC721Base__InvalidOwner();
        return owner;
    }

    function _exists(uint256 tokenId) internal view virtual returns (bool) {
        return ERC721BaseStorage.layout().tokenOwners.contains(tokenId);
    }

    function _getApproved(
        uint256 tokenId
    ) internal view virtual returns (address) {
        if (!_exists(tokenId)) revert ERC721Base__NonExistentToken();

        return ERC721BaseStorage.layout().tokenApprovals[tokenId];
    }

    function _isApprovedForAll(
        address account,
        address operator
    ) internal view virtual returns (bool) {
        return ERC721BaseStorage.layout().operatorApprovals[account][operator];
    }

    function _isApprovedOrOwner(
        address spender,
        uint256 tokenId
    ) internal view virtual returns (bool) {
        if (!_exists(tokenId)) revert ERC721Base__NonExistentToken();

        address owner = _ownerOf(tokenId);

        return (spender == owner ||
            _getApproved(tokenId) == spender ||
            _isApprovedForAll(owner, spender));
    }

    function _mint(address to, uint256 tokenId) internal virtual {
        if (to == address(0)) revert ERC721Base__MintToZeroAddress();
        if (_exists(tokenId)) revert ERC721Base__TokenAlreadyMinted();

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

        ERC721BaseStorage.Layout storage l = ERC721BaseStorage.layout();

        l.holderTokens[to].add(tokenId);
        l.tokenOwners.set(tokenId, to);

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

    function _safeMint(address to, uint256 tokenId) internal virtual {
        _safeMint(to, tokenId, '');
    }

    function _safeMint(
        address to,
        uint256 tokenId,
        bytes memory data
    ) internal virtual {
        _mint(to, tokenId);
        if (!_checkOnERC721Received(address(0), to, tokenId, data))
            revert ERC721Base__ERC721ReceiverNotImplemented();
    }

    function _burn(uint256 tokenId) internal virtual {
        address owner = _ownerOf(tokenId);

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

        ERC721BaseStorage.Layout storage l = ERC721BaseStorage.layout();

        l.holderTokens[owner].remove(tokenId);
        l.tokenOwners.remove(tokenId);

        l.tokenApprovals[tokenId] = address(0);

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

    function _transfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {
        address owner = _ownerOf(tokenId);

        if (owner != from) revert ERC721Base__NotTokenOwner();
        if (to == address(0)) revert ERC721Base__TransferToZeroAddress();

        _beforeTokenTransfer(from, to, tokenId);

        ERC721BaseStorage.Layout storage l = ERC721BaseStorage.layout();

        l.holderTokens[from].remove(tokenId);
        l.holderTokens[to].add(tokenId);
        l.tokenOwners.set(tokenId, to);
        l.tokenApprovals[tokenId] = address(0);

        emit Approval(owner, address(0), tokenId);
        emit Transfer(from, to, tokenId);
    }

    function _transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {
        _handleTransferMessageValue(from, to, tokenId, msg.value);
        if (!_isApprovedOrOwner(msg.sender, tokenId))
            revert ERC721Base__NotOwnerOrApproved();
        _transfer(from, to, tokenId);
    }

    function _safeTransfer(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) internal virtual {
        _transfer(from, to, tokenId);
        if (!_checkOnERC721Received(from, to, tokenId, data))
            revert ERC721Base__ERC721ReceiverNotImplemented();
    }

    function _safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {
        _safeTransferFrom(from, to, tokenId, '');
    }

    function _safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) internal virtual {
        _handleTransferMessageValue(from, to, tokenId, msg.value);
        if (!_isApprovedOrOwner(msg.sender, tokenId))
            revert ERC721Base__NotOwnerOrApproved();
        _safeTransfer(from, to, tokenId, data);
    }

    function _approve(address operator, uint256 tokenId) internal virtual {
        _handleApproveMessageValue(operator, tokenId, msg.value);

        address owner = _ownerOf(tokenId);

        if (operator == owner) revert ERC721Base__SelfApproval();
        if (msg.sender != owner && !_isApprovedForAll(owner, msg.sender))
            revert ERC721Base__NotOwnerOrApproved();

        ERC721BaseStorage.layout().tokenApprovals[tokenId] = operator;
        emit Approval(owner, operator, tokenId);
    }

    function _setApprovalForAll(
        address operator,
        bool status
    ) internal virtual {
        if (operator == msg.sender) revert ERC721Base__SelfApproval();
        ERC721BaseStorage.layout().operatorApprovals[msg.sender][
            operator
        ] = status;
        emit ApprovalForAll(msg.sender, operator, status);
    }

    function _checkOnERC721Received(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) internal virtual returns (bool) {
        if (!to.isContract()) {
            return true;
        }

        bytes memory returnData = to.functionCall(
            abi.encodeWithSelector(
                IERC721Receiver(to).onERC721Received.selector,
                msg.sender,
                from,
                tokenId,
                data
            ),
            'ERC721: transfer to non ERC721Receiver implementer'
        );

        bytes4 returnValue = abi.decode(returnData, (bytes4));
        return returnValue == type(IERC721Receiver).interfaceId;
    }

    /**
     * @notice ERC721 hook, called before externally called approvals for processing of included message value
     * @param operator beneficiary of approval
     * @param tokenId id of transferred token
     * @param value message value
     */
    function _handleApproveMessageValue(
        address operator,
        uint256 tokenId,
        uint256 value
    ) internal virtual {}

    /**
     * @notice ERC721 hook, called before externally called transfers for processing of included message value
     * @param from sender of token
     * @param to receiver of token
     * @param tokenId id of transferred token
     * @param value message value
     */
    function _handleTransferMessageValue(
        address from,
        address to,
        uint256 tokenId,
        uint256 value
    ) internal virtual {}

    /**
     * @notice ERC721 hook, called before all transfers including mint and burn
     * @dev function should be overridden and new implementation must call super
     * @param from sender of token
     * @param to receiver of token
     * @param tokenId id of transferred token
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {}
}

File 23 of 36 : ERC721BaseStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { EnumerableMap } from '../../../data/EnumerableMap.sol';
import { EnumerableSet } from '../../../data/EnumerableSet.sol';

library ERC721BaseStorage {
    using EnumerableSet for EnumerableSet.UintSet;
    using EnumerableMap for EnumerableMap.UintToAddressMap;

    bytes32 internal constant STORAGE_SLOT =
        keccak256('solidstate.contracts.storage.ERC721Base');

    struct Layout {
        EnumerableMap.UintToAddressMap tokenOwners;
        mapping(address => EnumerableSet.UintSet) holderTokens;
        mapping(uint256 => address) tokenApprovals;
        mapping(address => mapping(address => bool)) operatorApprovals;
    }

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = STORAGE_SLOT;
        assembly {
            l.slot := slot
        }
    }
}

File 24 of 36 : IERC721Base.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { IERC721 } from '../../../interfaces/IERC721.sol';
import { IERC721BaseInternal } from './IERC721BaseInternal.sol';

/**
 * @title ERC721 base interface
 */
interface IERC721Base is IERC721BaseInternal, IERC721 {

}

File 25 of 36 : IERC721BaseInternal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { IERC721Internal } from '../../../interfaces/IERC721Internal.sol';

/**
 * @title ERC721 base interface
 */
interface IERC721BaseInternal is IERC721Internal {
    error ERC721Base__NotOwnerOrApproved();
    error ERC721Base__SelfApproval();
    error ERC721Base__BalanceQueryZeroAddress();
    error ERC721Base__ERC721ReceiverNotImplemented();
    error ERC721Base__InvalidOwner();
    error ERC721Base__MintToZeroAddress();
    error ERC721Base__NonExistentToken();
    error ERC721Base__NotTokenOwner();
    error ERC721Base__TokenAlreadyMinted();
    error ERC721Base__TransferToZeroAddress();
}

File 26 of 36 : ERC721Enumerable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { EnumerableMap } from '../../../data/EnumerableMap.sol';
import { EnumerableSet } from '../../../data/EnumerableSet.sol';
import { ERC721BaseStorage } from '../base/ERC721BaseStorage.sol';
import { IERC721Enumerable } from './IERC721Enumerable.sol';
import { ERC721EnumerableInternal } from './ERC721EnumerableInternal.sol';

abstract contract ERC721Enumerable is
    IERC721Enumerable,
    ERC721EnumerableInternal
{
    using EnumerableMap for EnumerableMap.UintToAddressMap;
    using EnumerableSet for EnumerableSet.UintSet;

    /**
     * @inheritdoc IERC721Enumerable
     */
    function totalSupply() public view returns (uint256) {
        return _totalSupply();
    }

    /**
     * @inheritdoc IERC721Enumerable
     */
    function tokenOfOwnerByIndex(
        address owner,
        uint256 index
    ) public view returns (uint256) {
        return _tokenOfOwnerByIndex(owner, index);
    }

    /**
     * @inheritdoc IERC721Enumerable
     */
    function tokenByIndex(uint256 index) public view returns (uint256) {
        return _tokenByIndex(index);
    }
}

File 27 of 36 : ERC721EnumerableInternal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { EnumerableMap } from '../../../data/EnumerableMap.sol';
import { EnumerableSet } from '../../../data/EnumerableSet.sol';
import { ERC721BaseStorage } from '../base/ERC721BaseStorage.sol';

abstract contract ERC721EnumerableInternal {
    using EnumerableMap for EnumerableMap.UintToAddressMap;
    using EnumerableSet for EnumerableSet.UintSet;

    /**
     * @notice TODO
     */
    function _totalSupply() internal view returns (uint256) {
        return ERC721BaseStorage.layout().tokenOwners.length();
    }

    /**
     * @notice TODO
     */
    function _tokenOfOwnerByIndex(
        address owner,
        uint256 index
    ) internal view returns (uint256) {
        return ERC721BaseStorage.layout().holderTokens[owner].at(index);
    }

    /**
     * @notice TODO
     */
    function _tokenByIndex(
        uint256 index
    ) internal view returns (uint256 tokenId) {
        (tokenId, ) = ERC721BaseStorage.layout().tokenOwners.at(index);
    }
}

File 28 of 36 : IERC721Enumerable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

interface IERC721Enumerable {
    /**
     * @notice get total token supply
     * @return total supply
     */
    function totalSupply() external view returns (uint256);

    /**
     * @notice get token of given owner at given internal storage index
     * @param owner token holder to query
     * @param index position in owner's token list to query
     * @return tokenId id of retrieved token
     */
    function tokenOfOwnerByIndex(
        address owner,
        uint256 index
    ) external view returns (uint256 tokenId);

    /**
     * @notice get token at given internal storage index
     * @param index position in global token list to query
     * @return tokenId id of retrieved token
     */
    function tokenByIndex(
        uint256 index
    ) external view returns (uint256 tokenId);
}

File 29 of 36 : ERC721Metadata.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { ERC721MetadataInternal } from './ERC721MetadataInternal.sol';
import { IERC721Metadata } from './IERC721Metadata.sol';

/**
 * @title ERC721 metadata extensions
 */
abstract contract ERC721Metadata is IERC721Metadata, ERC721MetadataInternal {
    /**
     * @notice inheritdoc IERC721Metadata
     */
    function name() external view virtual returns (string memory) {
        return _name();
    }

    /**
     * @notice inheritdoc IERC721Metadata
     */
    function symbol() external view virtual returns (string memory) {
        return _symbol();
    }

    /**
     * @notice inheritdoc IERC721Metadata
     */
    function tokenURI(
        uint256 tokenId
    ) external view virtual returns (string memory) {
        return _tokenURI(tokenId);
    }

    /**
     * @inheritdoc ERC721MetadataInternal
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual override {
        super._beforeTokenTransfer(from, to, tokenId);
    }
}

File 30 of 36 : ERC721MetadataInternal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { UintUtils } from '../../../utils/UintUtils.sol';
import { ERC721BaseStorage } from '../base/ERC721BaseStorage.sol';
import { ERC721BaseInternal } from '../base/ERC721Base.sol';
import { IERC721MetadataInternal } from './IERC721MetadataInternal.sol';
import { ERC721MetadataStorage } from './ERC721MetadataStorage.sol';

/**
 * @title ERC721Metadata internal functions
 */
abstract contract ERC721MetadataInternal is
    IERC721MetadataInternal,
    ERC721BaseInternal
{
    using UintUtils for uint256;

    /**
     * @notice get token name
     * @return token name
     */
    function _name() internal view virtual returns (string memory) {
        return ERC721MetadataStorage.layout().name;
    }

    /**
     * @notice get token symbol
     * @return token symbol
     */
    function _symbol() internal view virtual returns (string memory) {
        return ERC721MetadataStorage.layout().symbol;
    }

    /**
     * @notice get generated URI for given token
     * @return token URI
     */
    function _tokenURI(
        uint256 tokenId
    ) internal view virtual returns (string memory) {
        if (!_exists(tokenId)) revert ERC721Metadata__NonExistentToken();

        ERC721MetadataStorage.Layout storage l = ERC721MetadataStorage.layout();

        string memory tokenIdURI = l.tokenURIs[tokenId];
        string memory baseURI = l.baseURI;

        if (bytes(baseURI).length == 0) {
            return tokenIdURI;
        } else if (bytes(tokenIdURI).length > 0) {
            return string(abi.encodePacked(baseURI, tokenIdURI));
        } else {
            return string(abi.encodePacked(baseURI, tokenId.toString()));
        }
    }

    /**
     * @notice ERC721 hook: clear per-token URI data on burn
     * @inheritdoc ERC721BaseInternal
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual override {
        super._beforeTokenTransfer(from, to, tokenId);

        if (to == address(0)) {
            delete ERC721MetadataStorage.layout().tokenURIs[tokenId];
        }
    }
}

File 31 of 36 : ERC721MetadataStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

library ERC721MetadataStorage {
    bytes32 internal constant STORAGE_SLOT =
        keccak256('solidstate.contracts.storage.ERC721Metadata');

    struct Layout {
        string name;
        string symbol;
        string baseURI;
        mapping(uint256 => string) tokenURIs;
    }

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = STORAGE_SLOT;
        assembly {
            l.slot := slot
        }
    }
}

File 32 of 36 : IERC721Metadata.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { IERC721MetadataInternal } from './IERC721MetadataInternal.sol';

/**
 * @title ERC721Metadata interface
 */
interface IERC721Metadata is IERC721MetadataInternal {
    /**
     * @notice get token name
     * @return token name
     */
    function name() external view returns (string memory);

    /**
     * @notice get token symbol
     * @return token symbol
     */
    function symbol() external view returns (string memory);

    /**
     * @notice get generated URI for given token
     * @return token URI
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

File 33 of 36 : IERC721MetadataInternal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { IERC721BaseInternal } from '../base/IERC721BaseInternal.sol';

/**
 * @title ERC721Metadata internal interface
 */
interface IERC721MetadataInternal is IERC721BaseInternal {
    error ERC721Metadata__NonExistentToken();
}

File 34 of 36 : AddressUtils.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { UintUtils } from './UintUtils.sol';

library AddressUtils {
    using UintUtils for uint256;

    error AddressUtils__InsufficientBalance();
    error AddressUtils__NotContract();
    error AddressUtils__SendValueFailed();

    function toString(address account) internal pure returns (string memory) {
        return uint256(uint160(account)).toHexString(20);
    }

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

    function sendValue(address payable account, uint256 amount) internal {
        (bool success, ) = account.call{ value: amount }('');
        if (!success) revert AddressUtils__SendValueFailed();
    }

    function functionCall(
        address target,
        bytes memory data
    ) internal returns (bytes memory) {
        return
            functionCall(target, data, 'AddressUtils: failed low-level call');
    }

    function functionCall(
        address target,
        bytes memory data,
        string memory error
    ) internal returns (bytes memory) {
        return _functionCallWithValue(target, data, 0, error);
    }

    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return
            functionCallWithValue(
                target,
                data,
                value,
                'AddressUtils: failed low-level call with value'
            );
    }

    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory error
    ) internal returns (bytes memory) {
        if (value > address(this).balance)
            revert AddressUtils__InsufficientBalance();
        return _functionCallWithValue(target, data, value, error);
    }

    /**
     * @notice execute arbitrary external call with limited gas usage and amount of copied return data
     * @dev derived from https://github.com/nomad-xyz/ExcessivelySafeCall (MIT License)
     * @param target recipient of call
     * @param gasAmount gas allowance for call
     * @param value native token value to include in call
     * @param maxCopy maximum number of bytes to copy from return data
     * @param data encoded call data
     * @return success whether call is successful
     * @return returnData copied return data
     */
    function excessivelySafeCall(
        address target,
        uint256 gasAmount,
        uint256 value,
        uint16 maxCopy,
        bytes memory data
    ) internal returns (bool success, bytes memory returnData) {
        returnData = new bytes(maxCopy);

        assembly {
            // execute external call via assembly to avoid automatic copying of return data
            success := call(
                gasAmount,
                target,
                value,
                add(data, 0x20),
                mload(data),
                0,
                0
            )

            // determine whether to limit amount of data to copy
            let toCopy := returndatasize()

            if gt(toCopy, maxCopy) {
                toCopy := maxCopy
            }

            // store the length of the copied bytes
            mstore(returnData, toCopy)

            // copy the bytes from returndata[0:toCopy]
            returndatacopy(add(returnData, 0x20), 0, toCopy)
        }
    }

    function _functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory error
    ) private returns (bytes memory) {
        if (!isContract(target)) revert AddressUtils__NotContract();

        (bool success, bytes memory returnData) = target.call{ value: value }(
            data
        );

        if (success) {
            return returnData;
        } else if (returnData.length > 0) {
            assembly {
                let returnData_size := mload(returnData)
                revert(add(32, returnData), returnData_size)
            }
        } else {
            revert(error);
        }
    }
}

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

pragma solidity ^0.8.8;

/**
 * @title utility functions for uint256 operations
 * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts/ (MIT license)
 */
library UintUtils {
    error UintUtils__InsufficientHexLength();

    bytes16 private constant HEX_SYMBOLS = '0123456789abcdef';

    function add(uint256 a, int256 b) internal pure returns (uint256) {
        return b < 0 ? sub(a, -b) : a + uint256(b);
    }

    function sub(uint256 a, int256 b) internal pure returns (uint256) {
        return b < 0 ? add(a, -b) : a - uint256(b);
    }

    function toString(uint256 value) internal pure returns (string memory) {
        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);
    }

    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return '0x00';
        }

        uint256 length = 0;

        for (uint256 temp = value; temp != 0; temp >>= 8) {
            unchecked {
                length++;
            }
        }

        return toHexString(value, 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';

        unchecked {
            for (uint256 i = 2 * length + 1; i > 1; --i) {
                buffer[i] = HEX_SYMBOLS[value & 0xf];
                value >>= 4;
            }
        }

        if (value != 0) revert UintUtils__InsufficientHexLength();

        return string(buffer);
    }
}

File 36 of 36 : LibSilksHorseDiamond.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;

import {EnumerableSet} from "@solidstate/contracts/data/EnumerableSet.sol";

struct SeasonInfo {
    uint256 seasonId;
    string description;
    bool paused;
    bool valid;
}

struct PayoutTier {
    uint256 tierId;
    string description;
    uint256 price;
    uint256 maxPerTx;
    uint256 payoutPct;
    uint256 maxSupply;
    bool paused;
    bool valid;
}

enum MintMethod {
    PURCHASE,
    AIRDROP,
    EXTERNAL_MINT
}

bytes32 constant CONTRACT_ADMIN_ROLE = keccak256("silks.contracts.roles.ContractAdminRole");
bytes32 constant MINT_ADMIN_ROLE = keccak256("silks.contracts.roles.MintAdminRole");

bytes32 constant HORSE_PURCHASING_PAUSED = keccak256('silks.contracts.paused.HorsePurchasing');

error InvalidAddress(address _address);
error InvalidSeason(uint256 _sent);
error InvalidPayoutTier(uint256 _sent);
error InvalidTokenId(uint256 _sent);
error InvalidIntValue(string _reason, uint256 _sent, uint256 _expected);
error InvalidStringValue(string _reason, string _sent, string _expected);
error InvalidExternalMintAddress(address _sender);
error MaxHorsesPerWalletExceeded(address _walletAddress);
error PayoutTierMaxSupplyExceeded(uint256 _payoutTier);
error MintFailed(string _reason, uint256 _seasonId, uint256 _payoutTier, uint256 _quantity, MintMethod _method, address _to);

library LibSilksHorseDiamond {
    bytes32 internal constant STORAGE_SLOT = keccak256('silks.contracts.storage.SilksHorseDiamond');
    
    struct Layout {
        mapping(uint256 => EnumerableSet.UintSet) seasonHorses;
        mapping(uint256 => SeasonInfo) seasonInfos;
        mapping(uint256 => PayoutTier) payoutTiers;
        mapping(uint256 => PayoutTier) horsePayoutTier;
        mapping(uint256 => EnumerableSet.UintSet) payoutTierHorses;
        mapping(uint256 => SeasonInfo) horseSeasonInfo;
        mapping(address => bool) allowedExternalMintAddresses;
        uint256 maxHorsesPerWallet;
        uint256 nextAvailableTokenId;
    }
    
    function layout()
    internal
    pure
    returns (
        Layout storage l
    ) {
        bytes32 slot = STORAGE_SLOT;
        assembly {
            l.slot := slot
        }
    }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[],"name":"AddressUtils__NotContract","type":"error"},{"inputs":[],"name":"ERC165Base__InvalidInterfaceId","type":"error"},{"inputs":[],"name":"ERC721Base__BalanceQueryZeroAddress","type":"error"},{"inputs":[],"name":"ERC721Base__ERC721ReceiverNotImplemented","type":"error"},{"inputs":[],"name":"ERC721Base__InvalidOwner","type":"error"},{"inputs":[],"name":"ERC721Base__MintToZeroAddress","type":"error"},{"inputs":[],"name":"ERC721Base__NonExistentToken","type":"error"},{"inputs":[],"name":"ERC721Base__NotOwnerOrApproved","type":"error"},{"inputs":[],"name":"ERC721Base__NotTokenOwner","type":"error"},{"inputs":[],"name":"ERC721Base__SelfApproval","type":"error"},{"inputs":[],"name":"ERC721Base__TokenAlreadyMinted","type":"error"},{"inputs":[],"name":"ERC721Base__TransferToZeroAddress","type":"error"},{"inputs":[],"name":"ERC721Metadata__NonExistentToken","type":"error"},{"inputs":[],"name":"EnumerableMap__IndexOutOfBounds","type":"error"},{"inputs":[],"name":"EnumerableMap__NonExistentKey","type":"error"},{"inputs":[],"name":"EnumerableSet__IndexOutOfBounds","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"}],"name":"InvalidExternalMintAddress","type":"error"},{"inputs":[{"internalType":"string","name":"_reason","type":"string"},{"internalType":"uint256","name":"_sent","type":"uint256"},{"internalType":"uint256","name":"_expected","type":"uint256"}],"name":"InvalidIntValue","type":"error"},{"inputs":[{"internalType":"uint256","name":"_sent","type":"uint256"}],"name":"InvalidPayoutTier","type":"error"},{"inputs":[{"internalType":"uint256","name":"_sent","type":"uint256"}],"name":"InvalidSeason","type":"error"},{"inputs":[{"internalType":"address","name":"_walletAddress","type":"address"}],"name":"MaxHorsesPerWalletExceeded","type":"error"},{"inputs":[{"internalType":"string","name":"_reason","type":"string"},{"internalType":"uint256","name":"_seasonId","type":"uint256"},{"internalType":"uint256","name":"_payoutTier","type":"uint256"},{"internalType":"uint256","name":"_quantity","type":"uint256"},{"internalType":"enum MintMethod","name":"_method","type":"uint8"},{"internalType":"address","name":"_to","type":"address"}],"name":"MintFailed","type":"error"},{"inputs":[],"name":"PartiallyPausable__NotPartiallyPaused","type":"error"},{"inputs":[],"name":"PartiallyPausable__PartiallyPaused","type":"error"},{"inputs":[],"name":"Pausable__NotPaused","type":"error"},{"inputs":[],"name":"Pausable__Paused","type":"error"},{"inputs":[{"internalType":"uint256","name":"_payoutTier","type":"uint256"}],"name":"PayoutTierMaxSupplyExceeded","type":"error"},{"inputs":[],"name":"UintUtils__InsufficientHexLength","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","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":"enum MintMethod","name":"method","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"seasonId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"payoutTier","type":"uint256"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"HorseMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"PartiallyPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"PartiallyUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","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":"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":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[{"internalType":"uint256","name":"_seasonId","type":"uint256"},{"internalType":"uint256","name":"_payoutTier","type":"uint256"},{"internalType":"uint256","name":"_quantity","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"airdrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_seasonId","type":"uint256"},{"internalType":"uint256","name":"_payoutTier","type":"uint256"},{"internalType":"uint256","name":"_quantity","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"externalMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_seasonId","type":"uint256"},{"internalType":"uint256","name":"_payoutTier","type":"uint256"},{"internalType":"uint256","name":"_quantity","type":"uint256"}],"name":"purchase","outputs":[],"stateMutability":"payable","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":"payable","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":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"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":"","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":"payable","type":"function"}]

608060405234801561001057600080fd5b50613e84806100206000396000f3fe6080604052600436106101145760003560e01c80636352211e116100a0578063b88d4fde11610064578063b88d4fde146103a1578063ba0a44b9146103bd578063c87b56dd146103e6578063e985e9c514610423578063fd152ee71461046057610114565b80636352211e146102b757806370a08231146102f457806395d89b41146103315780639b8b93051461035c578063a22cb4651461037857610114565b806318160ddd116100e757806318160ddd146101da57806323b872dd146102055780632f745c591461022157806342842e0e1461025e5780634f6ccce71461027a57610114565b806301ffc9a71461011957806306fdde0314610156578063081812fc14610181578063095ea7b3146101be575b600080fd5b34801561012557600080fd5b50610140600480360381019061013b9190612d58565b610489565b60405161014d9190612da0565b60405180910390f35b34801561016257600080fd5b5061016b61049b565b6040516101789190612e4b565b60405180910390f35b34801561018d57600080fd5b506101a860048036038101906101a39190612ea3565b6104aa565b6040516101b59190612f11565b60405180910390f35b6101d860048036038101906101d39190612f58565b6104bc565b005b3480156101e657600080fd5b506101ef6104ca565b6040516101fc9190612fa7565b60405180910390f35b61021f600480360381019061021a9190612fc2565b6104d9565b005b34801561022d57600080fd5b5061024860048036038101906102439190612f58565b6104e9565b6040516102559190612fa7565b60405180910390f35b61027860048036038101906102739190612fc2565b6104fd565b005b34801561028657600080fd5b506102a1600480360381019061029c9190612ea3565b61050d565b6040516102ae9190612fa7565b60405180910390f35b3480156102c357600080fd5b506102de60048036038101906102d99190612ea3565b61051f565b6040516102eb9190612f11565b60405180910390f35b34801561030057600080fd5b5061031b60048036038101906103169190613015565b610531565b6040516103289190612fa7565b60405180910390f35b34801561033d57600080fd5b50610346610543565b6040516103539190612e4b565b60405180910390f35b61037660048036038101906103719190613042565b610552565b005b34801561038457600080fd5b5061039f600480360381019061039a91906130c1565b6106e2565b005b6103bb60048036038101906103b69190613236565b6106f0565b005b3480156103c957600080fd5b506103e460048036038101906103df91906132b9565b610702565b005b3480156103f257600080fd5b5061040d60048036038101906104089190612ea3565b6107b3565b60405161041a9190612e4b565b60405180910390f35b34801561042f57600080fd5b5061044a60048036038101906104459190613320565b6107c5565b6040516104579190612da0565b60405180910390f35b34801561046c57600080fd5b50610487600480360381019061048291906132b9565b6107d9565b005b600061049482610818565b9050919050565b60606104a5610889565b905090565b60006104b582610924565b9050919050565b6104c682826109a9565b5050565b60006104d4610b5b565b905090565b6104e4838383610b75565b505050565b60006104f58383610bd1565b905092915050565b610508838383610c35565b505050565b600061051882610c55565b9050919050565b600061052a82610c7e565b9050919050565b600061053c82610d0f565b9050919050565b606061054d610dcd565b905090565b61055a610e68565b15610591576040517f059519da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fbaf1a8b39218df0710a90513bf0dcf53bf025fceec7598c2d0a27eec92649faa6105bb81610e88565b156105f2576040517fd73a2c8700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006105fc610ebb565b600201600085815260200190815260200160002090506000838260020154610624919061338f565b905034811461066c5734816040517f065a653700000000000000000000000000000000000000000000000000000000815260040161066392919061341d565b60405180910390fd5b60008260030154141580156106845750816003015484115b156106cc578382600301546040517f065a65370000000000000000000000000000000000000000000000000000000081526004016106c39291906134a5565b60405180910390fd5b6106da868686600033610ee8565b505050505050565b6106ec82826113d3565b5050565b6106fc8484848461153e565b50505050565b600061070c610ebb565b60060160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1690508061079e57336040517f43839dab0000000000000000000000000000000000000000000000000000000081526004016107959190612f11565b60405180910390fd5b6107ac858585600286610ee8565b5050505050565b60606107be8261159c565b9050919050565b60006107d1838361179b565b905092915050565b7f7dc7a9428f8cc2d7d0a73dfc0f0d4791fa005321ee0ba5d966a60588b12e576c61080381611838565b610811858585600186610ee8565b5050505050565b6000610822611845565b6000016000837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060009054906101000a900460ff169050919050565b6060610893611872565b60000180546108a190613510565b80601f01602080910402602001604051908101604052809291908181526020018280546108cd90613510565b801561091a5780601f106108ef5761010080835404028352916020019161091a565b820191906000526020600020905b8154815290600101906020018083116108fd57829003601f168201915b5050505050905090565b600061092f8261189f565b610965576040517fc1b843ef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61096d6118c5565b600301600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b6109b48282346118f2565b60006109bf82610c7e565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610a26576040517f424a22cb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015610a695750610a67813361179b565b155b15610aa0576040517f2f5de44f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610aa96118c5565b600301600084815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550818373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050565b6000610b70610b686118c5565b6000016118f7565b905090565b610b818383833461190c565b610b8b3382611912565b610bc1576040517f2f5de44f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bcc8383836119e7565b505050565b6000610c2d82610bdf6118c5565b60020160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020611caa90919063ffffffff16565b905092915050565b610c508383836040518060200160405280600081525061153e565b505050565b6000610c7482610c636118c5565b600001611cc490919063ffffffff16565b5080915050919050565b600080610c9e83610c8d6118c5565b600001611cf090919063ffffffff16565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610d06576040517f7e1a7d8b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80915050919050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610d76576040517f810ff97000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610dc6610d816118c5565b60020160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020611d0d565b9050919050565b6060610dd7611872565b6001018054610de590613510565b80601f0160208091040260200160405190810160405280929190818152602001828054610e1190613510565b8015610e5e5780601f10610e3357610100808354040283529160200191610e5e565b820191906000526020600020905b815481529060010190602001808311610e4157829003601f168201915b5050505050905090565b6000610e72611d22565b60000160009054906101000a900460ff16905090565b6000610e92611d4f565b600001600083815260200190815260200160002060009054906101000a900460ff169050919050565b6000807fa9766cf30247385bd274fe73461f870e9ad8351016f172911cfa198f44cc28e590508091505090565b6000610ef2610ebb565b600701549050600081118015610f1a57508084610f0e84610d0f565b610f189190613541565b115b15610f5c57816040517ffe26af11000000000000000000000000000000000000000000000000000000008152600401610f539190612f11565b60405180910390fd5b6000610f66610ebb565b600101600088815260200190815260200160002090508060020160009054906101000a900460ff1680610fa857508060020160019054906101000a900460ff16155b15610fea57866040517faa7ed920000000000000000000000000000000000000000000000000000000008152600401610fe19190612fa7565b60405180910390fd5b6000610ff4610ebb565b600201600088815260200190815260200160002090508060060160009054906101000a900460ff168061103657508060060160019054906101000a900460ff16155b1561107857866040517fb54df80b00000000000000000000000000000000000000000000000000000000815260040161106f9190612fa7565b60405180910390fd5b6000611082610ebb565b905060008160040160008a81526020019081526020016000209050600083600501541180156110c757508260050154886110bb83611d0d565b6110c59190613541565b115b1561110957886040517fa613fc860000000000000000000000000000000000000000000000000000000081526004016111009190612fa7565b60405180910390fd5b60008260000160008c8152602001908152602001600020905060008360080154905060005b8a8110156113b057600081836111449190613541565b90506111598185611d7c90919063ffffffff16565b6111a2578d8d8d8d8d6040517fe60b992a000000000000000000000000000000000000000000000000000000008152600401611199959493929190613638565b60405180910390fd5b6111b58186611d7c90919063ffffffff16565b6111fe578d8d8d8d8d6040517fe60b992a0000000000000000000000000000000000000000000000000000000081526004016111f5959493929190613710565b60405180910390fd5b8686600301600083815260200190815260200160002060008201548160000155600182018160010190816112329190613938565b50600282015481600201556003820154816003015560048201548160040155600582015481600501556006820160009054906101000a900460ff168160060160006101000a81548160ff0219169083151502179055506006820160019054906101000a900460ff168160060160016101000a81548160ff0219169083151502179055509050508786600501600083815260200190815260200160002060008201548160000155600182018160010190816112ec9190613938565b506002820160009054906101000a900460ff168160020160006101000a81548160ff0219169083151502179055506002820160019054906101000a900460ff168160020160016101000a81548160ff0219169083151502179055509050506113548a82611d96565b8c8e8c6002811115611369576113686135c1565b5b7f78da9a89ac3627c32a75c80f4320c7ced2fc3400714cf5a1f7d5668dda3d8d578d8560405161139a929190613a20565b60405180910390a481806001019250505061112e565b80826113bc9190613541565b856008018190555050505050505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611438576040517f424a22cb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806114416118c5565b60040160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31836040516115329190612da0565b60405180910390a35050565b61154a8484843461190c565b6115543383611912565b61158a576040517f2f5de44f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61159684848484611db4565b50505050565b60606115a78261189f565b6115dd576040517f2382d38000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006115e7611872565b90506000816003016000858152602001908152602001600020805461160b90613510565b80601f016020809104026020016040519081016040528092919081815260200182805461163790613510565b80156116845780601f1061165957610100808354040283529160200191611684565b820191906000526020600020905b81548152906001019060200180831161166757829003601f168201915b50505050509050600082600201805461169c90613510565b80601f01602080910402602001604051908101604052809291908181526020018280546116c890613510565b80156117155780601f106116ea57610100808354040283529160200191611715565b820191906000526020600020905b8154815290600101906020018083116116f857829003601f168201915b50505050509050600081510361173057819350505050611796565b60008251111561176657808260405160200161174d929190613a85565b6040516020818303038152906040529350505050611796565b8061177086611e07565b604051602001611781929190613a85565b60405160208183030381529060405293505050505b919050565b60006117a56118c5565b60040160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6118428133611f67565b50565b6000807ffc606c433378e3a7e0a6a531deac289b66caa1b4aa8554fd4ab2c6f1570f92d890508091505090565b6000807f99574a7094154bb123ae6ae102096f0bf9679b85a5cd1e727aaa0ae5f132e6b190508091505090565b60006118be826118ad6118c5565b60000161200b90919063ffffffff16565b9050919050565b6000807f3c7bf052874fa81625121783266a03507bd2cd48b16e571c01a04e8dd3fb07a690508091505090565b505050565b600061190582600001612025565b9050919050565b50505050565b600061191d8261189f565b611953576040517fc1b843ef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061195e83610c7e565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614806119cd57508373ffffffffffffffffffffffffffffffffffffffff166119b584610924565b73ffffffffffffffffffffffffffffffffffffffff16145b806119de57506119dd818561179b565b5b91505092915050565b60006119f282610c7e565b90508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611a59576040517f0f2db4ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611abf576040517f40311a0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611aca848484612036565b6000611ad46118c5565b9050611b29838260020160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002061204690919063ffffffff16565b50611b7d838260020160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020611d7c90919063ffffffff16565b50611b968385836000016120609092919063ffffffff16565b50600081600301600085815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4828473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45050505050565b6000611cb98360000183612095565b60001c905092915050565b600080600080611cd78660000186612100565b915091508160001c8160001c9350935050509250929050565b6000611d02836000018360001b612181565b60001c905092915050565b6000611d1b8260000161220a565b9050919050565b6000807f68721c0bbf2c02a4d65000340d1370666be06a630022208d4baa9bd7a4b6fea890508091505090565b6000807fb2b4df8db6c86b643bc9671655af7ecab384d088ad8b388456cdc1f36f10ab4590508091505090565b6000611d8e836000018360001b61221b565b905092915050565b611db0828260405180602001604052806000815250612282565b5050565b611dbf8484846119e7565b611dcb848484846122d4565b611e01576040517f9ff10cdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b606060008203611e4e576040518060400160405280600181526020017f30000000000000000000000000000000000000000000000000000000000000008152509050611f62565b600082905060005b60008214611e80578080611e6990613aa9565b915050600a82611e799190613b20565b9150611e56565b60008167ffffffffffffffff811115611e9c57611e9b61310b565b5b6040519080825280601f01601f191660200182016040528015611ece5781602001600182028036833780820191505090505b5090505b60008514611f5b57600182611ee79190613b51565b9150600a85611ef69190613b85565b6030611f029190613541565b60f81b818381518110611f1857611f17613bb6565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a85611f549190613b20565b9450611ed2565b8093505050505b919050565b611f71828261244a565b61200757611f948173ffffffffffffffffffffffffffffffffffffffff16612485565b611fab60208460001c6124b890919063ffffffff16565b604051602001611fbc929190613c7d565b6040516020818303038152906040526040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ffe9190612e4b565b60405180910390fd5b5050565b600061201d836000018360001b6126d4565b905092915050565b600081600001805490509050919050565b6120418383836126f7565b505050565b6000612058836000018360001b612707565b905092915050565b600061208c846000018460001b8473ffffffffffffffffffffffffffffffffffffffff1660001b6127eb565b90509392505050565b6000826000018054905082106120d7576040517fe637bf3b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260000182815481106120ed576120ec613bb6565b5b9060005260206000200154905092915050565b60008083600001805490508310612143576040517f117ec13800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084600001848154811061215b5761215a613bb6565b5b906000526020600020906002020190508060000154816001015492509250509250929050565b600080836001016000848152602001908152602001600020549050600081036121d6576040517ff551fb1400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8360000160018203815481106121ef576121ee613bb6565b5b90600052602060002090600202016001015491505092915050565b600081600001805490509050919050565b600061222783836128cd565b61227c5782600001829080600181540180825580915050600190039060005260206000200160009091909190915055826000018054905083600101600084815260200190815260200160002081905550600190505b92915050565b61228c83836128f0565b61229960008484846122d4565b6122cf576040517f9ff10cdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b60006122f58473ffffffffffffffffffffffffffffffffffffffff16612a7c565b6123025760019050612442565b60006123c263150b7a0260e01b338887876040516024016123269493929190613d0c565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051806060016040528060328152602001613e1d603291398773ffffffffffffffffffffffffffffffffffffffff16612a8f9092919063ffffffff16565b90506000818060200190518101906123da9190613d6d565b90507f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614925050505b949350505050565b600061247d82612458612aa7565b6000016000868152602001908152602001600020600001612ad490919063ffffffff16565b905092915050565b60606124b160148373ffffffffffffffffffffffffffffffffffffffff166124b890919063ffffffff16565b9050919050565b6060600060028360026124cb919061338f565b6124d59190613541565b67ffffffffffffffff8111156124ee576124ed61310b565b5b6040519080825280601f01601f1916602001820160405280156125205781602001600182028036833780820191505090505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811061255857612557613bb6565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f7800000000000000000000000000000000000000000000000000000000000000816001815181106125bc576125bb613bb6565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006001846002020190505b600181111561268f577f3031323334353637383961626364656600000000000000000000000000000000600f86166010811061263657612635613bb6565b5b1a60f81b82828151811061264d5761264c613bb6565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600485901c9450806001900390506125f7565b50600084146126ca576040517fc913478500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8091505092915050565b600080836001016000848152602001908152602001600020541415905092915050565b612702838383612b04565b505050565b600080836001016000848152602001908152602001600020549050600081146127e45760008460000160018660000180549050038154811061274c5761274b613bb6565b5b906000526020600020015490508085600001600184038154811061277357612772613bb6565b5b9060005260206000200181905550818560010160008381526020019081526020016000208190555050836000018054806127b0576127af613d9a565b5b6001900381819060005260206000200160009055905583600101600084815260200190815260200160002060009055600191505b5092915050565b60008084600101600085815260200190815260200160002054905060008103612891578460000160405180604001604052808681526020018581525090806001815401808255809150506001900390600052602060002090600202016000909190919091506000820151816000015560208201518160010155505084600001805490508560010160008681526020019081526020016000208190555060019150506128c6565b828560000160018303815481106128ab576128aa613bb6565b5b90600052602060002090600202016001018190555060009150505b9392505050565b600080836001016000848152602001908152602001600020541415905092915050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612956576040517f23e5311a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61295f8161189f565b15612996576040517f6c35dbd800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6129a260008383612036565b60006129ac6118c5565b9050612a01828260020160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020611d7c90919063ffffffff16565b50612a1a8284836000016120609092919063ffffffff16565b50818373ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b600080823b905060008111915050919050565b6060612a9e8484600085612b71565b90509392505050565b6000807fd3889cc5458b268d0544e5534672df1296288ca3f93cbd39bd6f497a5c62281190508091505090565b6000612afc836000018373ffffffffffffffffffffffffffffffffffffffff1660001b6128cd565b905092915050565b612b0f838383612c8a565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612b6c57612b4b611872565b60030160008281526020019081526020016000206000612b6b9190612c8f565b5b505050565b6060612b7c85612a7c565b612bb2576040517f89c35afc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612bdb9190613e05565b60006040518083038185875af1925050503d8060008114612c18576040519150601f19603f3d011682016040523d82523d6000602084013e612c1d565b606091505b50915091508115612c32578092505050612c82565b600081511115612c455780518082602001fd5b836040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c799190612e4b565b60405180910390fd5b949350505050565b505050565b508054612c9b90613510565b6000825580601f10612cad5750612ccc565b601f016020900490600052602060002090810190612ccb9190612ccf565b5b50565b5b80821115612ce8576000816000905550600101612cd0565b5090565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b612d3581612d00565b8114612d4057600080fd5b50565b600081359050612d5281612d2c565b92915050565b600060208284031215612d6e57612d6d612cf6565b5b6000612d7c84828501612d43565b91505092915050565b60008115159050919050565b612d9a81612d85565b82525050565b6000602082019050612db56000830184612d91565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015612df5578082015181840152602081019050612dda565b60008484015250505050565b6000601f19601f8301169050919050565b6000612e1d82612dbb565b612e278185612dc6565b9350612e37818560208601612dd7565b612e4081612e01565b840191505092915050565b60006020820190508181036000830152612e658184612e12565b905092915050565b6000819050919050565b612e8081612e6d565b8114612e8b57600080fd5b50565b600081359050612e9d81612e77565b92915050565b600060208284031215612eb957612eb8612cf6565b5b6000612ec784828501612e8e565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612efb82612ed0565b9050919050565b612f0b81612ef0565b82525050565b6000602082019050612f266000830184612f02565b92915050565b612f3581612ef0565b8114612f4057600080fd5b50565b600081359050612f5281612f2c565b92915050565b60008060408385031215612f6f57612f6e612cf6565b5b6000612f7d85828601612f43565b9250506020612f8e85828601612e8e565b9150509250929050565b612fa181612e6d565b82525050565b6000602082019050612fbc6000830184612f98565b92915050565b600080600060608486031215612fdb57612fda612cf6565b5b6000612fe986828701612f43565b9350506020612ffa86828701612f43565b925050604061300b86828701612e8e565b9150509250925092565b60006020828403121561302b5761302a612cf6565b5b600061303984828501612f43565b91505092915050565b60008060006060848603121561305b5761305a612cf6565b5b600061306986828701612e8e565b935050602061307a86828701612e8e565b925050604061308b86828701612e8e565b9150509250925092565b61309e81612d85565b81146130a957600080fd5b50565b6000813590506130bb81613095565b92915050565b600080604083850312156130d8576130d7612cf6565b5b60006130e685828601612f43565b92505060206130f7858286016130ac565b9150509250929050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61314382612e01565b810181811067ffffffffffffffff821117156131625761316161310b565b5b80604052505050565b6000613175612cec565b9050613181828261313a565b919050565b600067ffffffffffffffff8211156131a1576131a061310b565b5b6131aa82612e01565b9050602081019050919050565b82818337600083830152505050565b60006131d96131d484613186565b61316b565b9050828152602081018484840111156131f5576131f4613106565b5b6132008482856131b7565b509392505050565b600082601f83011261321d5761321c613101565b5b813561322d8482602086016131c6565b91505092915050565b600080600080608085870312156132505761324f612cf6565b5b600061325e87828801612f43565b945050602061326f87828801612f43565b935050604061328087828801612e8e565b925050606085013567ffffffffffffffff8111156132a1576132a0612cfb565b5b6132ad87828801613208565b91505092959194509250565b600080600080608085870312156132d3576132d2612cf6565b5b60006132e187828801612e8e565b94505060206132f287828801612e8e565b935050604061330387828801612e8e565b925050606061331487828801612f43565b91505092959194509250565b6000806040838503121561333757613336612cf6565b5b600061334585828601612f43565b925050602061335685828601612f43565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061339a82612e6d565b91506133a583612e6d565b92508282026133b381612e6d565b915082820484148315176133ca576133c9613360565b5b5092915050565b7f494e565f4554485f544f54414c00000000000000000000000000000000000000600082015250565b6000613407600d83612dc6565b9150613412826133d1565b602082019050919050565b60006060820190508181036000830152613436816133fa565b90506134456020830185612f98565b6134526040830184612f98565b9392505050565b7f5045525f54585f4552524f520000000000000000000000000000000000000000600082015250565b600061348f600c83612dc6565b915061349a82613459565b602082019050919050565b600060608201905081810360008301526134be81613482565b90506134cd6020830185612f98565b6134da6040830184612f98565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061352857607f821691505b60208210810361353b5761353a6134e1565b5b50919050565b600061354c82612e6d565b915061355783612e6d565b925082820190508082111561356f5761356e613360565b5b92915050565b7f544f4b454e5f43524f505f4153534f43494154494f4e5f4552524f5200000000600082015250565b60006135ab601c83612dc6565b91506135b682613575565b602082019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60038110613601576136006135c1565b5b50565b6000819050613612826135f0565b919050565b600061362282613604565b9050919050565b61363281613617565b82525050565b600060c08201905081810360008301526136518161359e565b90506136606020830188612f98565b61366d6040830187612f98565b61367a6060830186612f98565b6136876080830185613629565b61369460a0830184612f02565b9695505050505050565b7f544f4b454e5f5041594f55545f544945525f4153534f43494154494f4e5f455260008201527f524f520000000000000000000000000000000000000000000000000000000000602082015250565b60006136fa602383612dc6565b91506137058261369e565b604082019050919050565b600060c0820190508181036000830152613729816136ed565b90506137386020830188612f98565b6137456040830187612f98565b6137526060830186612f98565b61375f6080830185613629565b61376c60a0830184612f02565b9695505050505050565b60008154905061378581613510565b9050919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026137ee7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826137b1565b6137f886836137b1565b95508019841693508086168417925050509392505050565b6000819050919050565b600061383561383061382b84612e6d565b613810565b612e6d565b9050919050565b6000819050919050565b61384f8361381a565b61386361385b8261383c565b8484546137be565b825550505050565b600090565b61387861386b565b613883818484613846565b505050565b5b818110156138a75761389c600082613870565b600181019050613889565b5050565b601f8211156138ec576138bd8161378c565b6138c6846137a1565b810160208510156138d5578190505b6138e96138e1856137a1565b830182613888565b50505b505050565b600082821c905092915050565b600061390f600019846008026138f1565b1980831691505092915050565b600061392883836138fe565b9150826002028217905092915050565b818103613946575050613a1e565b61394f82613776565b67ffffffffffffffff8111156139685761396761310b565b5b6139728254613510565b61397d8282856138ab565b6000601f8311600181146139ac576000841561399a578287015490505b6139a4858261391c565b865550613a17565b601f1984166139ba8761378c565b96506139c58661378c565b60005b828110156139ed578489015482556001820191506001850194506020810190506139c8565b86831015613a0a5784890154613a06601f8916826138fe565b8355505b6001600288020188555050505b5050505050505b565b6000604082019050613a356000830185612f02565b613a426020830184612f98565b9392505050565b600081905092915050565b6000613a5f82612dbb565b613a698185613a49565b9350613a79818560208601612dd7565b80840191505092915050565b6000613a918285613a54565b9150613a9d8284613a54565b91508190509392505050565b6000613ab482612e6d565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613ae657613ae5613360565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000613b2b82612e6d565b9150613b3683612e6d565b925082613b4657613b45613af1565b5b828204905092915050565b6000613b5c82612e6d565b9150613b6783612e6d565b9250828203905081811115613b7f57613b7e613360565b5b92915050565b6000613b9082612e6d565b9150613b9b83612e6d565b925082613bab57613baa613af1565b5b828206905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000600082015250565b6000613c1b601783613a49565b9150613c2682613be5565b601782019050919050565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000600082015250565b6000613c67601183613a49565b9150613c7282613c31565b601182019050919050565b6000613c8882613c0e565b9150613c948285613a54565b9150613c9f82613c5a565b9150613cab8284613a54565b91508190509392505050565b600081519050919050565b600082825260208201905092915050565b6000613cde82613cb7565b613ce88185613cc2565b9350613cf8818560208601612dd7565b613d0181612e01565b840191505092915050565b6000608082019050613d216000830187612f02565b613d2e6020830186612f02565b613d3b6040830185612f98565b8181036060830152613d4d8184613cd3565b905095945050505050565b600081519050613d6781612d2c565b92915050565b600060208284031215613d8357613d82612cf6565b5b6000613d9184828501613d58565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600081905092915050565b6000613ddf82613cb7565b613de98185613dc9565b9350613df9818560208601612dd7565b80840191505092915050565b6000613e118284613dd4565b91508190509291505056fe4552433732313a207472616e7366657220746f206e6f6e20455243373231526563656976657220696d706c656d656e746572a2646970667358221220ea8a266ca15d20508a2b6bb06b0c78824352e8de93a238daafc31d8a24fc36fa64736f6c63430008140033

Deployed Bytecode

0x6080604052600436106101145760003560e01c80636352211e116100a0578063b88d4fde11610064578063b88d4fde146103a1578063ba0a44b9146103bd578063c87b56dd146103e6578063e985e9c514610423578063fd152ee71461046057610114565b80636352211e146102b757806370a08231146102f457806395d89b41146103315780639b8b93051461035c578063a22cb4651461037857610114565b806318160ddd116100e757806318160ddd146101da57806323b872dd146102055780632f745c591461022157806342842e0e1461025e5780634f6ccce71461027a57610114565b806301ffc9a71461011957806306fdde0314610156578063081812fc14610181578063095ea7b3146101be575b600080fd5b34801561012557600080fd5b50610140600480360381019061013b9190612d58565b610489565b60405161014d9190612da0565b60405180910390f35b34801561016257600080fd5b5061016b61049b565b6040516101789190612e4b565b60405180910390f35b34801561018d57600080fd5b506101a860048036038101906101a39190612ea3565b6104aa565b6040516101b59190612f11565b60405180910390f35b6101d860048036038101906101d39190612f58565b6104bc565b005b3480156101e657600080fd5b506101ef6104ca565b6040516101fc9190612fa7565b60405180910390f35b61021f600480360381019061021a9190612fc2565b6104d9565b005b34801561022d57600080fd5b5061024860048036038101906102439190612f58565b6104e9565b6040516102559190612fa7565b60405180910390f35b61027860048036038101906102739190612fc2565b6104fd565b005b34801561028657600080fd5b506102a1600480360381019061029c9190612ea3565b61050d565b6040516102ae9190612fa7565b60405180910390f35b3480156102c357600080fd5b506102de60048036038101906102d99190612ea3565b61051f565b6040516102eb9190612f11565b60405180910390f35b34801561030057600080fd5b5061031b60048036038101906103169190613015565b610531565b6040516103289190612fa7565b60405180910390f35b34801561033d57600080fd5b50610346610543565b6040516103539190612e4b565b60405180910390f35b61037660048036038101906103719190613042565b610552565b005b34801561038457600080fd5b5061039f600480360381019061039a91906130c1565b6106e2565b005b6103bb60048036038101906103b69190613236565b6106f0565b005b3480156103c957600080fd5b506103e460048036038101906103df91906132b9565b610702565b005b3480156103f257600080fd5b5061040d60048036038101906104089190612ea3565b6107b3565b60405161041a9190612e4b565b60405180910390f35b34801561042f57600080fd5b5061044a60048036038101906104459190613320565b6107c5565b6040516104579190612da0565b60405180910390f35b34801561046c57600080fd5b50610487600480360381019061048291906132b9565b6107d9565b005b600061049482610818565b9050919050565b60606104a5610889565b905090565b60006104b582610924565b9050919050565b6104c682826109a9565b5050565b60006104d4610b5b565b905090565b6104e4838383610b75565b505050565b60006104f58383610bd1565b905092915050565b610508838383610c35565b505050565b600061051882610c55565b9050919050565b600061052a82610c7e565b9050919050565b600061053c82610d0f565b9050919050565b606061054d610dcd565b905090565b61055a610e68565b15610591576040517f059519da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fbaf1a8b39218df0710a90513bf0dcf53bf025fceec7598c2d0a27eec92649faa6105bb81610e88565b156105f2576040517fd73a2c8700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006105fc610ebb565b600201600085815260200190815260200160002090506000838260020154610624919061338f565b905034811461066c5734816040517f065a653700000000000000000000000000000000000000000000000000000000815260040161066392919061341d565b60405180910390fd5b60008260030154141580156106845750816003015484115b156106cc578382600301546040517f065a65370000000000000000000000000000000000000000000000000000000081526004016106c39291906134a5565b60405180910390fd5b6106da868686600033610ee8565b505050505050565b6106ec82826113d3565b5050565b6106fc8484848461153e565b50505050565b600061070c610ebb565b60060160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1690508061079e57336040517f43839dab0000000000000000000000000000000000000000000000000000000081526004016107959190612f11565b60405180910390fd5b6107ac858585600286610ee8565b5050505050565b60606107be8261159c565b9050919050565b60006107d1838361179b565b905092915050565b7f7dc7a9428f8cc2d7d0a73dfc0f0d4791fa005321ee0ba5d966a60588b12e576c61080381611838565b610811858585600186610ee8565b5050505050565b6000610822611845565b6000016000837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060009054906101000a900460ff169050919050565b6060610893611872565b60000180546108a190613510565b80601f01602080910402602001604051908101604052809291908181526020018280546108cd90613510565b801561091a5780601f106108ef5761010080835404028352916020019161091a565b820191906000526020600020905b8154815290600101906020018083116108fd57829003601f168201915b5050505050905090565b600061092f8261189f565b610965576040517fc1b843ef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61096d6118c5565b600301600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b6109b48282346118f2565b60006109bf82610c7e565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610a26576040517f424a22cb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015610a695750610a67813361179b565b155b15610aa0576040517f2f5de44f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610aa96118c5565b600301600084815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550818373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050565b6000610b70610b686118c5565b6000016118f7565b905090565b610b818383833461190c565b610b8b3382611912565b610bc1576040517f2f5de44f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bcc8383836119e7565b505050565b6000610c2d82610bdf6118c5565b60020160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020611caa90919063ffffffff16565b905092915050565b610c508383836040518060200160405280600081525061153e565b505050565b6000610c7482610c636118c5565b600001611cc490919063ffffffff16565b5080915050919050565b600080610c9e83610c8d6118c5565b600001611cf090919063ffffffff16565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610d06576040517f7e1a7d8b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80915050919050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610d76576040517f810ff97000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610dc6610d816118c5565b60020160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020611d0d565b9050919050565b6060610dd7611872565b6001018054610de590613510565b80601f0160208091040260200160405190810160405280929190818152602001828054610e1190613510565b8015610e5e5780601f10610e3357610100808354040283529160200191610e5e565b820191906000526020600020905b815481529060010190602001808311610e4157829003601f168201915b5050505050905090565b6000610e72611d22565b60000160009054906101000a900460ff16905090565b6000610e92611d4f565b600001600083815260200190815260200160002060009054906101000a900460ff169050919050565b6000807fa9766cf30247385bd274fe73461f870e9ad8351016f172911cfa198f44cc28e590508091505090565b6000610ef2610ebb565b600701549050600081118015610f1a57508084610f0e84610d0f565b610f189190613541565b115b15610f5c57816040517ffe26af11000000000000000000000000000000000000000000000000000000008152600401610f539190612f11565b60405180910390fd5b6000610f66610ebb565b600101600088815260200190815260200160002090508060020160009054906101000a900460ff1680610fa857508060020160019054906101000a900460ff16155b15610fea57866040517faa7ed920000000000000000000000000000000000000000000000000000000008152600401610fe19190612fa7565b60405180910390fd5b6000610ff4610ebb565b600201600088815260200190815260200160002090508060060160009054906101000a900460ff168061103657508060060160019054906101000a900460ff16155b1561107857866040517fb54df80b00000000000000000000000000000000000000000000000000000000815260040161106f9190612fa7565b60405180910390fd5b6000611082610ebb565b905060008160040160008a81526020019081526020016000209050600083600501541180156110c757508260050154886110bb83611d0d565b6110c59190613541565b115b1561110957886040517fa613fc860000000000000000000000000000000000000000000000000000000081526004016111009190612fa7565b60405180910390fd5b60008260000160008c8152602001908152602001600020905060008360080154905060005b8a8110156113b057600081836111449190613541565b90506111598185611d7c90919063ffffffff16565b6111a2578d8d8d8d8d6040517fe60b992a000000000000000000000000000000000000000000000000000000008152600401611199959493929190613638565b60405180910390fd5b6111b58186611d7c90919063ffffffff16565b6111fe578d8d8d8d8d6040517fe60b992a0000000000000000000000000000000000000000000000000000000081526004016111f5959493929190613710565b60405180910390fd5b8686600301600083815260200190815260200160002060008201548160000155600182018160010190816112329190613938565b50600282015481600201556003820154816003015560048201548160040155600582015481600501556006820160009054906101000a900460ff168160060160006101000a81548160ff0219169083151502179055506006820160019054906101000a900460ff168160060160016101000a81548160ff0219169083151502179055509050508786600501600083815260200190815260200160002060008201548160000155600182018160010190816112ec9190613938565b506002820160009054906101000a900460ff168160020160006101000a81548160ff0219169083151502179055506002820160019054906101000a900460ff168160020160016101000a81548160ff0219169083151502179055509050506113548a82611d96565b8c8e8c6002811115611369576113686135c1565b5b7f78da9a89ac3627c32a75c80f4320c7ced2fc3400714cf5a1f7d5668dda3d8d578d8560405161139a929190613a20565b60405180910390a481806001019250505061112e565b80826113bc9190613541565b856008018190555050505050505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611438576040517f424a22cb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806114416118c5565b60040160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31836040516115329190612da0565b60405180910390a35050565b61154a8484843461190c565b6115543383611912565b61158a576040517f2f5de44f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61159684848484611db4565b50505050565b60606115a78261189f565b6115dd576040517f2382d38000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006115e7611872565b90506000816003016000858152602001908152602001600020805461160b90613510565b80601f016020809104026020016040519081016040528092919081815260200182805461163790613510565b80156116845780601f1061165957610100808354040283529160200191611684565b820191906000526020600020905b81548152906001019060200180831161166757829003601f168201915b50505050509050600082600201805461169c90613510565b80601f01602080910402602001604051908101604052809291908181526020018280546116c890613510565b80156117155780601f106116ea57610100808354040283529160200191611715565b820191906000526020600020905b8154815290600101906020018083116116f857829003601f168201915b50505050509050600081510361173057819350505050611796565b60008251111561176657808260405160200161174d929190613a85565b6040516020818303038152906040529350505050611796565b8061177086611e07565b604051602001611781929190613a85565b60405160208183030381529060405293505050505b919050565b60006117a56118c5565b60040160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6118428133611f67565b50565b6000807ffc606c433378e3a7e0a6a531deac289b66caa1b4aa8554fd4ab2c6f1570f92d890508091505090565b6000807f99574a7094154bb123ae6ae102096f0bf9679b85a5cd1e727aaa0ae5f132e6b190508091505090565b60006118be826118ad6118c5565b60000161200b90919063ffffffff16565b9050919050565b6000807f3c7bf052874fa81625121783266a03507bd2cd48b16e571c01a04e8dd3fb07a690508091505090565b505050565b600061190582600001612025565b9050919050565b50505050565b600061191d8261189f565b611953576040517fc1b843ef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061195e83610c7e565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614806119cd57508373ffffffffffffffffffffffffffffffffffffffff166119b584610924565b73ffffffffffffffffffffffffffffffffffffffff16145b806119de57506119dd818561179b565b5b91505092915050565b60006119f282610c7e565b90508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611a59576040517f0f2db4ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611abf576040517f40311a0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611aca848484612036565b6000611ad46118c5565b9050611b29838260020160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002061204690919063ffffffff16565b50611b7d838260020160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020611d7c90919063ffffffff16565b50611b968385836000016120609092919063ffffffff16565b50600081600301600085815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4828473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45050505050565b6000611cb98360000183612095565b60001c905092915050565b600080600080611cd78660000186612100565b915091508160001c8160001c9350935050509250929050565b6000611d02836000018360001b612181565b60001c905092915050565b6000611d1b8260000161220a565b9050919050565b6000807f68721c0bbf2c02a4d65000340d1370666be06a630022208d4baa9bd7a4b6fea890508091505090565b6000807fb2b4df8db6c86b643bc9671655af7ecab384d088ad8b388456cdc1f36f10ab4590508091505090565b6000611d8e836000018360001b61221b565b905092915050565b611db0828260405180602001604052806000815250612282565b5050565b611dbf8484846119e7565b611dcb848484846122d4565b611e01576040517f9ff10cdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b606060008203611e4e576040518060400160405280600181526020017f30000000000000000000000000000000000000000000000000000000000000008152509050611f62565b600082905060005b60008214611e80578080611e6990613aa9565b915050600a82611e799190613b20565b9150611e56565b60008167ffffffffffffffff811115611e9c57611e9b61310b565b5b6040519080825280601f01601f191660200182016040528015611ece5781602001600182028036833780820191505090505b5090505b60008514611f5b57600182611ee79190613b51565b9150600a85611ef69190613b85565b6030611f029190613541565b60f81b818381518110611f1857611f17613bb6565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a85611f549190613b20565b9450611ed2565b8093505050505b919050565b611f71828261244a565b61200757611f948173ffffffffffffffffffffffffffffffffffffffff16612485565b611fab60208460001c6124b890919063ffffffff16565b604051602001611fbc929190613c7d565b6040516020818303038152906040526040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ffe9190612e4b565b60405180910390fd5b5050565b600061201d836000018360001b6126d4565b905092915050565b600081600001805490509050919050565b6120418383836126f7565b505050565b6000612058836000018360001b612707565b905092915050565b600061208c846000018460001b8473ffffffffffffffffffffffffffffffffffffffff1660001b6127eb565b90509392505050565b6000826000018054905082106120d7576040517fe637bf3b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260000182815481106120ed576120ec613bb6565b5b9060005260206000200154905092915050565b60008083600001805490508310612143576040517f117ec13800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084600001848154811061215b5761215a613bb6565b5b906000526020600020906002020190508060000154816001015492509250509250929050565b600080836001016000848152602001908152602001600020549050600081036121d6576040517ff551fb1400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8360000160018203815481106121ef576121ee613bb6565b5b90600052602060002090600202016001015491505092915050565b600081600001805490509050919050565b600061222783836128cd565b61227c5782600001829080600181540180825580915050600190039060005260206000200160009091909190915055826000018054905083600101600084815260200190815260200160002081905550600190505b92915050565b61228c83836128f0565b61229960008484846122d4565b6122cf576040517f9ff10cdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b60006122f58473ffffffffffffffffffffffffffffffffffffffff16612a7c565b6123025760019050612442565b60006123c263150b7a0260e01b338887876040516024016123269493929190613d0c565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051806060016040528060328152602001613e1d603291398773ffffffffffffffffffffffffffffffffffffffff16612a8f9092919063ffffffff16565b90506000818060200190518101906123da9190613d6d565b90507f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614925050505b949350505050565b600061247d82612458612aa7565b6000016000868152602001908152602001600020600001612ad490919063ffffffff16565b905092915050565b60606124b160148373ffffffffffffffffffffffffffffffffffffffff166124b890919063ffffffff16565b9050919050565b6060600060028360026124cb919061338f565b6124d59190613541565b67ffffffffffffffff8111156124ee576124ed61310b565b5b6040519080825280601f01601f1916602001820160405280156125205781602001600182028036833780820191505090505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811061255857612557613bb6565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f7800000000000000000000000000000000000000000000000000000000000000816001815181106125bc576125bb613bb6565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006001846002020190505b600181111561268f577f3031323334353637383961626364656600000000000000000000000000000000600f86166010811061263657612635613bb6565b5b1a60f81b82828151811061264d5761264c613bb6565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600485901c9450806001900390506125f7565b50600084146126ca576040517fc913478500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8091505092915050565b600080836001016000848152602001908152602001600020541415905092915050565b612702838383612b04565b505050565b600080836001016000848152602001908152602001600020549050600081146127e45760008460000160018660000180549050038154811061274c5761274b613bb6565b5b906000526020600020015490508085600001600184038154811061277357612772613bb6565b5b9060005260206000200181905550818560010160008381526020019081526020016000208190555050836000018054806127b0576127af613d9a565b5b6001900381819060005260206000200160009055905583600101600084815260200190815260200160002060009055600191505b5092915050565b60008084600101600085815260200190815260200160002054905060008103612891578460000160405180604001604052808681526020018581525090806001815401808255809150506001900390600052602060002090600202016000909190919091506000820151816000015560208201518160010155505084600001805490508560010160008681526020019081526020016000208190555060019150506128c6565b828560000160018303815481106128ab576128aa613bb6565b5b90600052602060002090600202016001018190555060009150505b9392505050565b600080836001016000848152602001908152602001600020541415905092915050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612956576040517f23e5311a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61295f8161189f565b15612996576040517f6c35dbd800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6129a260008383612036565b60006129ac6118c5565b9050612a01828260020160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020611d7c90919063ffffffff16565b50612a1a8284836000016120609092919063ffffffff16565b50818373ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b600080823b905060008111915050919050565b6060612a9e8484600085612b71565b90509392505050565b6000807fd3889cc5458b268d0544e5534672df1296288ca3f93cbd39bd6f497a5c62281190508091505090565b6000612afc836000018373ffffffffffffffffffffffffffffffffffffffff1660001b6128cd565b905092915050565b612b0f838383612c8a565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612b6c57612b4b611872565b60030160008281526020019081526020016000206000612b6b9190612c8f565b5b505050565b6060612b7c85612a7c565b612bb2576040517f89c35afc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612bdb9190613e05565b60006040518083038185875af1925050503d8060008114612c18576040519150601f19603f3d011682016040523d82523d6000602084013e612c1d565b606091505b50915091508115612c32578092505050612c82565b600081511115612c455780518082602001fd5b836040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c799190612e4b565b60405180910390fd5b949350505050565b505050565b508054612c9b90613510565b6000825580601f10612cad5750612ccc565b601f016020900490600052602060002090810190612ccb9190612ccf565b5b50565b5b80821115612ce8576000816000905550600101612cd0565b5090565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b612d3581612d00565b8114612d4057600080fd5b50565b600081359050612d5281612d2c565b92915050565b600060208284031215612d6e57612d6d612cf6565b5b6000612d7c84828501612d43565b91505092915050565b60008115159050919050565b612d9a81612d85565b82525050565b6000602082019050612db56000830184612d91565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015612df5578082015181840152602081019050612dda565b60008484015250505050565b6000601f19601f8301169050919050565b6000612e1d82612dbb565b612e278185612dc6565b9350612e37818560208601612dd7565b612e4081612e01565b840191505092915050565b60006020820190508181036000830152612e658184612e12565b905092915050565b6000819050919050565b612e8081612e6d565b8114612e8b57600080fd5b50565b600081359050612e9d81612e77565b92915050565b600060208284031215612eb957612eb8612cf6565b5b6000612ec784828501612e8e565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612efb82612ed0565b9050919050565b612f0b81612ef0565b82525050565b6000602082019050612f266000830184612f02565b92915050565b612f3581612ef0565b8114612f4057600080fd5b50565b600081359050612f5281612f2c565b92915050565b60008060408385031215612f6f57612f6e612cf6565b5b6000612f7d85828601612f43565b9250506020612f8e85828601612e8e565b9150509250929050565b612fa181612e6d565b82525050565b6000602082019050612fbc6000830184612f98565b92915050565b600080600060608486031215612fdb57612fda612cf6565b5b6000612fe986828701612f43565b9350506020612ffa86828701612f43565b925050604061300b86828701612e8e565b9150509250925092565b60006020828403121561302b5761302a612cf6565b5b600061303984828501612f43565b91505092915050565b60008060006060848603121561305b5761305a612cf6565b5b600061306986828701612e8e565b935050602061307a86828701612e8e565b925050604061308b86828701612e8e565b9150509250925092565b61309e81612d85565b81146130a957600080fd5b50565b6000813590506130bb81613095565b92915050565b600080604083850312156130d8576130d7612cf6565b5b60006130e685828601612f43565b92505060206130f7858286016130ac565b9150509250929050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61314382612e01565b810181811067ffffffffffffffff821117156131625761316161310b565b5b80604052505050565b6000613175612cec565b9050613181828261313a565b919050565b600067ffffffffffffffff8211156131a1576131a061310b565b5b6131aa82612e01565b9050602081019050919050565b82818337600083830152505050565b60006131d96131d484613186565b61316b565b9050828152602081018484840111156131f5576131f4613106565b5b6132008482856131b7565b509392505050565b600082601f83011261321d5761321c613101565b5b813561322d8482602086016131c6565b91505092915050565b600080600080608085870312156132505761324f612cf6565b5b600061325e87828801612f43565b945050602061326f87828801612f43565b935050604061328087828801612e8e565b925050606085013567ffffffffffffffff8111156132a1576132a0612cfb565b5b6132ad87828801613208565b91505092959194509250565b600080600080608085870312156132d3576132d2612cf6565b5b60006132e187828801612e8e565b94505060206132f287828801612e8e565b935050604061330387828801612e8e565b925050606061331487828801612f43565b91505092959194509250565b6000806040838503121561333757613336612cf6565b5b600061334585828601612f43565b925050602061335685828601612f43565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061339a82612e6d565b91506133a583612e6d565b92508282026133b381612e6d565b915082820484148315176133ca576133c9613360565b5b5092915050565b7f494e565f4554485f544f54414c00000000000000000000000000000000000000600082015250565b6000613407600d83612dc6565b9150613412826133d1565b602082019050919050565b60006060820190508181036000830152613436816133fa565b90506134456020830185612f98565b6134526040830184612f98565b9392505050565b7f5045525f54585f4552524f520000000000000000000000000000000000000000600082015250565b600061348f600c83612dc6565b915061349a82613459565b602082019050919050565b600060608201905081810360008301526134be81613482565b90506134cd6020830185612f98565b6134da6040830184612f98565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061352857607f821691505b60208210810361353b5761353a6134e1565b5b50919050565b600061354c82612e6d565b915061355783612e6d565b925082820190508082111561356f5761356e613360565b5b92915050565b7f544f4b454e5f43524f505f4153534f43494154494f4e5f4552524f5200000000600082015250565b60006135ab601c83612dc6565b91506135b682613575565b602082019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60038110613601576136006135c1565b5b50565b6000819050613612826135f0565b919050565b600061362282613604565b9050919050565b61363281613617565b82525050565b600060c08201905081810360008301526136518161359e565b90506136606020830188612f98565b61366d6040830187612f98565b61367a6060830186612f98565b6136876080830185613629565b61369460a0830184612f02565b9695505050505050565b7f544f4b454e5f5041594f55545f544945525f4153534f43494154494f4e5f455260008201527f524f520000000000000000000000000000000000000000000000000000000000602082015250565b60006136fa602383612dc6565b91506137058261369e565b604082019050919050565b600060c0820190508181036000830152613729816136ed565b90506137386020830188612f98565b6137456040830187612f98565b6137526060830186612f98565b61375f6080830185613629565b61376c60a0830184612f02565b9695505050505050565b60008154905061378581613510565b9050919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026137ee7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826137b1565b6137f886836137b1565b95508019841693508086168417925050509392505050565b6000819050919050565b600061383561383061382b84612e6d565b613810565b612e6d565b9050919050565b6000819050919050565b61384f8361381a565b61386361385b8261383c565b8484546137be565b825550505050565b600090565b61387861386b565b613883818484613846565b505050565b5b818110156138a75761389c600082613870565b600181019050613889565b5050565b601f8211156138ec576138bd8161378c565b6138c6846137a1565b810160208510156138d5578190505b6138e96138e1856137a1565b830182613888565b50505b505050565b600082821c905092915050565b600061390f600019846008026138f1565b1980831691505092915050565b600061392883836138fe565b9150826002028217905092915050565b818103613946575050613a1e565b61394f82613776565b67ffffffffffffffff8111156139685761396761310b565b5b6139728254613510565b61397d8282856138ab565b6000601f8311600181146139ac576000841561399a578287015490505b6139a4858261391c565b865550613a17565b601f1984166139ba8761378c565b96506139c58661378c565b60005b828110156139ed578489015482556001820191506001850194506020810190506139c8565b86831015613a0a5784890154613a06601f8916826138fe565b8355505b6001600288020188555050505b5050505050505b565b6000604082019050613a356000830185612f02565b613a426020830184612f98565b9392505050565b600081905092915050565b6000613a5f82612dbb565b613a698185613a49565b9350613a79818560208601612dd7565b80840191505092915050565b6000613a918285613a54565b9150613a9d8284613a54565b91508190509392505050565b6000613ab482612e6d565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613ae657613ae5613360565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000613b2b82612e6d565b9150613b3683612e6d565b925082613b4657613b45613af1565b5b828204905092915050565b6000613b5c82612e6d565b9150613b6783612e6d565b9250828203905081811115613b7f57613b7e613360565b5b92915050565b6000613b9082612e6d565b9150613b9b83612e6d565b925082613bab57613baa613af1565b5b828206905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000600082015250565b6000613c1b601783613a49565b9150613c2682613be5565b601782019050919050565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000600082015250565b6000613c67601183613a49565b9150613c7282613c31565b601182019050919050565b6000613c8882613c0e565b9150613c948285613a54565b9150613c9f82613c5a565b9150613cab8284613a54565b91508190509392505050565b600081519050919050565b600082825260208201905092915050565b6000613cde82613cb7565b613ce88185613cc2565b9350613cf8818560208601612dd7565b613d0181612e01565b840191505092915050565b6000608082019050613d216000830187612f02565b613d2e6020830186612f02565b613d3b6040830185612f98565b8181036060830152613d4d8184613cd3565b905095945050505050565b600081519050613d6781612d2c565b92915050565b600060208284031215613d8357613d82612cf6565b5b6000613d9184828501613d58565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600081905092915050565b6000613ddf82613cb7565b613de98185613dc9565b9350613df9818560208601612dd7565b80840191505092915050565b6000613e118284613dd4565b91508190509291505056fe4552433732313a207472616e7366657220746f206e6f6e20455243373231526563656976657220696d706c656d656e746572a2646970667358221220ea8a266ca15d20508a2b6bb06b0c78824352e8de93a238daafc31d8a24fc36fa64736f6c63430008140033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

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