MATIC Price: $1.03 (-2.73%)
Gas: 64 GWei
 

Overview

MATIC Balance

Polygon PoS Chain LogoPolygon PoS Chain LogoPolygon PoS Chain Logo0 MATIC

MATIC Value

$0.00

Token Holdings

Sponsored

Transaction Hash
Method
Block
From
To
Value
Safe Transfer Fr...507868682023-12-05 22:39:3784 days 30 mins ago1701815977IN
0xD7519f...20e31988
0 MATIC0.0076562267.19762902
Safe Transfer Fr...507868212023-12-05 22:37:5784 days 32 mins ago1701815877IN
0xD7519f...20e31988
0 MATIC0.0083713673.47424409
Transfer From505806622023-11-30 17:23:3589 days 5 hrs ago1701365015IN
0xD7519f...20e31988
0 MATIC0.04921116442.87702233
Transfer From459050472023-08-04 16:17:43207 days 6 hrs ago1691165863IN
0xD7519f...20e31988
0 MATIC0.0084681576.20940013
Set Approval For...432822892023-05-29 8:55:03274 days 14 hrs ago1685350503IN
0xD7519f...20e31988
0 MATIC0.00716552153.88546953
Safe Transfer Fr...366290582022-12-09 19:01:24445 days 4 hrs ago1670612484IN
0xD7519f...20e31988
0 MATIC0.0040761735.75215
Set Approval For...366286732022-12-09 18:47:19445 days 4 hrs ago1670611639IN
0xD7519f...20e31988
0 MATIC0.0026423456.74650297
Mint Vehicle Sig...360599902022-11-25 18:48:09459 days 4 hrs ago1669402089IN
0xD7519f...20e31988
0 MATIC0.00953430.00000003
Mint Vehicle Sig...360599182022-11-25 18:45:41459 days 4 hrs ago1669401941IN
0xD7519f...20e31988
0 MATIC0.0100485930.00000003
Mint Vehicle Sig...359826562022-11-23 21:51:48461 days 1 hr ago1669240308IN
0xD7519f...20e31988
0 MATIC0.0095361630.00000001
Mint Vehicle Sig...359151962022-11-22 6:24:54462 days 16 hrs ago1669098294IN
0xD7519f...20e31988
0 MATIC0.0100484430.00000243
Mint Vehicle Sig...359054962022-11-22 0:47:07462 days 22 hrs ago1669078027IN
0xD7519f...20e31988
0 MATIC0.0100455630.00000002
Mint Vehicle Sig...359051932022-11-22 0:36:40462 days 22 hrs ago1669077400IN
0xD7519f...20e31988
0 MATIC0.0100484430.0000045
Mint Vehicle Sig...359050342022-11-22 0:31:14462 days 22 hrs ago1669077074IN
0xD7519f...20e31988
0 MATIC0.0100504230.00011623
Mint Vehicle Sig...358382262022-11-20 9:38:24464 days 13 hrs ago1668937104IN
0xD7519f...20e31988
0 MATIC0.0100501230.0002785
Mint Vehicle Sig...357910582022-11-19 6:21:55465 days 16 hrs ago1668838915IN
0xD7519f...20e31988
0 MATIC0.0100500330.00000002
Mint Vehicle Sig...357706562022-11-18 18:32:22466 days 4 hrs ago1668796342IN
0xD7519f...20e31988
0 MATIC0.0100921430.13219661
Mint Vehicle Sig...357261212022-11-17 16:19:56467 days 6 hrs ago1668701996IN
0xD7519f...20e31988
0 MATIC0.0205133764.51293448
Mint Vehicle Sig...356973522022-11-16 23:29:10467 days 23 hrs ago1668641350IN
0xD7519f...20e31988
0 MATIC0.0095350830.00000081
Mint Vehicle Sig...356862022022-11-16 16:58:59468 days 6 hrs ago1668617939IN
0xD7519f...20e31988
0 MATIC0.0133213839.7723367
Mint Vehicle Sig...356739982022-11-16 9:52:56468 days 13 hrs ago1668592376IN
0xD7519f...20e31988
0 MATIC0.0114067734.05171234
Mint Vehicle Sig...356555512022-11-15 23:04:44469 days 5 mins ago1668553484IN
0xD7519f...20e31988
0 MATIC0.0106925131.92634667
Mint Vehicle Sig...356450972022-11-15 17:04:51469 days 6 hrs ago1668531891IN
0xD7519f...20e31988
0 MATIC0.013069339.01749855
Mint Vehicle Sig...356166282022-11-15 0:23:13469 days 22 hrs ago1668471793IN
0xD7519f...20e31988
0 MATIC0.0103600230.93199666
Mint Vehicle Sig...356102872022-11-14 20:43:19470 days 2 hrs ago1668458599IN
0xD7519f...20e31988
0 MATIC0.0100521930.00861319
View all transactions

Parent Txn Hash Block From To Value
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
DIMORegistryBetaV1

Compiler Version
v0.8.13+commit.abaa5c0e

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion
File 1 of 26 : DIMORegistry.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.13;

import "./libraries/DIMOStorage.sol";
import "./access/AccessControlInternal.sol";
import "@solidstate/contracts/introspection/ERC165.sol";
import "@solidstate/contracts/token/ERC721/ERC721.sol";
import "@solidstate/contracts/token/ERC721/metadata/IERC721Metadata.sol";
import "@solidstate/contracts/token/ERC721/metadata/ERC721MetadataStorage.sol";

contract DIMORegistryBetaV1 is ERC721, AccessControlInternal {
    using ERC165Storage for ERC165Storage.Layout;

    event ModuleAdded(address indexed moduleAddr, bytes4[] selectors);
    event ModuleRemoved(address indexed moduleAddr, bytes4[] selectors);
    event ModuleUpdated(
        address indexed oldImplementation,
        address indexed newImplementation,
        bytes4[] oldSelectors,
        bytes4[] newSelectors
    );

    constructor(
        string memory _name,
        string memory _symbol,
        string memory __baseURI
    ) {
        _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);

        ERC721MetadataStorage.Layout storage s = ERC721MetadataStorage.layout();
        s.name = _name;
        s.symbol = _symbol;
        s.baseURI = __baseURI;

        ERC165Storage.layout().setSupportedInterface(
            type(IERC165).interfaceId,
            true
        );
        ERC165Storage.layout().setSupportedInterface(
            type(IERC721Metadata).interfaceId,
            true
        );
    }

    /// @notice pass a call to a module
    /* solhint-disable no-complex-fallback, payable-fallback, no-inline-assembly */
    fallback() external {
        address implementation = DIMOStorage.getStorage().implementations[
            msg.sig
        ];
        assembly {
            calldatacopy(0, 0, calldatasize())
            let result := delegatecall(
                gas(),
                implementation,
                0,
                calldatasize(),
                0,
                0
            )
            returndatacopy(0, 0, returndatasize())
            switch result
            case 0 {
                revert(0, returndatasize())
            }
            default {
                return(0, returndatasize())
            }
        }
    }

    /* solhint-enable no-complex-fallback, payable-fallback, no-inline-assembly */

    /// @notice update module
    /// @dev oldImplementation should be registered
    /// @param oldImplementation address of the module to remove
    /// @param newImplementation address of the module to register
    /// @param oldSelectors old function signatures list
    /// @param newSelectors new function signatures list
    function updateModule(
        address oldImplementation,
        address newImplementation,
        bytes4[] calldata oldSelectors,
        bytes4[] calldata newSelectors
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        _removeModule(oldImplementation, oldSelectors);
        _addModule(newImplementation, newSelectors);
        emit ModuleUpdated(
            oldImplementation,
            newImplementation,
            oldSelectors,
            newSelectors
        );
    }

    /// @notice Adds a new module
    /// @dev function selector should not have been registered
    /// @param implementation address of the implementation
    /// @param selectors selectors of the implementation contract
    function addModule(address implementation, bytes4[] calldata selectors)
        external
        onlyRole(DEFAULT_ADMIN_ROLE)
    {
        _addModule(implementation, selectors);
        emit ModuleAdded(implementation, selectors);
    }

    /// @notice Adds a new module and supported functions
    /// @dev function selector should not exist
    /// @param implementation implementation address
    /// @param selectors function signatures
    function removeModule(address implementation, bytes4[] calldata selectors)
        external
        onlyRole(DEFAULT_ADMIN_ROLE)
    {
        _removeModule(implementation, selectors);
        emit ModuleRemoved(implementation, selectors);
    }

    /// @notice Adds a new module
    /// @dev function selector should not have been registered.
    /// @param implementation address of the implementation
    /// @param selectors selectors of the implementation contract
    function _addModule(address implementation, bytes4[] calldata selectors)
        private
    {
        DIMOStorage.Storage storage s = DIMOStorage.getStorage();
        require(
            s.selectorsHash[implementation] == 0x0,
            "Implementation already exists"
        );

        for (uint256 i = 0; i < selectors.length; i++) {
            require(
                s.implementations[selectors[i]] == address(0),
                "Selector already registered"
            );
            s.implementations[selectors[i]] = implementation;
        }
        bytes32 hash = keccak256(abi.encode(selectors));
        s.selectorsHash[implementation] = hash;
    }

    /// @notice Adds a new module and supported functions
    /// @dev function selector should not exist
    /// @param implementation implementation address
    /// @param selectors function signatures
    function _removeModule(address implementation, bytes4[] calldata selectors)
        private
    {
        DIMOStorage.Storage storage s = DIMOStorage.getStorage();
        bytes32 hash = keccak256(abi.encode(selectors));
        require(
            s.selectorsHash[implementation] == hash,
            "Invalid selector list"
        );

        for (uint256 i = 0; i < selectors.length; i++) {
            require(
                s.implementations[selectors[i]] == implementation,
                "Unregistered selector"
            );
            s.implementations[selectors[i]] = address(0);
        }
    }
}

File 2 of 26 : DIMOStorage.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.13;

library DIMOStorage {
    bytes32 internal constant DIMO_REGISTRY_STORAGE_SLOT =
        keccak256("DIMORegistry.storage");

    struct Node {
        uint256 nodeType;
        uint256 parentNode;
        mapping(string => string) info;
    }

    struct Storage {
        address admin;
        // Maps function selectors to the implementations that execute the functions
        mapping(bytes4 => address) implementations;
        // Maps the implementation to the hash of all its selectors
        // implementation => keccak256(abi.encode(selectors))
        mapping(address => bytes32) selectorsHash;
        // [Node id] => Node info
        mapping(uint256 => Node) nodes;
        uint256 currentIndex;
    }

    /* solhint-disable no-inline-assembly */
    function getStorage() internal pure returns (Storage storage s) {
        bytes32 slot = DIMO_REGISTRY_STORAGE_SLOT;
        assembly {
            s.slot := slot
        }
    }
    /* solhint-enable no-inline-assembly */
}

File 3 of 26 : AccessControlInternal.sol
// SPDX-License-Identifier: Unlicensed
pragma solidity ^0.8.13;

import {AccessControlStorage} from "./AccessControlStorage.sol";
import {IAccessControlInternal} from "./IAccessControlInternal.sol";
import {UintUtils} from "@solidstate/contracts/utils/UintUtils.sol";
import {AddressUtils} from "@solidstate/contracts/utils/AddressUtils.sol";

contract AccessControlInternal is IAccessControlInternal {
    using AccessControlStorage for AccessControlStorage.Storage;
    using AddressUtils for address;
    using UintUtils for uint256;

    bytes32 internal constant DEFAULT_ADMIN_ROLE = 0x00;

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

    /**
     * @notice query if account's has role
     * @param role role to query
     * @param account account to query
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function _hasRole(bytes32 role, address account)
        internal
        view
        virtual
        returns (bool)
    {
        return AccessControlStorage.getStorage().roles[role].members[account];
    }

    /**
     * @notice query role by msg.sender
     * @param role role to query
     * @dev Revert with a standard message if `msg.sender` is missing `role`.
     * Overriding this function changes the behavior of the {onlyRole} modifier.
     *
     * Format of the revert message is described in {_checkRole}.
     *
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, msg.sender);
    }

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

    /**
     * @notice query admin role
     * @param role role to query
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function _getRoleAdmin(bytes32 role)
        internal
        view
        virtual
        returns (bytes32)
    {
        return AccessControlStorage.getStorage().roles[role].adminRole;
    }

    /**
     * @notice set role as admin role
     * @param role role to set
     * @param adminRole admin role to set
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = _getRoleAdmin(role);
        AccessControlStorage.getStorage().roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @notice grant role to account
     * @param role role to grant
     * @param account account to grant the role
     * @dev Grants `role` to `account`.
     *
     *  * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * Internal function without access restriction.
     */
    function _grantRole(bytes32 role, address account) internal virtual {
        if (!_hasRole(role, account)) {
            AccessControlStorage.getStorage().roles[role].members[
                account
            ] = true;
            emit RoleGranted(role, account, msg.sender);
        }
    }

    /**
     * @notice revoke role from account
     * @param role role to revoke
     * @param account account to revoke the role
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * Internal function without access restriction.
     */
    function _revokeRole(bytes32 role, address account) internal virtual {
        if (_hasRole(role, account)) {
            AccessControlStorage.getStorage().roles[role].members[
                account
            ] = false;
            emit RoleRevoked(role, account, msg.sender);
        }
    }
}

File 4 of 26 : ERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

/**
 * @title ERC165 implementation
 */
abstract contract ERC165 is IERC165 {
    using ERC165Storage for ERC165Storage.Layout;

    /**
     * @inheritdoc IERC165
     */
    function supportsInterface(bytes4 interfaceId) public view returns (bool) {
        return ERC165Storage.layout().isSupportedInterface(interfaceId);
    }
}

File 5 of 26 : ERC721.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { ERC721Base, ERC721BaseInternal } from './base/ERC721Base.sol';
import { ERC721Enumerable } from './enumerable/ERC721Enumerable.sol';
import { ERC721Metadata } from './metadata/ERC721Metadata.sol';
import { ERC165 } from '../../introspection/ERC165.sol';

/**
 * @title SolidState ERC721 implementation, including recommended extensions
 */
abstract contract ERC721 is
    ERC721Base,
    ERC721Enumerable,
    ERC721Metadata,
    ERC165
{
    /**
     * @notice ERC721 hook: revert if value is included in external approve function call
     * @inheritdoc ERC721BaseInternal
     */
    function _handleApproveMessageValue(
        address operator,
        uint256 tokenId,
        uint256 value
    ) internal virtual override {
        require(value == 0, 'ERC721: payable approve calls not supported');
        super._handleApproveMessageValue(operator, tokenId, value);
    }

    /**
     * @notice ERC721 hook: revert if value is included in external transfer function call
     * @inheritdoc ERC721BaseInternal
     */
    function _handleTransferMessageValue(
        address from,
        address to,
        uint256 tokenId,
        uint256 value
    ) internal virtual override {
        require(value == 0, 'ERC721: payable transfer calls not supported');
        super._handleTransferMessageValue(from, to, tokenId, value);
    }

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

File 6 of 26 : IERC721Metadata.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @title ERC721Metadata interface
 */
interface IERC721Metadata {
    /**
     * @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 7 of 26 : ERC721MetadataStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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 8 of 26 : AccessControlStorage.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.13;

library AccessControlStorage {
    bytes32 internal constant ACCESS_CONTROL_STORAGE_SLOT =
        keccak256("DIMORegistry.accessControl.storage");

    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

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

    /* solhint-disable no-inline-assembly */
    function getStorage() internal pure returns (Storage storage s) {
        bytes32 slot = ACCESS_CONTROL_STORAGE_SLOT;
        assembly {
            s.slot := slot
        }
    }
    /* solhint-enable no-inline-assembly */
}

File 9 of 26 : IAccessControlInternal.sol
// SPDX-License-Identifier: Unlicensed
// From OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.13;

/**
 * @title Partial AccessControl interface needed by internal functions
 */
interface IAccessControlInternal {
    /**
     * @notice Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     */
    event RoleAdminChanged(
        bytes32 indexed role,
        bytes32 indexed previousAdminRole,
        bytes32 indexed newAdminRole
    );

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

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

File 10 of 26 : UintUtils.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @title utility functions for uint256 operations
 * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts/ (MIT license)
 */
library UintUtils {
    bytes16 private constant HEX_SYMBOLS = '0123456789abcdef';

    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;
            }
        }

        require(value == 0, 'UintUtils: hex length insufficient');

        return string(buffer);
    }
}

File 11 of 26 : AddressUtils.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

library AddressUtils {
    using UintUtils for uint256;

    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 }('');
        require(success, 'AddressUtils: failed to send value');
    }

    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) {
        require(
            address(this).balance >= value,
            'AddressUtils: insufficient balance for call'
        );
        return _functionCallWithValue(target, data, value, error);
    }

    function _functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory error
    ) private returns (bytes memory) {
        require(
            isContract(target),
            'AddressUtils: function call to non-contract'
        );

        (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 12 of 26 : IERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @title ERC165 interface registration interface
 * @dev see https://eips.ethereum.org/EIPS/eip-165
 */
interface IERC165 {
    /**
     * @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 13 of 26 : ERC165Storage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

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

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

    function isSupportedInterface(Layout storage l, bytes4 interfaceId)
        internal
        view
        returns (bool)
    {
        return l.supportedInterfaces[interfaceId];
    }

    function setSupportedInterface(
        Layout storage l,
        bytes4 interfaceId,
        bool status
    ) internal {
        require(interfaceId != 0xffffffff, 'ERC165: invalid interface id');
        l.supportedInterfaces[interfaceId] = status;
    }
}

File 14 of 26 : ERC721Base.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { AddressUtils } from '../../../utils/AddressUtils.sol';
import { EnumerableMap } from '../../../utils/EnumerableMap.sol';
import { EnumerableSet } from '../../../utils/EnumerableSet.sol';
import { IERC721 } from '../IERC721.sol';
import { IERC721Receiver } from '../IERC721Receiver.sol';
import { ERC721BaseStorage } from './ERC721BaseStorage.sol';
import { ERC721BaseInternal } from './ERC721BaseInternal.sol';

/**
 * @title Base ERC721 implementation, excluding optional extensions
 */
abstract contract ERC721Base is IERC721, ERC721BaseInternal {
    using AddressUtils for address;
    using EnumerableMap for EnumerableMap.UintToAddressMap;
    using EnumerableSet for EnumerableSet.UintSet;

    /**
     * @inheritdoc IERC721
     */
    function balanceOf(address account) public view returns (uint256) {
        return _balanceOf(account);
    }

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

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

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

    /**
     * @inheritdoc IERC721
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public payable {
        _handleTransferMessageValue(from, to, tokenId, msg.value);
        require(
            _isApprovedOrOwner(msg.sender, tokenId),
            'ERC721: transfer caller is not owner or approved'
        );
        _transfer(from, to, tokenId);
    }

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

    /**
     * @inheritdoc IERC721
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) public payable {
        _handleTransferMessageValue(from, to, tokenId, msg.value);
        require(
            _isApprovedOrOwner(msg.sender, tokenId),
            'ERC721: transfer caller is not owner or approved'
        );
        _safeTransfer(from, to, tokenId, data);
    }

    /**
     * @inheritdoc IERC721
     */
    function approve(address operator, uint256 tokenId) public payable {
        _handleApproveMessageValue(operator, tokenId, msg.value);
        address owner = ownerOf(tokenId);
        require(operator != owner, 'ERC721: approval to current owner');
        require(
            msg.sender == owner || isApprovedForAll(owner, msg.sender),
            'ERC721: approve caller is not owner nor approved for all'
        );
        _approve(operator, tokenId);
    }

    /**
     * @inheritdoc IERC721
     */
    function setApprovalForAll(address operator, bool status) public {
        require(operator != msg.sender, 'ERC721: approve to caller');
        ERC721BaseStorage.layout().operatorApprovals[msg.sender][
            operator
        ] = status;
        emit ApprovalForAll(msg.sender, operator, status);
    }
}

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

pragma solidity ^0.8.0;

import { EnumerableMap } from '../../../utils/EnumerableMap.sol';
import { EnumerableSet } from '../../../utils/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 16 of 26 : ERC721Metadata.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

/**
 * @title ERC721 metadata extensions
 */
abstract contract ERC721Metadata is IERC721Metadata, ERC721MetadataInternal {
    using ERC721BaseStorage for ERC721BaseStorage.Layout;
    using UintUtils for uint256;

    /**
     * @notice inheritdoc IERC721Metadata
     */
    function name() public view virtual returns (string memory) {
        return ERC721MetadataStorage.layout().name;
    }

    /**
     * @notice inheritdoc IERC721Metadata
     */
    function symbol() public view virtual returns (string memory) {
        return ERC721MetadataStorage.layout().symbol;
    }

    /**
     * @notice inheritdoc IERC721Metadata
     */
    function tokenURI(uint256 tokenId)
        public
        view
        virtual
        returns (string memory)
    {
        require(
            ERC721BaseStorage.layout().exists(tokenId),
            'ERC721Metadata: URI query for nonexistent token'
        );

        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()));
        }
    }

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

File 17 of 26 : EnumerableMap.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @title Map implementation with enumeration functions
 * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license)
 */
library EnumerableMap {
    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);
        address addressKey;
        assembly {
            addressKey := mload(add(key, 20))
        }
        return (addressKey, 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 _at(Map storage map, uint256 index)
        private
        view
        returns (bytes32, bytes32)
    {
        require(
            map._entries.length > index,
            'EnumerableMap: index out of bounds'
        );

        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];
        require(keyIndex != 0, 'EnumerableMap: nonexistent key');
        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 18 of 26 : EnumerableSet.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @title Set implementation with enumeration functions
 * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license)
 */
library EnumerableSet {
    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 _at(Set storage set, uint256 index)
        private
        view
        returns (bytes32)
    {
        require(
            set._values.length > index,
            'EnumerableSet: index out of bounds'
        );
        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) {
        if (!_contains(set, value)) {
            set._values.push(value);
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    function _remove(Set storage set, bytes32 value) private returns (bool) {
        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];

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

File 19 of 26 : IERC721.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IERC165 } from '../../introspection/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 20 of 26 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

File 21 of 26 : ERC721BaseStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { EnumerableMap } from '../../../utils/EnumerableMap.sol';
import { EnumerableSet } from '../../../utils/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
        }
    }

    function exists(Layout storage l, uint256 tokenId)
        internal
        view
        returns (bool)
    {
        return l.tokenOwners.contains(tokenId);
    }

    function totalSupply(Layout storage l) internal view returns (uint256) {
        return l.tokenOwners.length();
    }

    function tokenOfOwnerByIndex(
        Layout storage l,
        address owner,
        uint256 index
    ) internal view returns (uint256) {
        return l.holderTokens[owner].at(index);
    }

    function tokenByIndex(Layout storage l, uint256 index)
        internal
        view
        returns (uint256)
    {
        (uint256 tokenId, ) = l.tokenOwners.at(index);
        return tokenId;
    }
}

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

pragma solidity ^0.8.0;

import { AddressUtils } from '../../../utils/AddressUtils.sol';
import { EnumerableMap } from '../../../utils/EnumerableMap.sol';
import { EnumerableSet } from '../../../utils/EnumerableSet.sol';
import { IERC721Internal } from '../IERC721Internal.sol';
import { IERC721Receiver } from '../IERC721Receiver.sol';
import { ERC721BaseStorage } from './ERC721BaseStorage.sol';

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

    function _balanceOf(address account) internal view returns (uint256) {
        require(
            account != address(0),
            'ERC721: balance query for the zero address'
        );
        return ERC721BaseStorage.layout().holderTokens[account].length();
    }

    function _ownerOf(uint256 tokenId) internal view returns (address) {
        address owner = ERC721BaseStorage.layout().tokenOwners.get(tokenId);
        require(owner != address(0), 'ERC721: invalid owner');
        return owner;
    }

    function _getApproved(uint256 tokenId) internal view returns (address) {
        ERC721BaseStorage.Layout storage l = ERC721BaseStorage.layout();

        require(
            l.exists(tokenId),
            'ERC721: approved query for nonexistent token'
        );

        return l.tokenApprovals[tokenId];
    }

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

    function _isApprovedOrOwner(address spender, uint256 tokenId)
        internal
        view
        returns (bool)
    {
        require(
            ERC721BaseStorage.layout().exists(tokenId),
            'ERC721: query for nonexistent token'
        );

        address owner = _ownerOf(tokenId);

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

    function _mint(address to, uint256 tokenId) internal {
        require(to != address(0), 'ERC721: mint to the zero address');

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

        require(!l.exists(tokenId), 'ERC721: token already minted');

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

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

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

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

    function _safeMint(
        address to,
        uint256 tokenId,
        bytes memory data
    ) internal {
        _mint(to, tokenId);
        require(
            _checkOnERC721Received(address(0), to, tokenId, data),
            'ERC721: transfer to non ERC721Receiver implementer'
        );
    }

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

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

        _approve(address(0), tokenId);

        ERC721BaseStorage.Layout storage l = ERC721BaseStorage.layout();
        l.holderTokens[owner].remove(tokenId);
        l.tokenOwners.remove(tokenId);

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

    function _transfer(
        address from,
        address to,
        uint256 tokenId
    ) internal {
        require(
            _ownerOf(tokenId) == from,
            'ERC721: transfer of token that is not own'
        );
        require(to != address(0), 'ERC721: transfer to the zero address');

        _beforeTokenTransfer(from, to, tokenId);

        _approve(address(0), tokenId);

        ERC721BaseStorage.Layout storage l = ERC721BaseStorage.layout();
        l.holderTokens[from].remove(tokenId);
        l.holderTokens[to].add(tokenId);
        l.tokenOwners.set(tokenId, to);

        emit Transfer(from, to, tokenId);
    }

    function _safeTransfer(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) internal {
        _transfer(from, to, tokenId);
        require(
            _checkOnERC721Received(from, to, tokenId, data),
            'ERC721: transfer to non ERC721Receiver implementer'
        );
    }

    function _approve(address operator, uint256 tokenId) internal {
        ERC721BaseStorage.layout().tokenApprovals[tokenId] = operator;
        emit Approval(_ownerOf(tokenId), operator, tokenId);
    }

    function _checkOnERC721Received(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) internal 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 26 : IERC721Internal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @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 24 of 26 : IERC721Enumerable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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 25 of 26 : ERC721EnumerableInternal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

abstract contract ERC721EnumerableInternal {
    using ERC721BaseStorage for ERC721BaseStorage.Layout;

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

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

    /**
     * @notice TODO
     */
    function _tokenByIndex(uint256 index) internal view returns (uint256) {
        return ERC721BaseStorage.layout().tokenByIndex(index);
    }
}

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

pragma solidity ^0.8.0;

import { ERC721BaseInternal } from '../base/ERC721Base.sol';
import { ERC721MetadataStorage } from './ERC721MetadataStorage.sol';

/**
 * @title ERC721Metadata internal functions
 */
abstract contract ERC721MetadataInternal is ERC721BaseInternal {
    /**
     * @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];
        }
    }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"string","name":"__baseURI","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"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":"address","name":"moduleAddr","type":"address"},{"indexed":false,"internalType":"bytes4[]","name":"selectors","type":"bytes4[]"}],"name":"ModuleAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"moduleAddr","type":"address"},{"indexed":false,"internalType":"bytes4[]","name":"selectors","type":"bytes4[]"}],"name":"ModuleRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldImplementation","type":"address"},{"indexed":true,"internalType":"address","name":"newImplementation","type":"address"},{"indexed":false,"internalType":"bytes4[]","name":"oldSelectors","type":"bytes4[]"},{"indexed":false,"internalType":"bytes4[]","name":"newSelectors","type":"bytes4[]"}],"name":"ModuleUpdated","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"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"},{"internalType":"bytes4[]","name":"selectors","type":"bytes4[]"}],"name":"addModule","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":"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":"address","name":"implementation","type":"address"},{"internalType":"bytes4[]","name":"selectors","type":"bytes4[]"}],"name":"removeModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"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"},{"inputs":[{"internalType":"address","name":"oldImplementation","type":"address"},{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes4[]","name":"oldSelectors","type":"bytes4[]"},{"internalType":"bytes4[]","name":"newSelectors","type":"bytes4[]"}],"name":"updateModule","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60806040523480156200001157600080fd5b5060405162004ef338038062004ef383398181016040528101906200003791906200068b565b6200004c6000801b336200016260201b60201c565b6000620000636200025b60201b62000e701760201c565b9050838160000190805190602001906200007f9291906200043e565b50828160010190805190602001906200009a9291906200043e565b5081816002019080519060200190620000b59291906200043e565b50620001077f01ffc9a7000000000000000000000000000000000000000000000000000000006001620000f26200028860201b62000e9d1760201c565b620002b560201b62000eca179092919060201c565b620001587f5b5e139f000000000000000000000000000000000000000000000000000000006001620001436200028860201b62000e9d1760201c565b620002b560201b62000eca179092919060201c565b505050506200082b565b6200017482826200039060201b60201c565b62000257576001620001906200041160201b62000fa21760201c565b600001600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055503373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b6000807f99574a7094154bb123ae6ae102096f0bf9679b85a5cd1e727aaa0ae5f132e6b190508091505090565b6000807f326d0c59a7612f6a9919e2a8ee333c80ba689d8ba2634de89c85cbb04832e70590508091505090565b63ffffffff60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160362000320576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200031790620007a5565b60405180910390fd5b80836000016000847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060006101000a81548160ff021916908315150217905550505050565b6000620003a76200041160201b62000fa21760201c565b600001600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6000807f0166504e5ccb463bc7d5bd33317cff1a2c4b9d767f1c547638f719d36741a1d090508091505090565b8280546200044c90620007f6565b90600052602060002090601f016020900481019282620004705760008555620004bc565b82601f106200048b57805160ff1916838001178555620004bc565b82800160010185558215620004bc579182015b82811115620004bb5782518255916020019190600101906200049e565b5b509050620004cb9190620004cf565b5090565b5b80821115620004ea576000816000905550600101620004d0565b5090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b62000557826200050c565b810181811067ffffffffffffffff821117156200057957620005786200051d565b5b80604052505050565b60006200058e620004ee565b90506200059c82826200054c565b919050565b600067ffffffffffffffff821115620005bf57620005be6200051d565b5b620005ca826200050c565b9050602081019050919050565b60005b83811015620005f7578082015181840152602081019050620005da565b8381111562000607576000848401525b50505050565b6000620006246200061e84620005a1565b62000582565b90508281526020810184848401111562000643576200064262000507565b5b62000650848285620005d7565b509392505050565b600082601f83011262000670576200066f62000502565b5b8151620006828482602086016200060d565b91505092915050565b600080600060608486031215620006a757620006a6620004f8565b5b600084015167ffffffffffffffff811115620006c857620006c7620004fd565b5b620006d68682870162000658565b935050602084015167ffffffffffffffff811115620006fa57620006f9620004fd565b5b620007088682870162000658565b925050604084015167ffffffffffffffff8111156200072c576200072b620004fd565b5b6200073a8682870162000658565b9150509250925092565b600082825260208201905092915050565b7f4552433136353a20696e76616c696420696e7465726661636520696400000000600082015250565b60006200078d601c8362000744565b91506200079a8262000755565b602082019050919050565b60006020820190508181036000830152620007c0816200077e565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200080f57607f821691505b602082108103620008255762000824620007c7565b5b50919050565b6146b8806200083b6000396000f3fe6080604052600436106101185760003560e01c806342842e0e116100a05780639748a762116100645780639748a76214610483578063a22cb465146104ac578063b88d4fde146104d5578063c87b56dd146104f1578063e985e9c51461052e57610119565b806342842e0e146103855780634f6ccce7146103a15780636352211e146103de57806370a082311461041b57806395d89b411461045857610119565b8063095ea7b3116100e7578063095ea7b3146102bc5780630df5b997146102d857806318160ddd1461030157806323b872dd1461032c5780632f745c591461034857610119565b806301ffc9a7146101ee57806306d1d2a11461022b57806306fdde0314610254578063081812fc1461027f57610119565b5b34801561012557600080fd5b50600061013061056b565b600101600080357fffffffff00000000000000000000000000000000000000000000000000000000167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690503660008037600080366000845af43d6000803e80600081146101e9573d6000f35b3d6000fd5b3480156101fa57600080fd5b5061021560048036038101906102109190612cde565b610598565b6040516102229190612d26565b60405180910390f35b34801561023757600080fd5b50610252600480360381019061024d9190612e04565b6105bb565b005b34801561026057600080fd5b50610269610652565b6040516102769190612f44565b60405180910390f35b34801561028b57600080fd5b506102a660048036038101906102a19190612f9c565b6106ed565b6040516102b39190612fd8565b60405180910390f35b6102d660048036038101906102d19190612ff3565b6106ff565b005b3480156102e457600080fd5b506102ff60048036038101906102fa9190613033565b610813565b005b34801561030d57600080fd5b50610316610881565b60405161032391906130a2565b60405180910390f35b610346600480360381019061034191906130bd565b610890565b005b34801561035457600080fd5b5061036f600480360381019061036a9190612ff3565b6108f5565b60405161037c91906130a2565b60405180910390f35b61039f600480360381019061039a91906130bd565b610909565b005b3480156103ad57600080fd5b506103c860048036038101906103c39190612f9c565b610929565b6040516103d591906130a2565b60405180910390f35b3480156103ea57600080fd5b5061040560048036038101906104009190612f9c565b61093b565b6040516104129190612fd8565b60405180910390f35b34801561042757600080fd5b50610442600480360381019061043d9190613110565b61094d565b60405161044f91906130a2565b60405180910390f35b34801561046457600080fd5b5061046d61095f565b60405161047a9190612f44565b60405180910390f35b34801561048f57600080fd5b506104aa60048036038101906104a59190613033565b6109fa565b005b3480156104b857600080fd5b506104d360048036038101906104ce9190613169565b610a68565b005b6104ef60048036038101906104ea91906132d9565b610bdc565b005b3480156104fd57600080fd5b5061051860048036038101906105139190612f9c565b610c43565b6040516105259190612f44565b60405180910390f35b34801561053a57600080fd5b506105556004803603810190610550919061335c565b610e5c565b6040516105629190612d26565b60405180910390f35b6000807f334bcdc01ad42928dc76b974b9dc2d08aef6ae80f647d452bdc48c2baf971e8890508091505090565b60006105b4826105a6610e9d565b610fcf90919063ffffffff16565b9050919050565b6000801b6105c88161103a565b6105d3878686611047565b6105de8684846112ee565b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fa062c2c046aa14dc9284b13bde77061cb034f0aa820f20057af6b164651eaa0887878787604051610641949392919061345f565b60405180910390a350505050505050565b606061065c610e70565b600001805461066a906134c9565b80601f0160208091040260200160405190810160405280929190818152602001828054610696906134c9565b80156106e35780601f106106b8576101008083540402835291602001916106e3565b820191906000526020600020905b8154815290600101906020018083116106c657829003601f168201915b5050505050905090565b60006106f8826115de565b9050919050565b61070a82823461167b565b60006107158261093b565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610785576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161077c9061356c565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806107c557506107c48133610e5c565b5b610804576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107fb906135fe565b60405180910390fd5b61080e83836116ce565b505050565b6000801b6108208161103a565b61082b8484846112ee565b8373ffffffffffffffffffffffffffffffffffffffff167f02d0c334c706cd2f08faf7bc03674fc7f3970dd8921776c655069cde33b7fb29848460405161087392919061361e565b60405180910390a250505050565b600061088b611790565b905090565b61089c838383346117a7565b6108a633826117fc565b6108e5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108dc906136b4565b60405180910390fd5b6108f08383836118eb565b505050565b60006109018383611b14565b905092915050565b61092483838360405180602001604052806000815250610bdc565b505050565b600061093482611b3a565b9050919050565b600061094682611b5d565b9050919050565b600061095882611bf7565b9050919050565b6060610969610e70565b6001018054610977906134c9565b80601f01602080910402602001604051908101604052809291908181526020018280546109a3906134c9565b80156109f05780601f106109c5576101008083540402835291602001916109f0565b820191906000526020600020905b8154815290600101906020018083116109d357829003601f168201915b5050505050905090565b6000801b610a078161103a565b610a12848484611047565b8373ffffffffffffffffffffffffffffffffffffffff167f7c3eb4f9083f75cbed2bd3f703e24b4bbcb77d345d3c50945f3abf3e967755cb8484604051610a5a92919061361e565b60405180910390a250505050565b3373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610ad6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610acd90613720565b60405180910390fd5b80610adf611cbe565b60040160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051610bd09190612d26565b60405180910390a35050565b610be8848484346117a7565b610bf233836117fc565b610c31576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c28906136b4565b60405180910390fd5b610c3d84848484611ceb565b50505050565b6060610c5f82610c51611cbe565b611d4790919063ffffffff16565b610c9e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c95906137b2565b60405180910390fd5b6000610ca8610e70565b905060008160030160008581526020019081526020016000208054610ccc906134c9565b80601f0160208091040260200160405190810160405280929190818152602001828054610cf8906134c9565b8015610d455780601f10610d1a57610100808354040283529160200191610d45565b820191906000526020600020905b815481529060010190602001808311610d2857829003601f168201915b505050505090506000826002018054610d5d906134c9565b80601f0160208091040260200160405190810160405280929190818152602001828054610d89906134c9565b8015610dd65780601f10610dab57610100808354040283529160200191610dd6565b820191906000526020600020905b815481529060010190602001808311610db957829003601f168201915b505050505090506000815103610df157819350505050610e57565b600082511115610e27578082604051602001610e0e92919061380e565b6040516020818303038152906040529350505050610e57565b80610e3186611d67565b604051602001610e4292919061380e565b60405160208183030381529060405293505050505b919050565b6000610e688383611ec7565b905092915050565b6000807f99574a7094154bb123ae6ae102096f0bf9679b85a5cd1e727aaa0ae5f132e6b190508091505090565b6000807f326d0c59a7612f6a9919e2a8ee333c80ba689d8ba2634de89c85cbb04832e70590508091505090565b63ffffffff60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603610f32576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f299061387e565b60405180910390fd5b80836000016000847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060006101000a81548160ff021916908315150217905550505050565b6000807f0166504e5ccb463bc7d5bd33317cff1a2c4b9d767f1c547638f719d36741a1d090508091505090565b6000826000016000837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060009054906101000a900460ff16905092915050565b6110448133611f64565b50565b600061105161056b565b90506000838360405160200161106892919061361e565b604051602081830303815290604052805190602001209050808260020160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414611103576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110fa906138ea565b60405180910390fd5b60005b848490508110156112e6578573ffffffffffffffffffffffffffffffffffffffff168360010160008787858181106111415761114061390a565b5b90506020020160208101906111569190612cde565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611219576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161121090613985565b60405180910390fd5b60008360010160008787858181106112345761123361390a565b5b90506020020160208101906112499190612cde565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080806112de906139d4565b915050611106565b505050505050565b60006112f861056b565b90506000801b8160020160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414611380576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161137790613a68565b60405180910390fd5b60005b8383905081101561156357600073ffffffffffffffffffffffffffffffffffffffff168260010160008686858181106113bf576113be61390a565b5b90506020020160208101906113d49190612cde565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611497576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161148e90613ad4565b60405180910390fd5b848260010160008686858181106114b1576114b061390a565b5b90506020020160208101906114c69190612cde565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808061155b906139d4565b915050611383565b506000838360405160200161157992919061361e565b604051602081830303815290604052805190602001209050808260020160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505050505050565b6000806115e9611cbe565b90506115fe8382611d4790919063ffffffff16565b61163d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161163490613b66565b60405180910390fd5b80600301600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16915050919050565b600081146116be576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116b590613bf8565b60405180910390fd5b6116c9838383612008565b505050565b816116d7611cbe565b600301600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff1661174a83611b5d565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60006117a261179d611cbe565b61200d565b905090565b600081146117ea576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117e190613c8a565b60405180910390fd5b6117f684848484612022565b50505050565b60006118188261180a611cbe565b611d4790919063ffffffff16565b611857576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161184e90613d1c565b60405180910390fd5b600061186283611b5d565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614806118d157508373ffffffffffffffffffffffffffffffffffffffff166118b9846115de565b73ffffffffffffffffffffffffffffffffffffffff16145b806118e257506118e18185611ec7565b5b91505092915050565b8273ffffffffffffffffffffffffffffffffffffffff1661190b82611b5d565b73ffffffffffffffffffffffffffffffffffffffff1614611961576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161195890613dae565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036119d0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119c790613e40565b60405180910390fd5b6119db838383612028565b6119e66000826116ce565b60006119f0611cbe565b9050611a45828260020160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002061203890919063ffffffff16565b50611a99828260020160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002061205290919063ffffffff16565b50611ab282848360000161206c9092919063ffffffff16565b50818373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a450505050565b6000611b328383611b23611cbe565b6120a19092919063ffffffff16565b905092915050565b6000611b5682611b48611cbe565b6120ff90919063ffffffff16565b9050919050565b600080611b7d83611b6c611cbe565b60000161212590919063ffffffff16565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611bee576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611be590613eac565b60405180910390fd5b80915050919050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611c67576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c5e90613f3e565b60405180910390fd5b611cb7611c72611cbe565b60020160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020612142565b9050919050565b6000807f3c7bf052874fa81625121783266a03507bd2cd48b16e571c01a04e8dd3fb07a690508091505090565b611cf68484846118eb565b611d0284848484612157565b611d41576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d3890613fd0565b60405180910390fd5b50505050565b6000611d5f82846000016122cd90919063ffffffff16565b905092915050565b606060008203611dae576040518060400160405280600181526020017f30000000000000000000000000000000000000000000000000000000000000008152509050611ec2565b600082905060005b60008214611de0578080611dc9906139d4565b915050600a82611dd9919061401f565b9150611db6565b60008167ffffffffffffffff811115611dfc57611dfb6131ae565b5b6040519080825280601f01601f191660200182016040528015611e2e5781602001600182028036833780820191505090505b5090505b60008514611ebb57600182611e479190614050565b9150600a85611e569190614084565b6030611e6291906140b5565b60f81b818381518110611e7857611e7761390a565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a85611eb4919061401f565b9450611e32565b8093505050505b919050565b6000611ed1611cbe565b60040160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b611f6e82826122e7565b61200457611f918173ffffffffffffffffffffffffffffffffffffffff1661235b565b611fa860208460001c61238e90919063ffffffff16565b604051602001611fb99291906141a3565b6040516020818303038152906040526040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ffb9190612f44565b60405180910390fd5b5050565b505050565b600061201b826000016125b3565b9050919050565b50505050565b6120338383836125c8565b505050565b600061204a836000018360001b6125d8565b905092915050565b6000612064836000018360001b6126c6565b905092915050565b6000612098846000018460001b8473ffffffffffffffffffffffffffffffffffffffff1660001b612736565b90509392505050565b60006120f6828560020160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002061281890919063ffffffff16565b90509392505050565b600080612118838560000161283290919063ffffffff16565b5090508091505092915050565b6000612137836000018360001b61285e565b60001c905092915050565b6000612150826000016128f0565b9050919050565b60006121788473ffffffffffffffffffffffffffffffffffffffff16612901565b61218557600190506122c5565b600061224563150b7a0260e01b338887876040516024016121a99493929190614232565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051806060016040528060328152602001614651603291398773ffffffffffffffffffffffffffffffffffffffff166129149092919063ffffffff16565b905060008180602001905181019061225d9190614293565b90507f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614925050505b949350505050565b60006122df836000018360001b61292c565b905092915050565b60006122f1610fa2565b600001600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b606061238760148373ffffffffffffffffffffffffffffffffffffffff1661238e90919063ffffffff16565b9050919050565b6060600060028360026123a191906142c0565b6123ab91906140b5565b67ffffffffffffffff8111156123c4576123c36131ae565b5b6040519080825280601f01601f1916602001820160405280156123f65781602001600182028036833780820191505090505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811061242e5761242d61390a565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f7800000000000000000000000000000000000000000000000000000000000000816001815181106124925761249161390a565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006001846002020190505b6001811115612565577f3031323334353637383961626364656600000000000000000000000000000000600f86166010811061250c5761250b61390a565b5b1a60f81b8282815181106125235761252261390a565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600485901c9450806001900390506124cd565b50600084146125a9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016125a09061438c565b60405180910390fd5b8091505092915050565b60006125c18260000161294f565b9050919050565b6125d3838383612960565b505050565b600080836001016000848152602001908152602001600020549050600081146126ba5760008460000160018660000180549050038154811061261d5761261c61390a565b5b90600052602060002001549050808560000160018403815481106126445761264361390a565b5b906000526020600020018190555081856001016000838152602001908152602001600020819055505083600001805480612681576126806143ac565b5b600190038181906000526020600020016000905590558360010160008481526020019081526020016000206000905560019150506126c0565b60009150505b92915050565b60006126d283836129cd565b61272b578260000182908060018154018082558091505060019003906000526020600020016000909190919091505582600001805490508360010160008481526020019081526020016000208190555060019050612730565b600090505b92915050565b600080846001016000858152602001908152602001600020549050600081036127dc57846000016040518060400160405280868152602001858152509080600181540180825580915050600190039060005260206000209060020201600090919091909150600082015181600001556020820151816001015550508460000180549050856001016000868152602001908152602001600020819055506001915050612811565b828560000160018303815481106127f6576127f561390a565b5b90600052602060002090600202016001018190555060009150505b9392505050565b600061282783600001836129f0565b60001c905092915050565b6000806000806128458660000186612a64565b915091508160001c8160001c9350935050509250929050565b600080836001016000848152602001908152602001600020549050600081036128bc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016128b390614427565b60405180910390fd5b8360000160018203815481106128d5576128d461390a565b5b90600052602060002090600202016001015491505092915050565b600081600001805490509050919050565b600080823b905060008111915050919050565b60606129238484600085612aee565b90509392505050565b600080836001016000848152602001908152602001600020541415905092915050565b600081600001805490509050919050565b61296b838383612c10565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036129c8576129a7610e70565b600301600082815260200190815260200160002060006129c79190612c15565b5b505050565b600080836001016000848152602001908152602001600020541415905092915050565b600081836000018054905011612a3b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a32906144b9565b60405180910390fd5b826000018281548110612a5157612a5061390a565b5b9060005260206000200154905092915050565b60008082846000018054905011612ab0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612aa79061454b565b60405180910390fd5b6000846000018481548110612ac857612ac761390a565b5b906000526020600020906002020190508060000154816001015492509250509250929050565b6060612af985612901565b612b38576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612b2f906145dd565b60405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612b619190614639565b60006040518083038185875af1925050503d8060008114612b9e576040519150601f19603f3d011682016040523d82523d6000602084013e612ba3565b606091505b50915091508115612bb8578092505050612c08565b600081511115612bcb5780518082602001fd5b836040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612bff9190612f44565b60405180910390fd5b949350505050565b505050565b508054612c21906134c9565b6000825580601f10612c335750612c52565b601f016020900490600052602060002090810190612c519190612c55565b5b50565b5b80821115612c6e576000816000905550600101612c56565b5090565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b612cbb81612c86565b8114612cc657600080fd5b50565b600081359050612cd881612cb2565b92915050565b600060208284031215612cf457612cf3612c7c565b5b6000612d0284828501612cc9565b91505092915050565b60008115159050919050565b612d2081612d0b565b82525050565b6000602082019050612d3b6000830184612d17565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612d6c82612d41565b9050919050565b612d7c81612d61565b8114612d8757600080fd5b50565b600081359050612d9981612d73565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f840112612dc457612dc3612d9f565b5b8235905067ffffffffffffffff811115612de157612de0612da4565b5b602083019150836020820283011115612dfd57612dfc612da9565b5b9250929050565b60008060008060008060808789031215612e2157612e20612c7c565b5b6000612e2f89828a01612d8a565b9650506020612e4089828a01612d8a565b955050604087013567ffffffffffffffff811115612e6157612e60612c81565b5b612e6d89828a01612dae565b9450945050606087013567ffffffffffffffff811115612e9057612e8f612c81565b5b612e9c89828a01612dae565b92509250509295509295509295565b600081519050919050565b600082825260208201905092915050565b60005b83811015612ee5578082015181840152602081019050612eca565b83811115612ef4576000848401525b50505050565b6000601f19601f8301169050919050565b6000612f1682612eab565b612f208185612eb6565b9350612f30818560208601612ec7565b612f3981612efa565b840191505092915050565b60006020820190508181036000830152612f5e8184612f0b565b905092915050565b6000819050919050565b612f7981612f66565b8114612f8457600080fd5b50565b600081359050612f9681612f70565b92915050565b600060208284031215612fb257612fb1612c7c565b5b6000612fc084828501612f87565b91505092915050565b612fd281612d61565b82525050565b6000602082019050612fed6000830184612fc9565b92915050565b6000806040838503121561300a57613009612c7c565b5b600061301885828601612d8a565b925050602061302985828601612f87565b9150509250929050565b60008060006040848603121561304c5761304b612c7c565b5b600061305a86828701612d8a565b935050602084013567ffffffffffffffff81111561307b5761307a612c81565b5b61308786828701612dae565b92509250509250925092565b61309c81612f66565b82525050565b60006020820190506130b76000830184613093565b92915050565b6000806000606084860312156130d6576130d5612c7c565b5b60006130e486828701612d8a565b93505060206130f586828701612d8a565b925050604061310686828701612f87565b9150509250925092565b60006020828403121561312657613125612c7c565b5b600061313484828501612d8a565b91505092915050565b61314681612d0b565b811461315157600080fd5b50565b6000813590506131638161313d565b92915050565b600080604083850312156131805761317f612c7c565b5b600061318e85828601612d8a565b925050602061319f85828601613154565b9150509250929050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6131e682612efa565b810181811067ffffffffffffffff82111715613205576132046131ae565b5b80604052505050565b6000613218612c72565b905061322482826131dd565b919050565b600067ffffffffffffffff821115613244576132436131ae565b5b61324d82612efa565b9050602081019050919050565b82818337600083830152505050565b600061327c61327784613229565b61320e565b905082815260208101848484011115613298576132976131a9565b5b6132a384828561325a565b509392505050565b600082601f8301126132c0576132bf612d9f565b5b81356132d0848260208601613269565b91505092915050565b600080600080608085870312156132f3576132f2612c7c565b5b600061330187828801612d8a565b945050602061331287828801612d8a565b935050604061332387828801612f87565b925050606085013567ffffffffffffffff81111561334457613343612c81565b5b613350878288016132ab565b91505092959194509250565b6000806040838503121561337357613372612c7c565b5b600061338185828601612d8a565b925050602061339285828601612d8a565b9150509250929050565b600082825260208201905092915050565b6000819050919050565b6133c081612c86565b82525050565b60006133d283836133b7565b60208301905092915050565b60006133ed6020840184612cc9565b905092915050565b6000602082019050919050565b600061340e838561339c565b9350613419826133ad565b8060005b858110156134525761342f82846133de565b61343988826133c6565b9750613444836133f5565b92505060018101905061341d565b5085925050509392505050565b6000604082019050818103600083015261347a818688613402565b9050818103602083015261348f818486613402565b905095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806134e157607f821691505b6020821081036134f4576134f361349a565b5b50919050565b7f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560008201527f7200000000000000000000000000000000000000000000000000000000000000602082015250565b6000613556602183612eb6565b9150613561826134fa565b604082019050919050565b6000602082019050818103600083015261358581613549565b9050919050565b7f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760008201527f6e6572206e6f7220617070726f76656420666f7220616c6c0000000000000000602082015250565b60006135e8603883612eb6565b91506135f38261358c565b604082019050919050565b60006020820190508181036000830152613617816135db565b9050919050565b60006020820190508181036000830152613639818486613402565b90509392505050565b7f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60008201527f776e6572206f7220617070726f76656400000000000000000000000000000000602082015250565b600061369e603083612eb6565b91506136a982613642565b604082019050919050565b600060208201905081810360008301526136cd81613691565b9050919050565b7f4552433732313a20617070726f766520746f2063616c6c657200000000000000600082015250565b600061370a601983612eb6565b9150613715826136d4565b602082019050919050565b60006020820190508181036000830152613739816136fd565b9050919050565b7f4552433732314d657461646174613a2055524920717565727920666f72206e6f60008201527f6e6578697374656e7420746f6b656e0000000000000000000000000000000000602082015250565b600061379c602f83612eb6565b91506137a782613740565b604082019050919050565b600060208201905081810360008301526137cb8161378f565b9050919050565b600081905092915050565b60006137e882612eab565b6137f281856137d2565b9350613802818560208601612ec7565b80840191505092915050565b600061381a82856137dd565b915061382682846137dd565b91508190509392505050565b7f4552433136353a20696e76616c696420696e7465726661636520696400000000600082015250565b6000613868601c83612eb6565b915061387382613832565b602082019050919050565b600060208201905081810360008301526138978161385b565b9050919050565b7f496e76616c69642073656c6563746f72206c6973740000000000000000000000600082015250565b60006138d4601583612eb6565b91506138df8261389e565b602082019050919050565b60006020820190508181036000830152613903816138c7565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f556e726567697374657265642073656c6563746f720000000000000000000000600082015250565b600061396f601583612eb6565b915061397a82613939565b602082019050919050565b6000602082019050818103600083015261399e81613962565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006139df82612f66565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613a1157613a106139a5565b5b600182019050919050565b7f496d706c656d656e746174696f6e20616c726561647920657869737473000000600082015250565b6000613a52601d83612eb6565b9150613a5d82613a1c565b602082019050919050565b60006020820190508181036000830152613a8181613a45565b9050919050565b7f53656c6563746f7220616c726561647920726567697374657265640000000000600082015250565b6000613abe601b83612eb6565b9150613ac982613a88565b602082019050919050565b60006020820190508181036000830152613aed81613ab1565b9050919050565b7f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860008201527f697374656e7420746f6b656e0000000000000000000000000000000000000000602082015250565b6000613b50602c83612eb6565b9150613b5b82613af4565b604082019050919050565b60006020820190508181036000830152613b7f81613b43565b9050919050565b7f4552433732313a2070617961626c6520617070726f76652063616c6c73206e6f60008201527f7420737570706f72746564000000000000000000000000000000000000000000602082015250565b6000613be2602b83612eb6565b9150613bed82613b86565b604082019050919050565b60006020820190508181036000830152613c1181613bd5565b9050919050565b7f4552433732313a2070617961626c65207472616e736665722063616c6c73206e60008201527f6f7420737570706f727465640000000000000000000000000000000000000000602082015250565b6000613c74602c83612eb6565b9150613c7f82613c18565b604082019050919050565b60006020820190508181036000830152613ca381613c67565b9050919050565b7f4552433732313a20717565727920666f72206e6f6e6578697374656e7420746f60008201527f6b656e0000000000000000000000000000000000000000000000000000000000602082015250565b6000613d06602383612eb6565b9150613d1182613caa565b604082019050919050565b60006020820190508181036000830152613d3581613cf9565b9050919050565b7f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960008201527f73206e6f74206f776e0000000000000000000000000000000000000000000000602082015250565b6000613d98602983612eb6565b9150613da382613d3c565b604082019050919050565b60006020820190508181036000830152613dc781613d8b565b9050919050565b7f4552433732313a207472616e7366657220746f20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b6000613e2a602483612eb6565b9150613e3582613dce565b604082019050919050565b60006020820190508181036000830152613e5981613e1d565b9050919050565b7f4552433732313a20696e76616c6964206f776e65720000000000000000000000600082015250565b6000613e96601583612eb6565b9150613ea182613e60565b602082019050919050565b60006020820190508181036000830152613ec581613e89565b9050919050565b7f4552433732313a2062616c616e636520717565727920666f7220746865207a6560008201527f726f206164647265737300000000000000000000000000000000000000000000602082015250565b6000613f28602a83612eb6565b9150613f3382613ecc565b604082019050919050565b60006020820190508181036000830152613f5781613f1b565b9050919050565b7f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560008201527f63656976657220696d706c656d656e7465720000000000000000000000000000602082015250565b6000613fba603283612eb6565b9150613fc582613f5e565b604082019050919050565b60006020820190508181036000830152613fe981613fad565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600061402a82612f66565b915061403583612f66565b92508261404557614044613ff0565b5b828204905092915050565b600061405b82612f66565b915061406683612f66565b925082821015614079576140786139a5565b5b828203905092915050565b600061408f82612f66565b915061409a83612f66565b9250826140aa576140a9613ff0565b5b828206905092915050565b60006140c082612f66565b91506140cb83612f66565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115614100576140ff6139a5565b5b828201905092915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000600082015250565b60006141416017836137d2565b915061414c8261410b565b601782019050919050565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000600082015250565b600061418d6011836137d2565b915061419882614157565b601182019050919050565b60006141ae82614134565b91506141ba82856137dd565b91506141c582614180565b91506141d182846137dd565b91508190509392505050565b600081519050919050565b600082825260208201905092915050565b6000614204826141dd565b61420e81856141e8565b935061421e818560208601612ec7565b61422781612efa565b840191505092915050565b60006080820190506142476000830187612fc9565b6142546020830186612fc9565b6142616040830185613093565b818103606083015261427381846141f9565b905095945050505050565b60008151905061428d81612cb2565b92915050565b6000602082840312156142a9576142a8612c7c565b5b60006142b78482850161427e565b91505092915050565b60006142cb82612f66565b91506142d683612f66565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561430f5761430e6139a5565b5b828202905092915050565b7f55696e745574696c733a20686578206c656e67746820696e737566666963696560008201527f6e74000000000000000000000000000000000000000000000000000000000000602082015250565b6000614376602283612eb6565b91506143818261431a565b604082019050919050565b600060208201905081810360008301526143a581614369565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f456e756d657261626c654d61703a206e6f6e6578697374656e74206b65790000600082015250565b6000614411601e83612eb6565b915061441c826143db565b602082019050919050565b6000602082019050818103600083015261444081614404565b9050919050565b7f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e60008201527f6473000000000000000000000000000000000000000000000000000000000000602082015250565b60006144a3602283612eb6565b91506144ae82614447565b604082019050919050565b600060208201905081810360008301526144d281614496565b9050919050565b7f456e756d657261626c654d61703a20696e646578206f7574206f6620626f756e60008201527f6473000000000000000000000000000000000000000000000000000000000000602082015250565b6000614535602283612eb6565b9150614540826144d9565b604082019050919050565b6000602082019050818103600083015261456481614528565b9050919050565b7f416464726573735574696c733a2066756e6374696f6e2063616c6c20746f206e60008201527f6f6e2d636f6e7472616374000000000000000000000000000000000000000000602082015250565b60006145c7602b83612eb6565b91506145d28261456b565b604082019050919050565b600060208201905081810360008301526145f6816145ba565b9050919050565b600081905092915050565b6000614613826141dd565b61461d81856145fd565b935061462d818560208601612ec7565b80840191505092915050565b60006146458284614608565b91508190509291505056fe4552433732313a207472616e7366657220746f206e6f6e20455243373231526563656976657220696d706c656d656e746572a264697066735822122016b6e7043e551b384240023a250e0d348d798088b1e4a195d832c1394c20bb9264736f6c634300080d0033000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000001544494d4f206964656e7469747920426574612056310000000000000000000000000000000000000000000000000000000000000000000000000000000000000a44494d4f42657461563100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002668747470733a2f2f646576696365732d6170692e64696d6f2e7a6f6e652f76312f6e6674732f0000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x6080604052600436106101185760003560e01c806342842e0e116100a05780639748a762116100645780639748a76214610483578063a22cb465146104ac578063b88d4fde146104d5578063c87b56dd146104f1578063e985e9c51461052e57610119565b806342842e0e146103855780634f6ccce7146103a15780636352211e146103de57806370a082311461041b57806395d89b411461045857610119565b8063095ea7b3116100e7578063095ea7b3146102bc5780630df5b997146102d857806318160ddd1461030157806323b872dd1461032c5780632f745c591461034857610119565b806301ffc9a7146101ee57806306d1d2a11461022b57806306fdde0314610254578063081812fc1461027f57610119565b5b34801561012557600080fd5b50600061013061056b565b600101600080357fffffffff00000000000000000000000000000000000000000000000000000000167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690503660008037600080366000845af43d6000803e80600081146101e9573d6000f35b3d6000fd5b3480156101fa57600080fd5b5061021560048036038101906102109190612cde565b610598565b6040516102229190612d26565b60405180910390f35b34801561023757600080fd5b50610252600480360381019061024d9190612e04565b6105bb565b005b34801561026057600080fd5b50610269610652565b6040516102769190612f44565b60405180910390f35b34801561028b57600080fd5b506102a660048036038101906102a19190612f9c565b6106ed565b6040516102b39190612fd8565b60405180910390f35b6102d660048036038101906102d19190612ff3565b6106ff565b005b3480156102e457600080fd5b506102ff60048036038101906102fa9190613033565b610813565b005b34801561030d57600080fd5b50610316610881565b60405161032391906130a2565b60405180910390f35b610346600480360381019061034191906130bd565b610890565b005b34801561035457600080fd5b5061036f600480360381019061036a9190612ff3565b6108f5565b60405161037c91906130a2565b60405180910390f35b61039f600480360381019061039a91906130bd565b610909565b005b3480156103ad57600080fd5b506103c860048036038101906103c39190612f9c565b610929565b6040516103d591906130a2565b60405180910390f35b3480156103ea57600080fd5b5061040560048036038101906104009190612f9c565b61093b565b6040516104129190612fd8565b60405180910390f35b34801561042757600080fd5b50610442600480360381019061043d9190613110565b61094d565b60405161044f91906130a2565b60405180910390f35b34801561046457600080fd5b5061046d61095f565b60405161047a9190612f44565b60405180910390f35b34801561048f57600080fd5b506104aa60048036038101906104a59190613033565b6109fa565b005b3480156104b857600080fd5b506104d360048036038101906104ce9190613169565b610a68565b005b6104ef60048036038101906104ea91906132d9565b610bdc565b005b3480156104fd57600080fd5b5061051860048036038101906105139190612f9c565b610c43565b6040516105259190612f44565b60405180910390f35b34801561053a57600080fd5b506105556004803603810190610550919061335c565b610e5c565b6040516105629190612d26565b60405180910390f35b6000807f334bcdc01ad42928dc76b974b9dc2d08aef6ae80f647d452bdc48c2baf971e8890508091505090565b60006105b4826105a6610e9d565b610fcf90919063ffffffff16565b9050919050565b6000801b6105c88161103a565b6105d3878686611047565b6105de8684846112ee565b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fa062c2c046aa14dc9284b13bde77061cb034f0aa820f20057af6b164651eaa0887878787604051610641949392919061345f565b60405180910390a350505050505050565b606061065c610e70565b600001805461066a906134c9565b80601f0160208091040260200160405190810160405280929190818152602001828054610696906134c9565b80156106e35780601f106106b8576101008083540402835291602001916106e3565b820191906000526020600020905b8154815290600101906020018083116106c657829003601f168201915b5050505050905090565b60006106f8826115de565b9050919050565b61070a82823461167b565b60006107158261093b565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610785576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161077c9061356c565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806107c557506107c48133610e5c565b5b610804576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107fb906135fe565b60405180910390fd5b61080e83836116ce565b505050565b6000801b6108208161103a565b61082b8484846112ee565b8373ffffffffffffffffffffffffffffffffffffffff167f02d0c334c706cd2f08faf7bc03674fc7f3970dd8921776c655069cde33b7fb29848460405161087392919061361e565b60405180910390a250505050565b600061088b611790565b905090565b61089c838383346117a7565b6108a633826117fc565b6108e5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108dc906136b4565b60405180910390fd5b6108f08383836118eb565b505050565b60006109018383611b14565b905092915050565b61092483838360405180602001604052806000815250610bdc565b505050565b600061093482611b3a565b9050919050565b600061094682611b5d565b9050919050565b600061095882611bf7565b9050919050565b6060610969610e70565b6001018054610977906134c9565b80601f01602080910402602001604051908101604052809291908181526020018280546109a3906134c9565b80156109f05780601f106109c5576101008083540402835291602001916109f0565b820191906000526020600020905b8154815290600101906020018083116109d357829003601f168201915b5050505050905090565b6000801b610a078161103a565b610a12848484611047565b8373ffffffffffffffffffffffffffffffffffffffff167f7c3eb4f9083f75cbed2bd3f703e24b4bbcb77d345d3c50945f3abf3e967755cb8484604051610a5a92919061361e565b60405180910390a250505050565b3373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610ad6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610acd90613720565b60405180910390fd5b80610adf611cbe565b60040160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051610bd09190612d26565b60405180910390a35050565b610be8848484346117a7565b610bf233836117fc565b610c31576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c28906136b4565b60405180910390fd5b610c3d84848484611ceb565b50505050565b6060610c5f82610c51611cbe565b611d4790919063ffffffff16565b610c9e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c95906137b2565b60405180910390fd5b6000610ca8610e70565b905060008160030160008581526020019081526020016000208054610ccc906134c9565b80601f0160208091040260200160405190810160405280929190818152602001828054610cf8906134c9565b8015610d455780601f10610d1a57610100808354040283529160200191610d45565b820191906000526020600020905b815481529060010190602001808311610d2857829003601f168201915b505050505090506000826002018054610d5d906134c9565b80601f0160208091040260200160405190810160405280929190818152602001828054610d89906134c9565b8015610dd65780601f10610dab57610100808354040283529160200191610dd6565b820191906000526020600020905b815481529060010190602001808311610db957829003601f168201915b505050505090506000815103610df157819350505050610e57565b600082511115610e27578082604051602001610e0e92919061380e565b6040516020818303038152906040529350505050610e57565b80610e3186611d67565b604051602001610e4292919061380e565b60405160208183030381529060405293505050505b919050565b6000610e688383611ec7565b905092915050565b6000807f99574a7094154bb123ae6ae102096f0bf9679b85a5cd1e727aaa0ae5f132e6b190508091505090565b6000807f326d0c59a7612f6a9919e2a8ee333c80ba689d8ba2634de89c85cbb04832e70590508091505090565b63ffffffff60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603610f32576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f299061387e565b60405180910390fd5b80836000016000847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060006101000a81548160ff021916908315150217905550505050565b6000807f0166504e5ccb463bc7d5bd33317cff1a2c4b9d767f1c547638f719d36741a1d090508091505090565b6000826000016000837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060009054906101000a900460ff16905092915050565b6110448133611f64565b50565b600061105161056b565b90506000838360405160200161106892919061361e565b604051602081830303815290604052805190602001209050808260020160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414611103576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110fa906138ea565b60405180910390fd5b60005b848490508110156112e6578573ffffffffffffffffffffffffffffffffffffffff168360010160008787858181106111415761114061390a565b5b90506020020160208101906111569190612cde565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611219576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161121090613985565b60405180910390fd5b60008360010160008787858181106112345761123361390a565b5b90506020020160208101906112499190612cde565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080806112de906139d4565b915050611106565b505050505050565b60006112f861056b565b90506000801b8160020160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414611380576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161137790613a68565b60405180910390fd5b60005b8383905081101561156357600073ffffffffffffffffffffffffffffffffffffffff168260010160008686858181106113bf576113be61390a565b5b90506020020160208101906113d49190612cde565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611497576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161148e90613ad4565b60405180910390fd5b848260010160008686858181106114b1576114b061390a565b5b90506020020160208101906114c69190612cde565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808061155b906139d4565b915050611383565b506000838360405160200161157992919061361e565b604051602081830303815290604052805190602001209050808260020160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505050505050565b6000806115e9611cbe565b90506115fe8382611d4790919063ffffffff16565b61163d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161163490613b66565b60405180910390fd5b80600301600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16915050919050565b600081146116be576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116b590613bf8565b60405180910390fd5b6116c9838383612008565b505050565b816116d7611cbe565b600301600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff1661174a83611b5d565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60006117a261179d611cbe565b61200d565b905090565b600081146117ea576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117e190613c8a565b60405180910390fd5b6117f684848484612022565b50505050565b60006118188261180a611cbe565b611d4790919063ffffffff16565b611857576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161184e90613d1c565b60405180910390fd5b600061186283611b5d565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614806118d157508373ffffffffffffffffffffffffffffffffffffffff166118b9846115de565b73ffffffffffffffffffffffffffffffffffffffff16145b806118e257506118e18185611ec7565b5b91505092915050565b8273ffffffffffffffffffffffffffffffffffffffff1661190b82611b5d565b73ffffffffffffffffffffffffffffffffffffffff1614611961576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161195890613dae565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036119d0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119c790613e40565b60405180910390fd5b6119db838383612028565b6119e66000826116ce565b60006119f0611cbe565b9050611a45828260020160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002061203890919063ffffffff16565b50611a99828260020160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002061205290919063ffffffff16565b50611ab282848360000161206c9092919063ffffffff16565b50818373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a450505050565b6000611b328383611b23611cbe565b6120a19092919063ffffffff16565b905092915050565b6000611b5682611b48611cbe565b6120ff90919063ffffffff16565b9050919050565b600080611b7d83611b6c611cbe565b60000161212590919063ffffffff16565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611bee576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611be590613eac565b60405180910390fd5b80915050919050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611c67576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c5e90613f3e565b60405180910390fd5b611cb7611c72611cbe565b60020160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020612142565b9050919050565b6000807f3c7bf052874fa81625121783266a03507bd2cd48b16e571c01a04e8dd3fb07a690508091505090565b611cf68484846118eb565b611d0284848484612157565b611d41576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d3890613fd0565b60405180910390fd5b50505050565b6000611d5f82846000016122cd90919063ffffffff16565b905092915050565b606060008203611dae576040518060400160405280600181526020017f30000000000000000000000000000000000000000000000000000000000000008152509050611ec2565b600082905060005b60008214611de0578080611dc9906139d4565b915050600a82611dd9919061401f565b9150611db6565b60008167ffffffffffffffff811115611dfc57611dfb6131ae565b5b6040519080825280601f01601f191660200182016040528015611e2e5781602001600182028036833780820191505090505b5090505b60008514611ebb57600182611e479190614050565b9150600a85611e569190614084565b6030611e6291906140b5565b60f81b818381518110611e7857611e7761390a565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a85611eb4919061401f565b9450611e32565b8093505050505b919050565b6000611ed1611cbe565b60040160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b611f6e82826122e7565b61200457611f918173ffffffffffffffffffffffffffffffffffffffff1661235b565b611fa860208460001c61238e90919063ffffffff16565b604051602001611fb99291906141a3565b6040516020818303038152906040526040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ffb9190612f44565b60405180910390fd5b5050565b505050565b600061201b826000016125b3565b9050919050565b50505050565b6120338383836125c8565b505050565b600061204a836000018360001b6125d8565b905092915050565b6000612064836000018360001b6126c6565b905092915050565b6000612098846000018460001b8473ffffffffffffffffffffffffffffffffffffffff1660001b612736565b90509392505050565b60006120f6828560020160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002061281890919063ffffffff16565b90509392505050565b600080612118838560000161283290919063ffffffff16565b5090508091505092915050565b6000612137836000018360001b61285e565b60001c905092915050565b6000612150826000016128f0565b9050919050565b60006121788473ffffffffffffffffffffffffffffffffffffffff16612901565b61218557600190506122c5565b600061224563150b7a0260e01b338887876040516024016121a99493929190614232565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051806060016040528060328152602001614651603291398773ffffffffffffffffffffffffffffffffffffffff166129149092919063ffffffff16565b905060008180602001905181019061225d9190614293565b90507f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614925050505b949350505050565b60006122df836000018360001b61292c565b905092915050565b60006122f1610fa2565b600001600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b606061238760148373ffffffffffffffffffffffffffffffffffffffff1661238e90919063ffffffff16565b9050919050565b6060600060028360026123a191906142c0565b6123ab91906140b5565b67ffffffffffffffff8111156123c4576123c36131ae565b5b6040519080825280601f01601f1916602001820160405280156123f65781602001600182028036833780820191505090505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811061242e5761242d61390a565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f7800000000000000000000000000000000000000000000000000000000000000816001815181106124925761249161390a565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006001846002020190505b6001811115612565577f3031323334353637383961626364656600000000000000000000000000000000600f86166010811061250c5761250b61390a565b5b1a60f81b8282815181106125235761252261390a565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600485901c9450806001900390506124cd565b50600084146125a9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016125a09061438c565b60405180910390fd5b8091505092915050565b60006125c18260000161294f565b9050919050565b6125d3838383612960565b505050565b600080836001016000848152602001908152602001600020549050600081146126ba5760008460000160018660000180549050038154811061261d5761261c61390a565b5b90600052602060002001549050808560000160018403815481106126445761264361390a565b5b906000526020600020018190555081856001016000838152602001908152602001600020819055505083600001805480612681576126806143ac565b5b600190038181906000526020600020016000905590558360010160008481526020019081526020016000206000905560019150506126c0565b60009150505b92915050565b60006126d283836129cd565b61272b578260000182908060018154018082558091505060019003906000526020600020016000909190919091505582600001805490508360010160008481526020019081526020016000208190555060019050612730565b600090505b92915050565b600080846001016000858152602001908152602001600020549050600081036127dc57846000016040518060400160405280868152602001858152509080600181540180825580915050600190039060005260206000209060020201600090919091909150600082015181600001556020820151816001015550508460000180549050856001016000868152602001908152602001600020819055506001915050612811565b828560000160018303815481106127f6576127f561390a565b5b90600052602060002090600202016001018190555060009150505b9392505050565b600061282783600001836129f0565b60001c905092915050565b6000806000806128458660000186612a64565b915091508160001c8160001c9350935050509250929050565b600080836001016000848152602001908152602001600020549050600081036128bc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016128b390614427565b60405180910390fd5b8360000160018203815481106128d5576128d461390a565b5b90600052602060002090600202016001015491505092915050565b600081600001805490509050919050565b600080823b905060008111915050919050565b60606129238484600085612aee565b90509392505050565b600080836001016000848152602001908152602001600020541415905092915050565b600081600001805490509050919050565b61296b838383612c10565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036129c8576129a7610e70565b600301600082815260200190815260200160002060006129c79190612c15565b5b505050565b600080836001016000848152602001908152602001600020541415905092915050565b600081836000018054905011612a3b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a32906144b9565b60405180910390fd5b826000018281548110612a5157612a5061390a565b5b9060005260206000200154905092915050565b60008082846000018054905011612ab0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612aa79061454b565b60405180910390fd5b6000846000018481548110612ac857612ac761390a565b5b906000526020600020906002020190508060000154816001015492509250509250929050565b6060612af985612901565b612b38576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612b2f906145dd565b60405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612b619190614639565b60006040518083038185875af1925050503d8060008114612b9e576040519150601f19603f3d011682016040523d82523d6000602084013e612ba3565b606091505b50915091508115612bb8578092505050612c08565b600081511115612bcb5780518082602001fd5b836040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612bff9190612f44565b60405180910390fd5b949350505050565b505050565b508054612c21906134c9565b6000825580601f10612c335750612c52565b601f016020900490600052602060002090810190612c519190612c55565b5b50565b5b80821115612c6e576000816000905550600101612c56565b5090565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b612cbb81612c86565b8114612cc657600080fd5b50565b600081359050612cd881612cb2565b92915050565b600060208284031215612cf457612cf3612c7c565b5b6000612d0284828501612cc9565b91505092915050565b60008115159050919050565b612d2081612d0b565b82525050565b6000602082019050612d3b6000830184612d17565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612d6c82612d41565b9050919050565b612d7c81612d61565b8114612d8757600080fd5b50565b600081359050612d9981612d73565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f840112612dc457612dc3612d9f565b5b8235905067ffffffffffffffff811115612de157612de0612da4565b5b602083019150836020820283011115612dfd57612dfc612da9565b5b9250929050565b60008060008060008060808789031215612e2157612e20612c7c565b5b6000612e2f89828a01612d8a565b9650506020612e4089828a01612d8a565b955050604087013567ffffffffffffffff811115612e6157612e60612c81565b5b612e6d89828a01612dae565b9450945050606087013567ffffffffffffffff811115612e9057612e8f612c81565b5b612e9c89828a01612dae565b92509250509295509295509295565b600081519050919050565b600082825260208201905092915050565b60005b83811015612ee5578082015181840152602081019050612eca565b83811115612ef4576000848401525b50505050565b6000601f19601f8301169050919050565b6000612f1682612eab565b612f208185612eb6565b9350612f30818560208601612ec7565b612f3981612efa565b840191505092915050565b60006020820190508181036000830152612f5e8184612f0b565b905092915050565b6000819050919050565b612f7981612f66565b8114612f8457600080fd5b50565b600081359050612f9681612f70565b92915050565b600060208284031215612fb257612fb1612c7c565b5b6000612fc084828501612f87565b91505092915050565b612fd281612d61565b82525050565b6000602082019050612fed6000830184612fc9565b92915050565b6000806040838503121561300a57613009612c7c565b5b600061301885828601612d8a565b925050602061302985828601612f87565b9150509250929050565b60008060006040848603121561304c5761304b612c7c565b5b600061305a86828701612d8a565b935050602084013567ffffffffffffffff81111561307b5761307a612c81565b5b61308786828701612dae565b92509250509250925092565b61309c81612f66565b82525050565b60006020820190506130b76000830184613093565b92915050565b6000806000606084860312156130d6576130d5612c7c565b5b60006130e486828701612d8a565b93505060206130f586828701612d8a565b925050604061310686828701612f87565b9150509250925092565b60006020828403121561312657613125612c7c565b5b600061313484828501612d8a565b91505092915050565b61314681612d0b565b811461315157600080fd5b50565b6000813590506131638161313d565b92915050565b600080604083850312156131805761317f612c7c565b5b600061318e85828601612d8a565b925050602061319f85828601613154565b9150509250929050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6131e682612efa565b810181811067ffffffffffffffff82111715613205576132046131ae565b5b80604052505050565b6000613218612c72565b905061322482826131dd565b919050565b600067ffffffffffffffff821115613244576132436131ae565b5b61324d82612efa565b9050602081019050919050565b82818337600083830152505050565b600061327c61327784613229565b61320e565b905082815260208101848484011115613298576132976131a9565b5b6132a384828561325a565b509392505050565b600082601f8301126132c0576132bf612d9f565b5b81356132d0848260208601613269565b91505092915050565b600080600080608085870312156132f3576132f2612c7c565b5b600061330187828801612d8a565b945050602061331287828801612d8a565b935050604061332387828801612f87565b925050606085013567ffffffffffffffff81111561334457613343612c81565b5b613350878288016132ab565b91505092959194509250565b6000806040838503121561337357613372612c7c565b5b600061338185828601612d8a565b925050602061339285828601612d8a565b9150509250929050565b600082825260208201905092915050565b6000819050919050565b6133c081612c86565b82525050565b60006133d283836133b7565b60208301905092915050565b60006133ed6020840184612cc9565b905092915050565b6000602082019050919050565b600061340e838561339c565b9350613419826133ad565b8060005b858110156134525761342f82846133de565b61343988826133c6565b9750613444836133f5565b92505060018101905061341d565b5085925050509392505050565b6000604082019050818103600083015261347a818688613402565b9050818103602083015261348f818486613402565b905095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806134e157607f821691505b6020821081036134f4576134f361349a565b5b50919050565b7f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560008201527f7200000000000000000000000000000000000000000000000000000000000000602082015250565b6000613556602183612eb6565b9150613561826134fa565b604082019050919050565b6000602082019050818103600083015261358581613549565b9050919050565b7f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760008201527f6e6572206e6f7220617070726f76656420666f7220616c6c0000000000000000602082015250565b60006135e8603883612eb6565b91506135f38261358c565b604082019050919050565b60006020820190508181036000830152613617816135db565b9050919050565b60006020820190508181036000830152613639818486613402565b90509392505050565b7f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60008201527f776e6572206f7220617070726f76656400000000000000000000000000000000602082015250565b600061369e603083612eb6565b91506136a982613642565b604082019050919050565b600060208201905081810360008301526136cd81613691565b9050919050565b7f4552433732313a20617070726f766520746f2063616c6c657200000000000000600082015250565b600061370a601983612eb6565b9150613715826136d4565b602082019050919050565b60006020820190508181036000830152613739816136fd565b9050919050565b7f4552433732314d657461646174613a2055524920717565727920666f72206e6f60008201527f6e6578697374656e7420746f6b656e0000000000000000000000000000000000602082015250565b600061379c602f83612eb6565b91506137a782613740565b604082019050919050565b600060208201905081810360008301526137cb8161378f565b9050919050565b600081905092915050565b60006137e882612eab565b6137f281856137d2565b9350613802818560208601612ec7565b80840191505092915050565b600061381a82856137dd565b915061382682846137dd565b91508190509392505050565b7f4552433136353a20696e76616c696420696e7465726661636520696400000000600082015250565b6000613868601c83612eb6565b915061387382613832565b602082019050919050565b600060208201905081810360008301526138978161385b565b9050919050565b7f496e76616c69642073656c6563746f72206c6973740000000000000000000000600082015250565b60006138d4601583612eb6565b91506138df8261389e565b602082019050919050565b60006020820190508181036000830152613903816138c7565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f556e726567697374657265642073656c6563746f720000000000000000000000600082015250565b600061396f601583612eb6565b915061397a82613939565b602082019050919050565b6000602082019050818103600083015261399e81613962565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006139df82612f66565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613a1157613a106139a5565b5b600182019050919050565b7f496d706c656d656e746174696f6e20616c726561647920657869737473000000600082015250565b6000613a52601d83612eb6565b9150613a5d82613a1c565b602082019050919050565b60006020820190508181036000830152613a8181613a45565b9050919050565b7f53656c6563746f7220616c726561647920726567697374657265640000000000600082015250565b6000613abe601b83612eb6565b9150613ac982613a88565b602082019050919050565b60006020820190508181036000830152613aed81613ab1565b9050919050565b7f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860008201527f697374656e7420746f6b656e0000000000000000000000000000000000000000602082015250565b6000613b50602c83612eb6565b9150613b5b82613af4565b604082019050919050565b60006020820190508181036000830152613b7f81613b43565b9050919050565b7f4552433732313a2070617961626c6520617070726f76652063616c6c73206e6f60008201527f7420737570706f72746564000000000000000000000000000000000000000000602082015250565b6000613be2602b83612eb6565b9150613bed82613b86565b604082019050919050565b60006020820190508181036000830152613c1181613bd5565b9050919050565b7f4552433732313a2070617961626c65207472616e736665722063616c6c73206e60008201527f6f7420737570706f727465640000000000000000000000000000000000000000602082015250565b6000613c74602c83612eb6565b9150613c7f82613c18565b604082019050919050565b60006020820190508181036000830152613ca381613c67565b9050919050565b7f4552433732313a20717565727920666f72206e6f6e6578697374656e7420746f60008201527f6b656e0000000000000000000000000000000000000000000000000000000000602082015250565b6000613d06602383612eb6565b9150613d1182613caa565b604082019050919050565b60006020820190508181036000830152613d3581613cf9565b9050919050565b7f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960008201527f73206e6f74206f776e0000000000000000000000000000000000000000000000602082015250565b6000613d98602983612eb6565b9150613da382613d3c565b604082019050919050565b60006020820190508181036000830152613dc781613d8b565b9050919050565b7f4552433732313a207472616e7366657220746f20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b6000613e2a602483612eb6565b9150613e3582613dce565b604082019050919050565b60006020820190508181036000830152613e5981613e1d565b9050919050565b7f4552433732313a20696e76616c6964206f776e65720000000000000000000000600082015250565b6000613e96601583612eb6565b9150613ea182613e60565b602082019050919050565b60006020820190508181036000830152613ec581613e89565b9050919050565b7f4552433732313a2062616c616e636520717565727920666f7220746865207a6560008201527f726f206164647265737300000000000000000000000000000000000000000000602082015250565b6000613f28602a83612eb6565b9150613f3382613ecc565b604082019050919050565b60006020820190508181036000830152613f5781613f1b565b9050919050565b7f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560008201527f63656976657220696d706c656d656e7465720000000000000000000000000000602082015250565b6000613fba603283612eb6565b9150613fc582613f5e565b604082019050919050565b60006020820190508181036000830152613fe981613fad565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600061402a82612f66565b915061403583612f66565b92508261404557614044613ff0565b5b828204905092915050565b600061405b82612f66565b915061406683612f66565b925082821015614079576140786139a5565b5b828203905092915050565b600061408f82612f66565b915061409a83612f66565b9250826140aa576140a9613ff0565b5b828206905092915050565b60006140c082612f66565b91506140cb83612f66565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115614100576140ff6139a5565b5b828201905092915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000600082015250565b60006141416017836137d2565b915061414c8261410b565b601782019050919050565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000600082015250565b600061418d6011836137d2565b915061419882614157565b601182019050919050565b60006141ae82614134565b91506141ba82856137dd565b91506141c582614180565b91506141d182846137dd565b91508190509392505050565b600081519050919050565b600082825260208201905092915050565b6000614204826141dd565b61420e81856141e8565b935061421e818560208601612ec7565b61422781612efa565b840191505092915050565b60006080820190506142476000830187612fc9565b6142546020830186612fc9565b6142616040830185613093565b818103606083015261427381846141f9565b905095945050505050565b60008151905061428d81612cb2565b92915050565b6000602082840312156142a9576142a8612c7c565b5b60006142b78482850161427e565b91505092915050565b60006142cb82612f66565b91506142d683612f66565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561430f5761430e6139a5565b5b828202905092915050565b7f55696e745574696c733a20686578206c656e67746820696e737566666963696560008201527f6e74000000000000000000000000000000000000000000000000000000000000602082015250565b6000614376602283612eb6565b91506143818261431a565b604082019050919050565b600060208201905081810360008301526143a581614369565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f456e756d657261626c654d61703a206e6f6e6578697374656e74206b65790000600082015250565b6000614411601e83612eb6565b915061441c826143db565b602082019050919050565b6000602082019050818103600083015261444081614404565b9050919050565b7f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e60008201527f6473000000000000000000000000000000000000000000000000000000000000602082015250565b60006144a3602283612eb6565b91506144ae82614447565b604082019050919050565b600060208201905081810360008301526144d281614496565b9050919050565b7f456e756d657261626c654d61703a20696e646578206f7574206f6620626f756e60008201527f6473000000000000000000000000000000000000000000000000000000000000602082015250565b6000614535602283612eb6565b9150614540826144d9565b604082019050919050565b6000602082019050818103600083015261456481614528565b9050919050565b7f416464726573735574696c733a2066756e6374696f6e2063616c6c20746f206e60008201527f6f6e2d636f6e7472616374000000000000000000000000000000000000000000602082015250565b60006145c7602b83612eb6565b91506145d28261456b565b604082019050919050565b600060208201905081810360008301526145f6816145ba565b9050919050565b600081905092915050565b6000614613826141dd565b61461d81856145fd565b935061462d818560208601612ec7565b80840191505092915050565b60006146458284614608565b91508190509291505056fe4552433732313a207472616e7366657220746f206e6f6e20455243373231526563656976657220696d706c656d656e746572a264697066735822122016b6e7043e551b384240023a250e0d348d798088b1e4a195d832c1394c20bb9264736f6c634300080d0033

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

000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000001544494d4f206964656e7469747920426574612056310000000000000000000000000000000000000000000000000000000000000000000000000000000000000a44494d4f42657461563100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002668747470733a2f2f646576696365732d6170692e64696d6f2e7a6f6e652f76312f6e6674732f0000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : _name (string): DIMO identity Beta V1
Arg [1] : _symbol (string): DIMOBetaV1
Arg [2] : __baseURI (string): https://devices-api.dimo.zone/v1/nfts/

-----Encoded View---------------
10 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [2] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000015
Arg [4] : 44494d4f206964656e7469747920426574612056310000000000000000000000
Arg [5] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [6] : 44494d4f42657461563100000000000000000000000000000000000000000000
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000026
Arg [8] : 68747470733a2f2f646576696365732d6170692e64696d6f2e7a6f6e652f7631
Arg [9] : 2f6e6674732f0000000000000000000000000000000000000000000000000000


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

Txn Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

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.