Contract Address Details

0xB1b599Ec67ad23AF7FAC240191319822e674571A

Contract Name
RolesRegistry
Creator
0x066f91–19f71d at 0x7dbdcd–11f005
Balance
0 TCRO
Tokens
Fetching tokens...
Transactions
0 Transactions
Transfers
0 Transfers
Gas Used
Fetching gas used...
Last Balance Update
25250972
Contract name:
RolesRegistry




Optimization enabled
false
Compiler version
v0.8.9+commit.e5eed63a




Verified at
2023-11-13T12:56:33.200118Z

contracts/RolesRegistry.sol

// SPDX-License-Identifier: CC0-1.0

pragma solidity 0.8.9;

import { IERC7432 } from "./interfaces/IERC7432.sol";
import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";

contract RolesRegistry is IERC7432 {
    // grantee => tokenAddress => tokenId => role => struct(expirationDate, data)
    mapping(address => mapping(address => mapping(uint256 => mapping(bytes32 => RoleData)))) public roleAssignments;

    // tokenAddress => tokenId => role => grantee
    mapping(address => mapping(uint256 => mapping(bytes32 => address))) public latestGrantees;

    // grantor => tokenAddress => operator => isApproved
    mapping(address => mapping(address => mapping(address => bool))) public tokenApprovals;

    modifier validExpirationDate(uint64 _expirationDate) {
        require(_expirationDate > block.timestamp, "RolesRegistry: expiration date must be in the future");
        _;
    }

    modifier onlyOwnerOrApproved(
        address _tokenAddress,
        uint256 _tokenId,
        address _account
    ) {
        address _tokenOwner = IERC721(_tokenAddress).ownerOf(_tokenId);
        require(
            msg.sender == _tokenOwner ||
                (isRoleApprovedForAll(_tokenAddress, _account, msg.sender) && _account == _tokenOwner),
            "RolesRegistry: sender must be token owner or approved"
        );
        _;
    }

    modifier isTokenOwner(
        address _tokenAddress,
        uint256 _tokenId,
        address _account
    ) {
        require(_account == IERC721(_tokenAddress).ownerOf(_tokenId), "RolesRegistry: account must be token owner");
        _;
    }

    function grantRoleFrom(
        RoleAssignment calldata _roleAssignment
    )
        external
        override
        onlyOwnerOrApproved(_roleAssignment.tokenAddress, _roleAssignment.tokenId, _roleAssignment.grantor)
    {
        _grantRole(_roleAssignment, false);
    }

    function grantRevocableRoleFrom(
        RoleAssignment calldata _roleAssignment
    )
        external
        override
        onlyOwnerOrApproved(_roleAssignment.tokenAddress, _roleAssignment.tokenId, _roleAssignment.grantor)
    {
        _grantRole(_roleAssignment, true);
    }

    function _grantRole(
        RoleAssignment calldata _roleAssignment,
        bool _revocable
    ) internal validExpirationDate(_roleAssignment.expirationDate) {
        address _lastGrantee = latestGrantees[_roleAssignment.tokenAddress][_roleAssignment.tokenId][
            _roleAssignment.role
        ];
        RoleData memory _roleData = roleAssignments[_lastGrantee][_roleAssignment.tokenAddress][
            _roleAssignment.tokenId
        ][_roleAssignment.role];

        bool _hasActiveAssignment = _roleData.expirationDate > block.timestamp;

        if (_hasActiveAssignment) {
            // only unique roles can be revocable
            require(_roleData.revocable, "RolesRegistry: role is not revocable");
        }

        roleAssignments[_roleAssignment.grantee][_roleAssignment.tokenAddress][_roleAssignment.tokenId][
            _roleAssignment.role
        ] = RoleData(_roleAssignment.expirationDate, _revocable, _roleAssignment.data);
        latestGrantees[_roleAssignment.tokenAddress][_roleAssignment.tokenId][_roleAssignment.role] = _roleAssignment
            .grantee;
        emit RoleGranted(
            _roleAssignment.role,
            _roleAssignment.tokenAddress,
            _roleAssignment.tokenId,
            _roleAssignment.grantor,
            _roleAssignment.grantee,
            _roleAssignment.expirationDate,
            _revocable,
            _roleAssignment.data
        );
    }

    function revokeRoleFrom(
        bytes32 _role,
        address _tokenAddress,
        uint256 _tokenId,
        address _revoker,
        address _grantee
    ) external override isTokenOwner(_tokenAddress, _tokenId, _revoker) {
        address _caller = msg.sender == _revoker || msg.sender == _grantee
            ? msg.sender
            : _getApprovedCaller(_tokenAddress, _revoker, _grantee);
        _revokeRole(_role, _tokenAddress, _tokenId, _revoker, _grantee, _caller);
    }

    function _getApprovedCaller(
        address _tokenAddress,
        address _revoker,
        address _grantee
    ) internal view returns (address) {
        if (isRoleApprovedForAll(_tokenAddress, _grantee, msg.sender)) {
            return _grantee;
        } else if (isRoleApprovedForAll(_tokenAddress, _revoker, msg.sender)) {
            return _revoker;
        } else {
            revert("RolesRegistry: sender must be approved");
        }
    }

    function _revokeRole(
        bytes32 _role,
        address _tokenAddress,
        uint256 _tokenId,
        address _revoker,
        address _grantee,
        address _caller
    ) internal {
        require(
            _caller == _grantee || roleAssignments[_grantee][_tokenAddress][_tokenId][_role].revocable,
            "RolesRegistry: Role is not revocable or caller is not the grantee"
        );
        delete roleAssignments[_grantee][_tokenAddress][_tokenId][_role];
        delete latestGrantees[_tokenAddress][_tokenId][_role];
        emit RoleRevoked(_role, _tokenAddress, _tokenId, _revoker, _grantee);
    }

    function hasNonUniqueRole(
        bytes32 _role,
        address _tokenAddress,
        uint256 _tokenId,
        address _grantor, // not used, but needed for compatibility with ERC7432
        address _grantee
    ) external view returns (bool) {
        return roleAssignments[_grantee][_tokenAddress][_tokenId][_role].expirationDate > block.timestamp;
    }

    function hasRole(
        bytes32 _role,
        address _tokenAddress,
        uint256 _tokenId,
        address _grantor, // not used, but needed for compatibility with ERC7432
        address _grantee
    ) external view returns (bool) {
        return
            latestGrantees[_tokenAddress][_tokenId][_role] == _grantee &&
            roleAssignments[_grantee][_tokenAddress][_tokenId][_role].expirationDate > block.timestamp;
    }

    function roleData(
        bytes32 _role,
        address _tokenAddress,
        uint256 _tokenId,
        address _grantor, // not used, but needed for compatibility with ERC7432
        address _grantee
    ) external view returns (RoleData memory) {
        return roleAssignments[_grantee][_tokenAddress][_tokenId][_role];
    }

    function roleExpirationDate(
        bytes32 _role,
        address _tokenAddress,
        uint256 _tokenId,
        address _grantor, // not used, but needed for compatibility with ERC7432
        address _grantee
    ) external view returns (uint64 expirationDate_) {
        return roleAssignments[_grantee][_tokenAddress][_tokenId][_role].expirationDate;
    }

    function supportsInterface(bytes4 interfaceId) external view virtual override returns (bool) {
        return interfaceId == type(IERC7432).interfaceId;
    }

    function setRoleApprovalForAll(address _tokenAddress, address _operator, bool _isApproved) external override {
        tokenApprovals[msg.sender][_tokenAddress][_operator] = _isApproved;
        emit RoleApprovalForAll(_tokenAddress, _operator, _isApproved);
    }

    function isRoleApprovedForAll(
        address _tokenAddress,
        address _grantor,
        address _operator
    ) public view override returns (bool) {
        return tokenApprovals[_grantor][_tokenAddress][_operator];
    }

    function lastGrantee(
        bytes32 _role,
        address _tokenAddress,
        uint256 _tokenId,
        address _grantor // not used, but needed for compatibility with ERC7432
    ) public view override returns (address) {
        return latestGrantees[_tokenAddress][_tokenId][_role];
    }
}
        

@openzeppelin/contracts/token/ERC721/IERC721.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

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

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

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

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

@openzeppelin/contracts/utils/introspection/ERC165Checker.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/introspection/ERC165Checker.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Library used to query support of an interface declared via {IERC165}.
 *
 * Note that these functions return the actual result of the query: they do not
 * `revert` if an interface is not supported. It is up to the caller to decide
 * what to do in these cases.
 */
library ERC165Checker {
    // As per the EIP-165 spec, no interface should ever match 0xffffffff
    bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;

    /**
     * @dev Returns true if `account` supports the {IERC165} interface.
     */
    function supportsERC165(address account) internal view returns (bool) {
        // Any contract that implements ERC165 must explicitly indicate support of
        // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
        return
            supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) &&
            !supportsERC165InterfaceUnchecked(account, _INTERFACE_ID_INVALID);
    }

    /**
     * @dev Returns true if `account` supports the interface defined by
     * `interfaceId`. Support for {IERC165} itself is queried automatically.
     *
     * See {IERC165-supportsInterface}.
     */
    function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
        // query support of both ERC165 as per the spec and support of _interfaceId
        return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId);
    }

    /**
     * @dev Returns a boolean array where each value corresponds to the
     * interfaces passed in and whether they're supported or not. This allows
     * you to batch check interfaces for a contract where your expectation
     * is that some interfaces may not be supported.
     *
     * See {IERC165-supportsInterface}.
     *
     * _Available since v3.4._
     */
    function getSupportedInterfaces(
        address account,
        bytes4[] memory interfaceIds
    ) internal view returns (bool[] memory) {
        // an array of booleans corresponding to interfaceIds and whether they're supported or not
        bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);

        // query support of ERC165 itself
        if (supportsERC165(account)) {
            // query support of each interface in interfaceIds
            for (uint256 i = 0; i < interfaceIds.length; i++) {
                interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]);
            }
        }

        return interfaceIdsSupported;
    }

    /**
     * @dev Returns true if `account` supports all the interfaces defined in
     * `interfaceIds`. Support for {IERC165} itself is queried automatically.
     *
     * Batch-querying can lead to gas savings by skipping repeated checks for
     * {IERC165} support.
     *
     * See {IERC165-supportsInterface}.
     */
    function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
        // query support of ERC165 itself
        if (!supportsERC165(account)) {
            return false;
        }

        // query support of each interface in interfaceIds
        for (uint256 i = 0; i < interfaceIds.length; i++) {
            if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) {
                return false;
            }
        }

        // all interfaces supported
        return true;
    }

    /**
     * @notice Query if a contract implements an interface, does not check ERC165 support
     * @param account The address of the contract to query for support of an interface
     * @param interfaceId The interface identifier, as specified in ERC-165
     * @return true if the contract at account indicates support of the interface with
     * identifier interfaceId, false otherwise
     * @dev Assumes that account contains a contract that supports ERC165, otherwise
     * the behavior of this method is undefined. This precondition can be checked
     * with {supportsERC165}.
     *
     * Some precompiled contracts will falsely indicate support for a given interface, so caution
     * should be exercised when using this function.
     *
     * Interface identification is specified in ERC-165.
     */
    function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {
        // prepare call
        bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);

        // perform static call
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly {
            success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0x00)
        }

        return success && returnSize >= 0x20 && returnValue > 0;
    }
}
          

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

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

pragma solidity ^0.8.0;

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

contracts/interfaces/IERC7432.sol

// SPDX-License-Identifier: CC0-1.0

pragma solidity 0.8.9;

import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

/// @title ERC-7432 Non-Fungible Token Roles
/// @dev See https://eips.ethereum.org/EIPS/eip-7432
/// Note: the ERC-165 identifier for this interface is 0x04984ac8.
interface IERC7432 is IERC165 {
    struct RoleData {
        uint64 expirationDate;
        bool revocable;
        bytes data;
    }

    struct RoleAssignment {
        bytes32 role;
        address tokenAddress;
        uint256 tokenId;
        address grantor;
        address grantee;
        uint64 expirationDate;
        bytes data;
    }

    /** Events **/

    /// @notice Emitted when a role is granted.
    /// @param _role The role identifier.
    /// @param _tokenAddress The token address.
    /// @param _tokenId The token identifier.
    /// @param _grantor The user assigning the role.
    /// @param _grantee The user receiving the role.
    /// @param _expirationDate The expiration date of the role.
    /// @param _revocable Whether the role is revocable or not.
    /// @param _data Any additional data about the role.
    event RoleGranted(
        bytes32 indexed _role,
        address indexed _tokenAddress,
        uint256 indexed _tokenId,
        address _grantor,
        address _grantee,
        uint64 _expirationDate,
        bool _revocable,
        bytes _data
    );

    /// @notice Emitted when a role is revoked.
    /// @param _role The role identifier.
    /// @param _tokenAddress The token address.
    /// @param _tokenId The token identifier.
    /// @param _revoker The user revoking the role.
    /// @param _grantee The user that receives the role revocation.
    event RoleRevoked(
        bytes32 indexed _role,
        address indexed _tokenAddress,
        uint256 indexed _tokenId,
        address _revoker,
        address _grantee
    );

    /// @notice Emitted when a user is approved to manage any role on behalf of another user.
    /// @param _tokenAddress The token address.
    /// @param _operator The user approved to grant and revoke roles.
    /// @param _isApproved The approval status.
    event RoleApprovalForAll(
        address indexed _tokenAddress,
        address indexed _operator,
        bool _isApproved
    );

    /** External Functions **/

    /// @notice Grants a role on behalf of a user.
    /// @param _roleAssignment The role assignment data.
    function grantRoleFrom(RoleAssignment calldata _roleAssignment) external;

    /// @notice Grants a role on behalf of a user.
    /// @param _roleAssignment The role assignment data.
    function grantRevocableRoleFrom(RoleAssignment calldata _roleAssignment) external;

    /// @notice Revokes a role on behalf of a user.
    /// @param _role The role identifier.
    /// @param _tokenAddress The token address.
    /// @param _tokenId The token identifier.
    /// @param _revoker The user revoking the role.
    /// @param _grantee The user that receives the role revocation.
    function revokeRoleFrom(
        bytes32 _role,
        address _tokenAddress,
        uint256 _tokenId,
        address _revoker,
        address _grantee
    ) external;

    /// @notice Approves operator to grant and revoke any roles on behalf of another user.
    /// @param _tokenAddress The token address.
    /// @param _operator The user approved to grant and revoke roles.
    /// @param _approved The approval status.
    function setRoleApprovalForAll(
        address _tokenAddress,
        address _operator,
        bool _approved
    ) external;

    /** View Functions **/

    /// @notice Checks if a user has a role.
    /// @param _role The role identifier.
    /// @param _tokenAddress The token address.
    /// @param _tokenId The token identifier.
    /// @param _grantor The user that assigned the role.
    /// @param _grantee The user that received the role.
    function hasNonUniqueRole(
        bytes32 _role,
        address _tokenAddress,
        uint256 _tokenId,
        address _grantor,
        address _grantee
    ) external view returns (bool);

    /// @notice Checks if a user has a unique role.
    /// @param _role The role identifier.
    /// @param _tokenAddress The token address.
    /// @param _tokenId The token identifier.
    /// @param _grantor The user that assigned the role.
    /// @param _grantee The user that received the role.
    function hasRole(
        bytes32 _role,
        address _tokenAddress,
        uint256 _tokenId,
        address _grantor,
        address _grantee
    ) external view returns (bool);

    /// @notice Returns the custom data of a role assignment.
    /// @param _role The role identifier.
    /// @param _tokenAddress The token address.
    /// @param _tokenId The token identifier.
    /// @param _grantor The user that assigned the role.
    /// @param _grantee The user that received the role.
    function roleData(
        bytes32 _role,
        address _tokenAddress,
        uint256 _tokenId,
        address _grantor,
        address _grantee
    ) external view returns (RoleData memory data_);

    /// @notice Returns the expiration date of a role assignment.
    /// @param _role The role identifier.
    /// @param _tokenAddress The token address.
    /// @param _tokenId The token identifier.
    /// @param _grantor The user that assigned the role.
    /// @param _grantee The user that received the role.
    function roleExpirationDate(
        bytes32 _role,
        address _tokenAddress,
        uint256 _tokenId,
        address _grantor,
        address _grantee
    ) external view returns (uint64 expirationDate_);

    /// @notice Checks if the grantor approved the operator for all NFTs.
    /// @param _tokenAddress The token address.
    /// @param _grantor The user that approved the operator.
    /// @param _operator The user that can grant and revoke roles.
    function isRoleApprovedForAll(
        address _tokenAddress,
        address _grantor,
        address _operator
    ) external view returns (bool);

    /// @notice Returns the last grantee of a role.
    /// @param _role The role.
    /// @param _tokenAddress The token address.
    /// @param _tokenId The token ID.
    /// @param _grantor The user that granted the role.
    function lastGrantee(
        bytes32 _role,
        address _tokenAddress,
        uint256 _tokenId,
        address _grantor
    ) external view returns (address);
}
          

Contract ABI

[{"type":"event","name":"RoleApprovalForAll","inputs":[{"type":"address","name":"_tokenAddress","internalType":"address","indexed":true},{"type":"address","name":"_operator","internalType":"address","indexed":true},{"type":"bool","name":"_isApproved","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"type":"bytes32","name":"_role","internalType":"bytes32","indexed":true},{"type":"address","name":"_tokenAddress","internalType":"address","indexed":true},{"type":"uint256","name":"_tokenId","internalType":"uint256","indexed":true},{"type":"address","name":"_grantor","internalType":"address","indexed":false},{"type":"address","name":"_grantee","internalType":"address","indexed":false},{"type":"uint64","name":"_expirationDate","internalType":"uint64","indexed":false},{"type":"bool","name":"_revocable","internalType":"bool","indexed":false},{"type":"bytes","name":"_data","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"type":"bytes32","name":"_role","internalType":"bytes32","indexed":true},{"type":"address","name":"_tokenAddress","internalType":"address","indexed":true},{"type":"uint256","name":"_tokenId","internalType":"uint256","indexed":true},{"type":"address","name":"_revoker","internalType":"address","indexed":false},{"type":"address","name":"_grantee","internalType":"address","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"grantRevocableRoleFrom","inputs":[{"type":"tuple","name":"_roleAssignment","internalType":"struct IERC7432.RoleAssignment","components":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"address","name":"grantor","internalType":"address"},{"type":"address","name":"grantee","internalType":"address"},{"type":"uint64","name":"expirationDate","internalType":"uint64"},{"type":"bytes","name":"data","internalType":"bytes"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"grantRoleFrom","inputs":[{"type":"tuple","name":"_roleAssignment","internalType":"struct IERC7432.RoleAssignment","components":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"address","name":"grantor","internalType":"address"},{"type":"address","name":"grantee","internalType":"address"},{"type":"uint64","name":"expirationDate","internalType":"uint64"},{"type":"bytes","name":"data","internalType":"bytes"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"hasNonUniqueRole","inputs":[{"type":"bytes32","name":"_role","internalType":"bytes32"},{"type":"address","name":"_tokenAddress","internalType":"address"},{"type":"uint256","name":"_tokenId","internalType":"uint256"},{"type":"address","name":"_grantor","internalType":"address"},{"type":"address","name":"_grantee","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"hasRole","inputs":[{"type":"bytes32","name":"_role","internalType":"bytes32"},{"type":"address","name":"_tokenAddress","internalType":"address"},{"type":"uint256","name":"_tokenId","internalType":"uint256"},{"type":"address","name":"_grantor","internalType":"address"},{"type":"address","name":"_grantee","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isRoleApprovedForAll","inputs":[{"type":"address","name":"_tokenAddress","internalType":"address"},{"type":"address","name":"_grantor","internalType":"address"},{"type":"address","name":"_operator","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"lastGrantee","inputs":[{"type":"bytes32","name":"_role","internalType":"bytes32"},{"type":"address","name":"_tokenAddress","internalType":"address"},{"type":"uint256","name":"_tokenId","internalType":"uint256"},{"type":"address","name":"_grantor","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"latestGrantees","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"revokeRoleFrom","inputs":[{"type":"bytes32","name":"_role","internalType":"bytes32"},{"type":"address","name":"_tokenAddress","internalType":"address"},{"type":"uint256","name":"_tokenId","internalType":"uint256"},{"type":"address","name":"_revoker","internalType":"address"},{"type":"address","name":"_grantee","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint64","name":"expirationDate","internalType":"uint64"},{"type":"bool","name":"revocable","internalType":"bool"},{"type":"bytes","name":"data","internalType":"bytes"}],"name":"roleAssignments","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct IERC7432.RoleData","components":[{"type":"uint64","name":"expirationDate","internalType":"uint64"},{"type":"bool","name":"revocable","internalType":"bool"},{"type":"bytes","name":"data","internalType":"bytes"}]}],"name":"roleData","inputs":[{"type":"bytes32","name":"_role","internalType":"bytes32"},{"type":"address","name":"_tokenAddress","internalType":"address"},{"type":"uint256","name":"_tokenId","internalType":"uint256"},{"type":"address","name":"_grantor","internalType":"address"},{"type":"address","name":"_grantee","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint64","name":"expirationDate_","internalType":"uint64"}],"name":"roleExpirationDate","inputs":[{"type":"bytes32","name":"_role","internalType":"bytes32"},{"type":"address","name":"_tokenAddress","internalType":"address"},{"type":"uint256","name":"_tokenId","internalType":"uint256"},{"type":"address","name":"_grantor","internalType":"address"},{"type":"address","name":"_grantee","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRoleApprovalForAll","inputs":[{"type":"address","name":"_tokenAddress","internalType":"address"},{"type":"address","name":"_operator","internalType":"address"},{"type":"bool","name":"_isApproved","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"supportsInterface","inputs":[{"type":"bytes4","name":"interfaceId","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"tokenApprovals","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"}]}]
            

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106100ea5760003560e01c806353f8a7ce1161008c578063a34adf0a11610066578063a34adf0a146102a7578063a9c39982146102c3578063d5ced376146102df578063fe78cf281461030f576100ea565b806353f8a7ce1461022b5780638767c67e1461025b5780639760a9e11461028b576100ea565b806310c10939116100c857806310c109391461017f5780631e3337c6146101af57806344c722cf146101df5780634ea538a2146101fb576100ea565b806301ffc9a7146100ef578063040b0cb51461011f5780630f1df0071461014f575b600080fd5b61010960048036038101906101049190611c27565b610341565b6040516101169190611c6f565b60405180910390f35b61013960048036038101906101349190611d54565b6103ab565b6040516101469190611c6f565b60405180910390f35b61016960048036038101906101649190611d54565b610479565b6040516101769190611df2565b60405180910390f35b61019960048036038101906101949190611e0d565b61053b565b6040516101a69190611c6f565b60405180910390f35b6101c960048036038101906101c49190611d54565b610577565b6040516101d69190611f67565b60405180910390f35b6101f960048036038101906101f49190611fad565b610711565b005b61021560048036038101906102109190611ff6565b610892565b604051610222919061206c565b60405180910390f35b61024560048036038101906102409190611d54565b610920565b6040516102529190611c6f565b60405180910390f35b61027560048036038101906102709190612087565b610aa6565b604051610282919061206c565b60405180910390f35b6102a560048036038101906102a09190611fad565b610af5565b005b6102c160048036038101906102bc9190612106565b610c76565b005b6102dd60048036038101906102d89190611d54565b610db1565b005b6102f960048036038101906102f49190611e0d565b610f42565b6040516103069190611c6f565b60405180910390f35b61032960048036038101906103249190612159565b611014565b6040516103389392919061220a565b60405180910390f35b60007f04984ac8000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b6000426000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000868152602001908152602001600020600088815260200190815260200160002060000160009054906101000a900467ffffffffffffffff1667ffffffffffffffff1611905095945050505050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000858152602001908152602001600020600087815260200190815260200160002060000160009054906101000a900467ffffffffffffffff16905095945050505050565b6002602052826000526040600020602052816000526040600020602052806000526040600020600092509250509054906101000a900460ff1681565b61057f611ab5565b6000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600085815260200190815260200160002060008781526020019081526020016000206040518060600160405290816000820160009054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020016000820160089054906101000a900460ff1615151515815260200160018201805461068490612277565b80601f01602080910402602001604051908101604052809291908181526020018280546106b090612277565b80156106fd5780601f106106d2576101008083540402835291602001916106fd565b820191906000526020600020905b8154815290600101906020018083116106e057829003601f168201915b505050505081525050905095945050505050565b80602001602081019061072491906122a9565b816040013582606001602081019061073c91906122a9565b60008373ffffffffffffffffffffffffffffffffffffffff16636352211e846040518263ffffffff1660e01b815260040161077791906122e5565b60206040518083038186803b15801561078f57600080fd5b505afa1580156107a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107c79190612315565b90508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806108415750610809848333610f42565b801561084057508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b5b610880576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610877906123c5565b60405180910390fd5b61088b85600161110e565b5050505050565b6000600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000848152602001908152602001600020600086815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050949350505050565b60008173ffffffffffffffffffffffffffffffffffffffff16600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000868152602001908152602001600020600088815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16148015610a9b5750426000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000868152602001908152602001600020600088815260200190815260200160002060000160009054906101000a900467ffffffffffffffff1667ffffffffffffffff16115b905095945050505050565b6001602052826000526040600020602052816000526040600020602052806000526040600020600092509250509054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b806020016020810190610b0891906122a9565b8160400135826060016020810190610b2091906122a9565b60008373ffffffffffffffffffffffffffffffffffffffff16636352211e846040518263ffffffff1660e01b8152600401610b5b91906122e5565b60206040518083038186803b158015610b7357600080fd5b505afa158015610b87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bab9190612315565b90508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480610c255750610bed848333610f42565b8015610c2457508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b5b610c64576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c5b906123c5565b60405180910390fd5b610c6f85600061110e565b5050505050565b80600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fa9f861543e61f98894ecc9e3edeb6ca82ac424611eb0d8943a84bb89a2eb1d0b83604051610da49190611c6f565b60405180910390a3505050565b8383838273ffffffffffffffffffffffffffffffffffffffff16636352211e836040518263ffffffff1660e01b8152600401610ded91906122e5565b60206040518083038186803b158015610e0557600080fd5b505afa158015610e19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3d9190612315565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610eaa576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ea190612457565b60405180910390fd5b60008573ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480610f1157508473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b610f2557610f20888787611761565b610f27565b335b9050610f378989898989866117d5565b505050505050505050565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1690509392505050565b60006020528360005260406000206020528260005260406000206020528160005260406000206020528060005260406000206000935093505050508060000160009054906101000a900467ffffffffffffffff16908060000160089054906101000a900460ff169080600101805461108b90612277565b80601f01602080910402602001604051908101604052809291908181526020018280546110b790612277565b80156111045780601f106110d957610100808354040283529160200191611104565b820191906000526020600020905b8154815290600101906020018083116110e757829003601f168201915b5050505050905083565b8160a001602081019061112191906124a3565b428167ffffffffffffffff161161116d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161116490612542565b60405180910390fd5b60006001600085602001602081019061118691906122a9565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008560400135815260200190815260200160002060008560000135815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600086602001602081019061126291906122a9565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000866040013581526020019081526020016000206000866000013581526020019081526020016000206040518060600160405290816000820160009054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020016000820160089054906101000a900460ff1615151515815260200160018201805461132e90612277565b80601f016020809104026020016040519081016040528092919081815260200182805461135a90612277565b80156113a75780601f1061137c576101008083540402835291602001916113a7565b820191906000526020600020905b81548152906001019060200180831161138a57829003601f168201915b5050505050815250509050600042826000015167ffffffffffffffff161190508015611412578160200151611411576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611408906125d4565b60405180910390fd5b5b60405180606001604052808760a001602081019061143091906124a3565b67ffffffffffffffff1681526020018615158152602001878060c001906114579190612603565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508152506000808860800160208101906114b391906122a9565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600088602001602081019061150291906122a9565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008860400135815260200190815260200160002060008860000135815260200190815260200160002060008201518160000160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060208201518160000160086101000a81548160ff02191690831515021790555060408201518160010190805190602001906115d1929190611ae2565b509050508560800160208101906115e891906122a9565b600160008860200160208101906115ff91906122a9565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008860400135815260200190815260200160002060008860000135815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555085604001358660200160208101906116b991906122a9565b73ffffffffffffffffffffffffffffffffffffffff1687600001357f87ce9b16c986be2f6c60151d2337ecfee6fd8067d3e3d81d3276cbab55139eab89606001602081019061170891906122a9565b8a608001602081019061171b91906122a9565b8b60a001602081019061172e91906124a3565b8b8d8060c0019061173f9190612603565b604051611751969594939291906126a2565b60405180910390a4505050505050565b600061176e848333610f42565b1561177b578190506117ce565b611786848433610f42565b15611793578290506117ce565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117c590612770565b60405180910390fd5b9392505050565b8173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614806118b957506000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000858152602001908152602001600020600087815260200190815260200160002060000160089054906101000a900460ff165b6118f8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118ef90612828565b60405180910390fd5b6000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008581526020019081526020016000206000878152602001908152602001600020600080820160006101000a81549067ffffffffffffffff02191690556000820160086101000a81549060ff02191690556001820160006119d59190611b68565b5050600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000858152602001908152602001600020600087815260200190815260200160002060006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055838573ffffffffffffffffffffffffffffffffffffffff16877fd0fed9028dcedb984cc57c4ddcc971990f107dbff315e3c92db61f2927a3e2b98686604051611aa5929190612848565b60405180910390a4505050505050565b6040518060600160405280600067ffffffffffffffff168152602001600015158152602001606081525090565b828054611aee90612277565b90600052602060002090601f016020900481019282611b105760008555611b57565b82601f10611b2957805160ff1916838001178555611b57565b82800160010185558215611b57579182015b82811115611b56578251825591602001919060010190611b3b565b5b509050611b649190611ba8565b5090565b508054611b7490612277565b6000825580601f10611b865750611ba5565b601f016020900490600052602060002090810190611ba49190611ba8565b5b50565b5b80821115611bc1576000816000905550600101611ba9565b5090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b611c0481611bcf565b8114611c0f57600080fd5b50565b600081359050611c2181611bfb565b92915050565b600060208284031215611c3d57611c3c611bc5565b5b6000611c4b84828501611c12565b91505092915050565b60008115159050919050565b611c6981611c54565b82525050565b6000602082019050611c846000830184611c60565b92915050565b6000819050919050565b611c9d81611c8a565b8114611ca857600080fd5b50565b600081359050611cba81611c94565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000611ceb82611cc0565b9050919050565b611cfb81611ce0565b8114611d0657600080fd5b50565b600081359050611d1881611cf2565b92915050565b6000819050919050565b611d3181611d1e565b8114611d3c57600080fd5b50565b600081359050611d4e81611d28565b92915050565b600080600080600060a08688031215611d7057611d6f611bc5565b5b6000611d7e88828901611cab565b9550506020611d8f88828901611d09565b9450506040611da088828901611d3f565b9350506060611db188828901611d09565b9250506080611dc288828901611d09565b9150509295509295909350565b600067ffffffffffffffff82169050919050565b611dec81611dcf565b82525050565b6000602082019050611e076000830184611de3565b92915050565b600080600060608486031215611e2657611e25611bc5565b5b6000611e3486828701611d09565b9350506020611e4586828701611d09565b9250506040611e5686828701611d09565b9150509250925092565b611e6981611dcf565b82525050565b611e7881611c54565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015611eb8578082015181840152602081019050611e9d565b83811115611ec7576000848401525b50505050565b6000601f19601f8301169050919050565b6000611ee982611e7e565b611ef38185611e89565b9350611f03818560208601611e9a565b611f0c81611ecd565b840191505092915050565b6000606083016000830151611f2f6000860182611e60565b506020830151611f426020860182611e6f565b5060408301518482036040860152611f5a8282611ede565b9150508091505092915050565b60006020820190508181036000830152611f818184611f17565b905092915050565b600080fd5b600060e08284031215611fa457611fa3611f89565b5b81905092915050565b600060208284031215611fc357611fc2611bc5565b5b600082013567ffffffffffffffff811115611fe157611fe0611bca565b5b611fed84828501611f8e565b91505092915050565b600080600080608085870312156120105761200f611bc5565b5b600061201e87828801611cab565b945050602061202f87828801611d09565b935050604061204087828801611d3f565b925050606061205187828801611d09565b91505092959194509250565b61206681611ce0565b82525050565b6000602082019050612081600083018461205d565b92915050565b6000806000606084860312156120a05761209f611bc5565b5b60006120ae86828701611d09565b93505060206120bf86828701611d3f565b92505060406120d086828701611cab565b9150509250925092565b6120e381611c54565b81146120ee57600080fd5b50565b600081359050612100816120da565b92915050565b60008060006060848603121561211f5761211e611bc5565b5b600061212d86828701611d09565b935050602061213e86828701611d09565b925050604061214f868287016120f1565b9150509250925092565b6000806000806080858703121561217357612172611bc5565b5b600061218187828801611d09565b945050602061219287828801611d09565b93505060406121a387828801611d3f565b92505060606121b487828801611cab565b91505092959194509250565b600082825260208201905092915050565b60006121dc82611e7e565b6121e681856121c0565b93506121f6818560208601611e9a565b6121ff81611ecd565b840191505092915050565b600060608201905061221f6000830186611de3565b61222c6020830185611c60565b818103604083015261223e81846121d1565b9050949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061228f57607f821691505b602082108114156122a3576122a2612248565b5b50919050565b6000602082840312156122bf576122be611bc5565b5b60006122cd84828501611d09565b91505092915050565b6122df81611d1e565b82525050565b60006020820190506122fa60008301846122d6565b92915050565b60008151905061230f81611cf2565b92915050565b60006020828403121561232b5761232a611bc5565b5b600061233984828501612300565b91505092915050565b600082825260208201905092915050565b7f526f6c657352656769737472793a2073656e646572206d75737420626520746f60008201527f6b656e206f776e6572206f7220617070726f7665640000000000000000000000602082015250565b60006123af603583612342565b91506123ba82612353565b604082019050919050565b600060208201905081810360008301526123de816123a2565b9050919050565b7f526f6c657352656769737472793a206163636f756e74206d757374206265207460008201527f6f6b656e206f776e657200000000000000000000000000000000000000000000602082015250565b6000612441602a83612342565b915061244c826123e5565b604082019050919050565b6000602082019050818103600083015261247081612434565b9050919050565b61248081611dcf565b811461248b57600080fd5b50565b60008135905061249d81612477565b92915050565b6000602082840312156124b9576124b8611bc5565b5b60006124c78482850161248e565b91505092915050565b7f526f6c657352656769737472793a2065787069726174696f6e2064617465206d60008201527f75737420626520696e2074686520667574757265000000000000000000000000602082015250565b600061252c603483612342565b9150612537826124d0565b604082019050919050565b6000602082019050818103600083015261255b8161251f565b9050919050565b7f526f6c657352656769737472793a20726f6c65206973206e6f74207265766f6360008201527f61626c6500000000000000000000000000000000000000000000000000000000602082015250565b60006125be602483612342565b91506125c982612562565b604082019050919050565b600060208201905081810360008301526125ed816125b1565b9050919050565b600080fd5b600080fd5b600080fd5b600080833560016020038436030381126126205761261f6125f4565b5b80840192508235915067ffffffffffffffff821115612642576126416125f9565b5b60208301925060018202360383131561265e5761265d6125fe565b5b509250929050565b82818337600083830152505050565b600061268183856121c0565b935061268e838584612666565b61269783611ecd565b840190509392505050565b600060a0820190506126b7600083018961205d565b6126c4602083018861205d565b6126d16040830187611de3565b6126de6060830186611c60565b81810360808301526126f1818486612675565b9050979650505050505050565b7f526f6c657352656769737472793a2073656e646572206d75737420626520617060008201527f70726f7665640000000000000000000000000000000000000000000000000000602082015250565b600061275a602683612342565b9150612765826126fe565b604082019050919050565b600060208201905081810360008301526127898161274d565b9050919050565b7f526f6c657352656769737472793a20526f6c65206973206e6f74207265766f6360008201527f61626c65206f722063616c6c6572206973206e6f7420746865206772616e746560208201527f6500000000000000000000000000000000000000000000000000000000000000604082015250565b6000612812604183612342565b915061281d82612790565b606082019050919050565b6000602082019050818103600083015261284181612805565b9050919050565b600060408201905061285d600083018561205d565b61286a602083018461205d565b939250505056fea2646970667358221220c0ab9a543e48541beeea6483689fdec915032425a82dc477ddbc163b2437655264736f6c63430008090033