Contract Address Details

0xc1ebaaF29b85e2C716Dc610A888750c4D60d5644

Contract Name
RoyaltiesRegistry
Creator
0x0ca38e–8259bd at 0xc9205c–012136
Balance
0 CHZ ( )
Tokens
Fetching tokens...
Transactions
0 Transactions
Transfers
0 Transfers
Gas Used
Fetching gas used...
Last Balance Update
17543394
Contract name:
RoyaltiesRegistry




Optimization enabled
true
Compiler version
v0.7.6+commit.7338295f




Optimization runs
200
EVM Version
istanbul




Verified at
2023-10-26T13:49:04.194513Z

@rarible/royalties-registry/contracts/RoyaltiesRegistry.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;
pragma abicoder v2;

import "@rarible/exchange-interfaces/contracts/IRoyaltiesProvider.sol";
import "@rarible/royalties/contracts/LibRoyaltiesV2.sol";
import "@rarible/royalties/contracts/LibRoyaltiesV1.sol";
import "@rarible/royalties/contracts/LibRoyalties2981.sol";
import "@rarible/royalties/contracts/RoyaltiesV1.sol";
import "@rarible/royalties/contracts/RoyaltiesV2.sol";
import "@rarible/royalties/contracts/IERC2981.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

contract RoyaltiesRegistry is IRoyaltiesProvider, OwnableUpgradeable {
    /// @dev deprecated
    event RoyaltiesSetForToken(address indexed token, uint indexed tokenId, LibPart.Part[] royalties);
    /// @dev emitted when royalties set for token in 
    event RoyaltiesSetForContract(address indexed token, LibPart.Part[] royalties);

    /// @dev struct to store royalties in royaltiesByToken
    struct RoyaltiesSet {
        bool initialized;
        LibPart.Part[] royalties;
    }

    /// @dev deprecated
    mapping(bytes32 => RoyaltiesSet) public royaltiesByTokenAndTokenId;
    /// @dev stores royalties for token contract, set in setRoyaltiesByToken() method
    mapping(address => RoyaltiesSet) public royaltiesByToken;
    /// @dev stores external provider and royalties type for token contract
    mapping(address => uint) public royaltiesProviders;

    /// @dev total amount or supported royalties types
    // 0 - royalties type is unset
    // 1 - royaltiesByToken, 2 - v2, 3 - v1,
    // 4 - external provider, 5 - EIP-2981
    // 6 - unsupported/nonexistent royalties type
    uint constant royaltiesTypesAmount = 6;

    function __RoyaltiesRegistry_init() external initializer {
        __Ownable_init_unchained();
    }

    /// @dev sets external provider for token contract, and royalties type = 4
    function setProviderByToken(address token, address provider) external {
        checkOwner(token);
        setRoyaltiesType(token, 4, provider);
    }

    /// @dev returns provider address for token contract from royaltiesProviders mapping
    function getProvider(address token) public view returns(address) {
        return address(royaltiesProviders[token]);
    }

    /// @dev returns royalties type for token contract
    function getRoyaltiesType(address token) external view returns(uint) {
        return _getRoyaltiesType(royaltiesProviders[token]);
    }

    /// @dev returns royalties type from uint
    function _getRoyaltiesType(uint data) internal pure returns(uint) {
        for (uint i = 1; i <= royaltiesTypesAmount; ++i) {
            if (data / 2**(256-i) == 1) {
                return i;
            }
        }
        return 0;
    }

    /// @dev sets royalties type for token contract
    function setRoyaltiesType(address token, uint royaltiesType, address royaltiesProvider) internal {
        require(royaltiesType > 0 && royaltiesType <= royaltiesTypesAmount, "wrong royaltiesType");
        royaltiesProviders[token] = uint(royaltiesProvider) + 2**(256 - royaltiesType);
    }

    /// @dev clears and sets new royalties type for token contract
    function forceSetRoyaltiesType(address token, uint royaltiesType) external {
        checkOwner(token);
        setRoyaltiesType(token, royaltiesType, getProvider(token));
    }

    /// @dev clears royalties type for token contract
    function clearRoyaltiesType(address token) external {
        checkOwner(token);
        royaltiesProviders[token] = uint(getProvider(token));
    }

    /// @dev sets royalties for token contract in royaltiesByToken mapping and royalties type = 1
    function setRoyaltiesByToken(address token, LibPart.Part[] memory royalties) external {
        checkOwner(token);
        //clearing royaltiesProviders value for the token
        delete royaltiesProviders[token];
        // setting royaltiesType = 1 for the token
        setRoyaltiesType(token, 1, address(0));
        uint sumRoyalties = 0;
        delete royaltiesByToken[token];
        for (uint i = 0; i < royalties.length; ++i) {
            require(royalties[i].account != address(0x0), "RoyaltiesByToken recipient should be present");
            require(royalties[i].value != 0, "Royalty value for RoyaltiesByToken should be > 0");
            royaltiesByToken[token].royalties.push(royalties[i]);
            sumRoyalties += royalties[i].value;
        }
        require(sumRoyalties < 10000, "Set by token royalties sum more, than 100%");
        royaltiesByToken[token].initialized = true;
        emit RoyaltiesSetForContract(token, royalties);
    }

    /// @dev checks if msg.sender is owner of this contract or owner of the token contract
    function checkOwner(address token) internal view {
        if ((owner() != _msgSender()) && (OwnableUpgradeable(token).owner() != _msgSender())) {
            revert("Token owner not detected");
        }
    }

    /// @dev calculates royalties type for token contract
    function calculateRoyaltiesType(address token, address royaltiesProvider ) internal view returns(uint) {   
        try IERC165Upgradeable(token).supportsInterface(LibRoyaltiesV2._INTERFACE_ID_ROYALTIES) returns(bool result) {
            if (result) {
                return 2;
            }
        } catch { }

        try IERC165Upgradeable(token).supportsInterface(LibRoyaltiesV1._INTERFACE_ID_FEES) returns(bool result) {
            if (result) {
                return 3;
            }
        } catch { }
        
        try IERC165Upgradeable(token).supportsInterface(LibRoyalties2981._INTERFACE_ID_ROYALTIES) returns(bool result) {
            if (result) {
                return 5;
            }
        } catch { }
        
        if (royaltiesProvider != address(0)) {
            return 4;
        }

        if (royaltiesByToken[token].initialized) {
            return 1;
        }

        return 6;
    }

    /// @dev returns royalties for token contract and token id
    function getRoyalties(address token, uint tokenId) override external returns (LibPart.Part[] memory) {
        uint royaltiesProviderData = royaltiesProviders[token];

        address royaltiesProvider = address(royaltiesProviderData);
        uint royaltiesType = _getRoyaltiesType(royaltiesProviderData);

        // case when royaltiesType is not set
        if (royaltiesType == 0) {
            // calculating royalties type for token
            royaltiesType = calculateRoyaltiesType(token, royaltiesProvider);
            
            //saving royalties type
            setRoyaltiesType(token, royaltiesType, royaltiesProvider);
        }

        //case royaltiesType = 1, royalties are set in royaltiesByToken
        if (royaltiesType == 1) {
            return royaltiesByToken[token].royalties;
        }

        //case royaltiesType = 2, royalties rarible v2
        if (royaltiesType == 2) {
            return getRoyaltiesRaribleV2(token,tokenId);
        }

        //case royaltiesType = 3, royalties rarible v1
        if (royaltiesType == 3) {
            return getRoyaltiesRaribleV1(token, tokenId);
        }

        //case royaltiesType = 4, royalties from external provider
        if (royaltiesType == 4) {
            return providerExtractor(token, tokenId, royaltiesProvider);
        }

        //case royaltiesType = 5, royalties EIP-2981
        if (royaltiesType == 5) {
            return getRoyaltiesEIP2981(token, tokenId);
        }

        // case royaltiesType = 6, unknown/empty royalties
        if (royaltiesType == 6) {
            return new LibPart.Part[](0);
        } 

        revert("something wrong in getRoyalties");
    }

    /// @dev tries to get royalties rarible-v2 for token and tokenId
    function getRoyaltiesRaribleV2(address token, uint tokenId) internal view returns (LibPart.Part[] memory) {
        try RoyaltiesV2(token).getRaribleV2Royalties(tokenId) returns (LibPart.Part[] memory result) {
            return result;
        } catch {
            return new LibPart.Part[](0);
        }
    }

    /// @dev tries to get royalties rarible-v1 for token and tokenId
    function getRoyaltiesRaribleV1(address token, uint tokenId) internal view returns (LibPart.Part[] memory) {
        RoyaltiesV1 v1 = RoyaltiesV1(token);
        address payable[] memory recipients;
        try v1.getFeeRecipients(tokenId) returns (address payable[] memory resultRecipients) {
            recipients = resultRecipients;
        } catch {
            return new LibPart.Part[](0);
        }
        uint[] memory values;
        try v1.getFeeBps(tokenId) returns (uint[] memory resultValues) {
            values = resultValues;
        } catch {
            return new LibPart.Part[](0);
        }
        if (values.length != recipients.length) {
            return new LibPart.Part[](0);
        }
        LibPart.Part[] memory result = new LibPart.Part[](values.length);
        for (uint256 i = 0; i < values.length; ++i) {
            result[i].value = uint96(values[i]);
            result[i].account = recipients[i];
        }
        return result;
    }

    /// @dev tries to get royalties EIP-2981 for token and tokenId
    function getRoyaltiesEIP2981(address token, uint tokenId) internal view returns (LibPart.Part[] memory) {
        try IERC2981(token).royaltyInfo(tokenId, LibRoyalties2981._WEIGHT_VALUE) returns (address receiver, uint256 royaltyAmount) {
            return LibRoyalties2981.calculateRoyalties(receiver, royaltyAmount);
        } catch {
            return new LibPart.Part[](0);
        }
    }

    /// @dev tries to get royalties for token and tokenId from external provider set in royaltiesProviders
    function providerExtractor(address token, uint tokenId, address providerAddress) internal returns (LibPart.Part[] memory) {
        try IRoyaltiesProvider(providerAddress).getRoyalties(token, tokenId) returns (LibPart.Part[] memory result) {
            return result;
        } catch {
            return new LibPart.Part[](0);
        }
    }

    uint256[46] private __gap;
}
        

@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

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

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal initializer {
        __Context_init_unchained();
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal initializer {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

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

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

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

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

@openzeppelin/contracts-upgradeable/introspection/IERC165Upgradeable.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

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

@openzeppelin/contracts-upgradeable/proxy/Initializable.sol

// SPDX-License-Identifier: MIT

// solhint-disable-next-line compiler-version
pragma solidity >=0.4.24 <0.8.0;

import "../utils/AddressUpgradeable.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 */
abstract contract Initializable {

    /**
     * @dev Indicates that the contract has been initialized.
     */
    bool private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Modifier to protect an initializer function from being invoked twice.
     */
    modifier initializer() {
        require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized");

        bool isTopLevelCall = !_initializing;
        if (isTopLevelCall) {
            _initializing = true;
            _initialized = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;
        }
    }

    /// @dev Returns true if and only if the function is running in the constructor
    function _isConstructor() private view returns (bool) {
        return !AddressUpgradeable.isContract(address(this));
    }
}
          

@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

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

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

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

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

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

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

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

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

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

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

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

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

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

@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;
import "../proxy/Initializable.sol";

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

    function __Context_init_unchained() internal initializer {
    }
    function _msgSender() internal view virtual returns (address payable) {
        return msg.sender;
    }

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

@rarible/exchange-interfaces/contracts/IRoyaltiesProvider.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;
pragma abicoder v2;

import "@rarible/lib-part/contracts/LibPart.sol";

interface IRoyaltiesProvider {
    function getRoyalties(address token, uint tokenId) external returns (LibPart.Part[] memory);
}
          

@rarible/lib-part/contracts/LibPart.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

library LibPart {
    bytes32 public constant TYPE_HASH = keccak256("Part(address account,uint96 value)");

    struct Part {
        address payable account;
        uint96 value;
    }

    function hash(Part memory part) internal pure returns (bytes32) {
        return keccak256(abi.encode(TYPE_HASH, part.account, part.value));
    }
}
          

@rarible/royalties/contracts/IERC2981.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;
import "@rarible/lib-part/contracts/LibPart.sol";
///
/// @dev Interface for the NFT Royalty Standard
///
//interface IERC2981 is IERC165 {
interface IERC2981 {
    /// ERC165 bytes to add to interface array - set in parent contract
    /// implementing this standard
    ///
    /// bytes4(keccak256("royaltyInfo(uint256,uint256)")) == 0x2a55205a
    /// bytes4 private constant _INTERFACE_ID_ERC2981 = 0x2a55205a;
    /// _registerInterface(_INTERFACE_ID_ERC2981);

    /// @notice Called with the sale price to determine how much royalty
    //          is owed and to whom.
    /// @param _tokenId - the NFT asset queried for royalty information
    /// @param _salePrice - the sale price of the NFT asset specified by _tokenId
    /// @return receiver - address of who should be sent the royalty payment
    /// @return royaltyAmount - the royalty payment amount for _salePrice
    function royaltyInfo(
        uint256 _tokenId,
        uint256 _salePrice
    ) external view returns (
        address receiver,
        uint256 royaltyAmount
    );
}
          

@rarible/royalties/contracts/LibRoyalties2981.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

import "@rarible/lib-part/contracts/LibPart.sol";

library LibRoyalties2981 {
    /*
     * https://eips.ethereum.org/EIPS/eip-2981: bytes4 private constant _INTERFACE_ID_ERC2981 = 0x2a55205a;
     */
    bytes4 constant _INTERFACE_ID_ROYALTIES = 0x2a55205a;
    uint96 constant _WEIGHT_VALUE = 1000000;

    /*Method for converting amount to percent and forming LibPart*/
    function calculateRoyalties(address to, uint256 amount) internal view returns (LibPart.Part[] memory) {
        LibPart.Part[] memory result;
        if (amount == 0) {
            return result;
        }
        uint256 percent = amount * 10000 / _WEIGHT_VALUE;
        require(percent < 10000, "Royalties 2981 exceeds 100%");
        result = new LibPart.Part[](1);
        result[0].account = payable(to);
        result[0].value = uint96(percent);
        return result;
    }
}
          

@rarible/royalties/contracts/LibRoyaltiesV1.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

library LibRoyaltiesV1 {
    /*
     * bytes4(keccak256('getFeeBps(uint256)')) == 0x0ebd4c7f
     * bytes4(keccak256('getFeeRecipients(uint256)')) == 0xb9c4d9fb
     *
     * => 0x0ebd4c7f ^ 0xb9c4d9fb == 0xb7799584
     */
    bytes4 constant _INTERFACE_ID_FEES = 0xb7799584;
}
          

@rarible/royalties/contracts/LibRoyaltiesV2.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

library LibRoyaltiesV2 {
    /*
     * bytes4(keccak256('getRaribleV2Royalties(uint256)')) == 0xcad96cca
     */
    bytes4 constant _INTERFACE_ID_ROYALTIES = 0xcad96cca;
}
          

@rarible/royalties/contracts/RoyaltiesV1.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

interface RoyaltiesV1 {
    event SecondarySaleFees(uint256 tokenId, address[] recipients, uint[] bps);

    function getFeeRecipients(uint256 id) external view returns (address payable[] memory);
    function getFeeBps(uint256 id) external view returns (uint[] memory);
}
          

@rarible/royalties/contracts/RoyaltiesV2.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;
pragma abicoder v2;

import "@rarible/lib-part/contracts/LibPart.sol";

interface RoyaltiesV2 {
    event RoyaltiesSet(uint256 tokenId, LibPart.Part[] royalties);

    function getRaribleV2Royalties(uint256 id) external view returns (LibPart.Part[] memory);
}
          

Contract ABI

[{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"__RoyaltiesRegistry_init","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"clearRoyaltiesType","inputs":[{"type":"address","name":"token","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"forceSetRoyaltiesType","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"royaltiesType","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"getProvider","inputs":[{"type":"address","name":"token","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"tuple[]","name":"","internalType":"struct LibPart.Part[]","components":[{"type":"address"},{"type":"uint96"}]}],"name":"getRoyalties","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getRoyaltiesType","inputs":[{"type":"address","name":"token","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"initialized","internalType":"bool"}],"name":"royaltiesByToken","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"initialized","internalType":"bool"}],"name":"royaltiesByTokenAndTokenId","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"royaltiesProviders","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setProviderByToken","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"address","name":"provider","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRoyaltiesByToken","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"tuple[]","name":"royalties","internalType":"struct LibPart.Part[]","components":[{"type":"address"},{"type":"uint96"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","indexed":true},{"type":"address","name":"newOwner","indexed":true}],"anonymous":false},{"type":"event","name":"RoyaltiesSetForContract","inputs":[{"type":"address","name":"token","indexed":true},{"type":"tuple[]","name":"royalties","indexed":false,"components":[{"type":"address"},{"type":"uint96"}]}],"anonymous":false},{"type":"event","name":"RoyaltiesSetForToken","inputs":[{"type":"address","name":"token","indexed":true},{"type":"uint256","name":"tokenId","indexed":true},{"type":"tuple[]","name":"royalties","indexed":false,"components":[{"type":"address"},{"type":"uint96"}]}],"anonymous":false}]
            

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106100ea5760003560e01c80639ca7dc7a1161008c578063d836f01311610066578063d836f013146101cb578063f2fde38b146101de578063f39cc706146101f1578063fc73be0014610204576100ea565b80639ca7dc7a14610185578063acf14efb146101a5578063d1da3cce146101b8576100ea565b806355f21eb7116100c857806355f21eb714610135578063715018a61461015557806382b19f121461015d5780638da5cb5b1461017d576100ea565b806305df952f146100ef57806327fff8ab1461011857806336eff6c214610122575b600080fd5b6101026100fd366004611449565b610217565b60405161010f91906118be565b60405180910390f35b61012061022c565b005b6101206101303660046115a9565b6102d6565b610148610143366004611449565b6102f6565b60405161010f9190611830565b610120610315565b61017061016b366004611449565b6103d3565b60405161010f9190611a5f565b6101486103fb565b6101986101933660046115a9565b61040a565b60405161010f919061185d565b6101206101b33660046114b9565b6105a8565b6101026101c6366004611818565b6107e4565b6101206101d9366004611481565b6107f9565b6101206101ec366004611449565b61080e565b6101706101ff366004611449565b610923565b610120610212366004611449565b610935565b60666020526000908152604090205460ff1681565b600054610100900460ff16806102455750610245610966565b80610253575060005460ff16155b61028e5760405162461bcd60e51b815260040180806020018281038252602e815260200180611b12602e913960400191505060405180910390fd5b600054610100900460ff161580156102b9576000805460ff1961ff0019909116610100171660011790555b6102c1610977565b80156102d3576000805461ff00191690555b50565b6102df82610a70565b6102f282826102ed856102f6565b610b46565b5050565b6001600160a01b0381166000908152606760205260409020545b919050565b61031d610b9d565b6001600160a01b031661032e6103fb565b6001600160a01b031614610389576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6033546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3603380546001600160a01b0319169055565b6001600160a01b0381166000908152606760205260408120546103f590610ba1565b92915050565b6033546001600160a01b031690565b6001600160a01b038216600090815260676020526040812054606091819061043182610ba1565b90508061044f576104428683610bdf565b905061044f868284610b46565b80600114156104eb576001600160a01b038616600090815260666020908152604080832060010180548251818502810185019093528083529193909284015b828210156104dd57600084815260209081902060408051808201909152908401546001600160a01b0381168252600160a01b90046001600160601b03168183015282526001909201910161048e565b5050505093505050506103f5565b8060021415610508576104fe8686610ded565b93505050506103f5565b806003141561051b576104fe8686610ead565b806004141561052f576104fe868684611161565b8060051415610542576104fe8686611228565b806006141561058757604080516000808252602082019092529061057c565b610569611400565b8152602001906001900390816105615790505b5093505050506103f5565b60405162461bcd60e51b815260040161059f906118de565b60405180910390fd5b6105b182610a70565b6001600160a01b03821660009081526067602052604081208190556105da908390600190610b46565b6001600160a01b0382166000908152606660205260408120805460ff19168155816106086001830182611417565b505060005b82518110156107625760006001600160a01b031683828151811061062d57fe5b6020026020010151600001516001600160a01b031614156106605760405162461bcd60e51b815260040161059f90611915565b82818151811061066c57fe5b6020026020010151602001516001600160601b0316600014156106a15760405162461bcd60e51b815260040161059f906119e2565b60666000856001600160a01b03166001600160a01b031681526020019081526020016000206001018382815181106106d557fe5b602090810291909101810151825460018101845560009384529282902081519301805491909201516001600160601b0316600160a01b026001600160a01b039384166001600160a01b031990921691909117909216919091179055825183908290811061073e57fe5b6020026020010151602001516001600160601b03168201915080600101905061060d565b5061271081106107845760405162461bcd60e51b815260040161059f90611961565b6001600160a01b03831660008181526066602052604090819020805460ff19166001179055517fc026171b9a7c9009d6a748a19a0a3cb877978a585e1647a87a786d724bbde127906107d790859061185d565b60405180910390a2505050565b60656020526000908152604090205460ff1681565b61080282610a70565b6102f282600483610b46565b610816610b9d565b6001600160a01b03166108276103fb565b6001600160a01b031614610882576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b0381166108c75760405162461bcd60e51b8152600401808060200182810382526026815260200180611aec6026913960400191505060405180910390fd5b6033546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3603380546001600160a01b0319166001600160a01b0392909216919091179055565b60676020526000908152604090205481565b61093e81610a70565b610947816102f6565b6001600160a01b03918216600090815260676020526040902091169055565b6000610971306112f2565b15905090565b600054610100900460ff16806109905750610990610966565b8061099e575060005460ff16155b6109d95760405162461bcd60e51b815260040180806020018281038252602e815260200180611b12602e913960400191505060405180910390fd5b600054610100900460ff16158015610a04576000805460ff1961ff0019909116610100171660011790555b6000610a0e610b9d565b603380546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a35080156102d3576000805461ff001916905550565b610a78610b9d565b6001600160a01b0316610a896103fb565b6001600160a01b031614158015610b295750610aa3610b9d565b6001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610ae557600080fd5b505afa158015610af9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b1d9190611465565b6001600160a01b031614155b156102d35760405162461bcd60e51b815260040161059f906119ab565b600082118015610b57575060068211155b610b735760405162461bcd60e51b815260040161059f90611a32565b6001600160a01b03928316600090815260676020526040902092166101009190910360020a019055565b3390565b600060015b60068111610bd657806101000360020a8381610bbe57fe5b0460011415610bce579050610310565b600101610ba6565b50600092915050565b6040516301ffc9a760e01b81526000906001600160a01b038416906301ffc9a790610c159063656cb66560e11b906004016118c9565b60206040518083038186803b158015610c2d57600080fd5b505afa925050508015610c5d575060408051601f3d908101601f19168201909252610c5a918101906117f8565b60015b610c6657610c78565b8015610c765760029150506103f5565b505b6040516301ffc9a760e01b81526001600160a01b038416906301ffc9a790610cab90632dde656160e21b906004016118c9565b60206040518083038186803b158015610cc357600080fd5b505afa925050508015610cf3575060408051601f3d908101601f19168201909252610cf0918101906117f8565b60015b610cfc57610d0e565b8015610d0c5760039150506103f5565b505b6040516301ffc9a760e01b81526001600160a01b038416906301ffc9a790610d419063152a902d60e11b906004016118c9565b60206040518083038186803b158015610d5957600080fd5b505afa925050508015610d89575060408051601f3d908101601f19168201909252610d86918101906117f8565b60015b610d9257610da4565b8015610da25760059150506103f5565b505b6001600160a01b03821615610dbb575060046103f5565b6001600160a01b03831660009081526066602052604090205460ff1615610de4575060016103f5565b50600692915050565b60405163656cb66560e11b81526060906001600160a01b0384169063cad96cca90610e1c908590600401611a5f565b60006040518083038186803b158015610e3457600080fd5b505afa925050508015610e6957506040513d6000823e601f3d908101601f19168201604052610e66919081019061169a565b60015b610ea6576040805160008082526020820190925290610e9e565b610e8b611400565b815260200190600190039081610e835790505b5090506103f5565b90506103f5565b60405163b9c4d9fb60e01b8152606090839082906001600160a01b0383169063b9c4d9fb90610ee0908790600401611a5f565b60006040518083038186803b158015610ef857600080fd5b505afa925050508015610f2d57506040513d6000823e601f3d908101601f19168201604052610f2a9190810190611601565b60015b610f6c576040805160008082526020820190925290610f62565b610f4f611400565b815260200190600190039081610f475790505b50925050506103f5565b9050604051630ebd4c7f60e01b81526060906001600160a01b03841690630ebd4c7f90610f9d908890600401611a5f565b60006040518083038186803b158015610fb557600080fd5b505afa925050508015610fea57506040513d6000823e601f3d908101601f19168201604052610fe79190810190611774565b60015b61102957604080516000808252602082019092529061057c565b61100c611400565b8152602001906001900390816110045790505093505050506103f5565b9050815181511461106f57604080516000808252602082019092529061057c565b611052611400565b81526020019060019003908161104a5790505093505050506103f5565b6000815167ffffffffffffffff8111801561108957600080fd5b506040519080825280602002602001820160405280156110c357816020015b6110b0611400565b8152602001906001900390816110a85790505b50905060005b8251811015611156578281815181106110de57fe5b60200260200101518282815181106110f257fe5b6020026020010151602001906001600160601b031690816001600160601b03168152505083818151811061112257fe5b602002602001015182828151811061113657fe5b60209081029190910101516001600160a01b0390911690526001016110c9565b509695505050505050565b604051634e53ee3d60e11b81526060906001600160a01b03831690639ca7dc7a906111929087908790600401611844565b600060405180830381600087803b1580156111ac57600080fd5b505af19250505080156111e157506040513d6000823e601f3d908101601f191682016040526111de919081019061169a565b60015b61121e576040805160008082526020820190925290611216565b611203611400565b8152602001906001900390816111fb5790505b509050611221565b90505b9392505050565b60405163152a902d60e11b81526060906001600160a01b03841690632a55205a9061125c908590620f424090600401611a68565b604080518083038186803b15801561127357600080fd5b505afa9250505080156112a3575060408051601f3d908101601f191682019092526112a0918101906115d4565b60015b6112df576040805160008082526020820190925290610e9e565b6112c5611400565b8152602001906001900390816112bd5790505090506103f5565b6112e982826112f8565b925050506103f5565b3b151590565b606080826113075790506103f5565b6000620f42406127108502049050612710811061136b576040805162461bcd60e51b815260206004820152601b60248201527f526f79616c746965732032393831206578636565647320313030250000000000604482015290519081900360640190fd5b60408051600180825281830190925290816020015b611388611400565b81526020019060019003908161138057905050915084826000815181106113ab57fe5b6020026020010151600001906001600160a01b031690816001600160a01b03168152505080826000815181106113dd57fe5b6020908102919091018101516001600160601b0390921691015250905092915050565b604080518082019091526000808252602082015290565b50805460008255906000526020600020908101906102d391905b808211156114455760008155600101611431565b5090565b60006020828403121561145a578081fd5b813561122181611ac1565b600060208284031215611476578081fd5b815161122181611ac1565b60008060408385031215611493578081fd5b823561149e81611ac1565b915060208301356114ae81611ac1565b809150509250929050565b60008060408084860312156114cc578283fd5b83356114d781611ac1565b925060208481013567ffffffffffffffff808211156114f4578485fd5b818701915087601f830112611507578485fd5b813561151a61151582611aa3565b611a7f565b81815284810190848601878402860187018c1015611536578889fd5b8895505b838610156115975787818d031215611550578889fd5b8751888101818110878211171561156357fe5b8952813561157081611ac1565b81528188013561157f81611ad6565b8189015283526001959095019491860191870161153a565b50809750505050505050509250929050565b600080604083850312156115bb578182fd5b82356115c681611ac1565b946020939093013593505050565b600080604083850312156115e6578182fd5b82516115f181611ac1565b6020939093015192949293505050565b60006020808385031215611613578182fd5b825167ffffffffffffffff811115611629578283fd5b8301601f81018513611639578283fd5b805161164761151582611aa3565b8181528381019083850185840285018601891015611663578687fd5b8694505b8385101561168e57805161167a81611ac1565b835260019490940193918501918501611667565b50979650505050505050565b600060208083850312156116ac578182fd5b825167ffffffffffffffff808211156116c3578384fd5b818501915085601f8301126116d6578384fd5b81516116e461151582611aa3565b818152848101908486016040808502870188018b1015611702578889fd5b8896505b848710156117655780828c03121561171c578889fd5b8051818101818110888211171561172f57fe5b8252825161173c81611ac1565b81528289015161174b81611ad6565b818a01528452600196909601959287019290810190611706565b50909998505050505050505050565b60006020808385031215611786578182fd5b825167ffffffffffffffff81111561179c578283fd5b8301601f810185136117ac578283fd5b80516117ba61151582611aa3565b81815283810190838501858402850186018910156117d6578687fd5b8694505b8385101561168e5780518352600194909401939185019185016117da565b600060208284031215611809578081fd5b81518015158114611221578182fd5b600060208284031215611829578081fd5b5035919050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b602080825282518282018190526000919060409081850190868401855b828110156118b157815180516001600160a01b031685528601516001600160601b031686850152928401929085019060010161187a565b5091979650505050505050565b901515815260200190565b6001600160e01b031991909116815260200190565b6020808252601f908201527f736f6d657468696e672077726f6e6720696e20676574526f79616c7469657300604082015260600190565b6020808252602c908201527f526f79616c746965734279546f6b656e20726563697069656e742073686f756c60408201526b19081899481c1c995cd95b9d60a21b606082015260800190565b6020808252602a908201527f53657420627920746f6b656e20726f79616c746965732073756d206d6f72652c604082015269207468616e203130302560b01b606082015260800190565b60208082526018908201527f546f6b656e206f776e6572206e6f742064657465637465640000000000000000604082015260600190565b60208082526030908201527f526f79616c74792076616c756520666f7220526f79616c746965734279546f6b60408201526f0656e2073686f756c64206265203e20360841b606082015260800190565b60208082526013908201527277726f6e6720726f79616c746965735479706560681b604082015260600190565b90815260200190565b9182526001600160601b0316602082015260400190565b60405181810167ffffffffffffffff81118282101715611a9b57fe5b604052919050565b600067ffffffffffffffff821115611ab757fe5b5060209081020190565b6001600160a01b03811681146102d357600080fd5b6001600160601b03811681146102d357600080fdfe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373496e697469616c697a61626c653a20636f6e747261637420697320616c726561647920696e697469616c697a6564a2646970667358221220f878997b3993921c7d742a989b91f3f44ce15246365b6de753ca92808d9c105c64736f6c63430007060033