ERC165 gives contracts a standard way to advertise supported interfaces. An interface ID is the XOR of its function selectors; it describes a set of signatures, not the implementation’s correctness.
In Solidity the source used:
type(ITest).interfaceId
What changes the identifier
Function selectors depend on the function name and canonical parameter types. Parameter names and return types do not change them. The original examples record those distinctions:
Inspect the empty-interface and selector examples
=> bytes4: 0x00000000
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ITest {
}
contract Test is ITest {
bytes4 public constant IID_ITEST = type(ITest).interfaceId;
}
=> bytes4: 0x0ee2cb10
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ITest {
function getCreator() external;
}
contract Test is ITest {
bytes4 public constant IID_ITEST = type(ITest).interfaceId;
function getCreator() external override { }
}
===========
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ITest {
function getCreator() external returns (uint);
}
contract Test is ITest {
bytes4 public constant IID_ITEST = type(ITest).interfaceId;
function getCreator() external pure override returns (uint) {
return 0;
}
}
=> bytes4: 0xd48e638a
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ITest {
function getCreator(uint name) external returns (uint);
}
contract Test is ITest {
bytes4 public constant IID_ITEST = type(ITest).interfaceId;
function getCreator(uint name) external pure override returns (uint) {
return name;
}
}
===========
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ITest {
function getCreator(uint name2) external returns (uint);
}
contract Test is ITest {
bytes4 public constant IID_ITEST = type(ITest).interfaceId;
function getCreator(uint name2) external pure override returns (uint) {
return name2;
}
}
The empty interface has no selectors to XOR, yielding zero in the source example. Identical identifiers can also arise without identical semantics; a short ID is not a security guarantee.
Historical token and checker examples
Read the ERC1155, ERC721, and checker contracts
// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
contract MockERC1155 is ERC1155 {
constructor() public ERC1155("https://nhancv.com/{id}.json") {
mint(msg.sender, 0, 1);
}
function mint(
address account,
uint256 id,
uint256 amount
) public {
_mint(account, id, amount, "");
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
contract MockERC721 is ERC721 {
constructor(string memory _name, string memory _symbol) ERC721(_name, _symbol) {
mint(msg.sender, 0);
}
function mint(address account, uint256 id) public {
_mint(account, id);
}
/**
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, can be overriden in child contracts.
*/
function _baseURI() internal pure override returns (string memory) {
return "https://nhancv.com";
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
interface ITest {
function isERC1155(address nftAddress) external returns (bool);
function isERC721(address nftAddress) external returns (bool);
}
contract Test is ITest, IERC165 {
using ERC165Checker for address;
bytes4 public constant IID_ITEST = type(ITest).interfaceId;
bytes4 public constant IID_IERC165 = type(IERC165).interfaceId;
bytes4 public constant IID_IERC1155 = type(IERC1155).interfaceId;
bytes4 public constant IID_IERC721 = type(IERC721).interfaceId;
function isERC1155(address nftAddress) external view override returns (bool) {
return nftAddress.supportsInterface(IID_IERC1155);
}
function isERC721(address nftAddress) external view override returns (bool) {
return nftAddress.supportsInterface(IID_IERC721);
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == IID_ITEST || interfaceId == IID_IERC165;
}
}
These imports and overrides belong to the original Solidity/OpenZeppelin generation. Their presence does not establish compatibility with a newly installed package version.
The standard requires support for its own ID, rejection of 0xffffffff, and a bounded gas cost for the query. A contract can still advertise an interface incorrectly, so discovery does not replace checking actual behavior and authorization. No contracts were compiled or queried for this revision. Reference: ERC165 specification.