123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- // SPDX-License-Identifier: MIT
- // OpenZeppelin Contracts (last updated v4.8.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;
- }
- }
|