Skip to content

Instantly share code, notes, and snippets.

@the-vampiire
Last active May 11, 2022 14:59
Show Gist options
  • Save the-vampiire/1b4e8cd92b20dc4f034457c926210965 to your computer and use it in GitHub Desktop.
Save the-vampiire/1b4e8cd92b20dc4f034457c926210965 to your computer and use it in GitHub Desktop.
ERC165 interface IDs (ERC721 etc)
const INTERFACE_IDS = {
ERC165: '0x01ffc9a7',
ERC721: '0x80ac58cd',
ERC721Enumerable: '0x780e9d63',
ERC721Metadata: '0x5b5e139f',
ERC1155: '0xd9b67a26',
ERC1155Receiver: '0x4e2312e0',
AccessControl: '0x7965db0b',
AccessControlEnumerable: '0x5a05180f',
Governor: '0xbf26d897',
GovernorWithParams: '0x79dd796f',
GovernorTimelock: '0x6e665ced',
ERC2981: '0x2a55205a'
}
};
// computed from open zeppelin
// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/test/utils/introspection/SupportsInterface.behavior.js
// https://github.com/OpenZeppelin/openzeppelin-test-helpers/blob/master/src/makeInterfaceId.js
const { soliditySha3 } = require("web3-utils");
const INTERFACES = {
ERC165: ["supportsInterface(bytes4)"],
ERC721: [
"balanceOf(address)",
"ownerOf(uint256)",
"approve(address,uint256)",
"getApproved(uint256)",
"setApprovalForAll(address,bool)",
"isApprovedForAll(address,address)",
"transferFrom(address,address,uint256)",
"safeTransferFrom(address,address,uint256)",
"safeTransferFrom(address,address,uint256,bytes)",
],
ERC721Enumerable: [
"totalSupply()",
"tokenOfOwnerByIndex(address,uint256)",
"tokenByIndex(uint256)",
],
ERC721Metadata: ["name()", "symbol()", "tokenURI(uint256)"],
ERC1155: [
"balanceOf(address,uint256)",
"balanceOfBatch(address[],uint256[])",
"setApprovalForAll(address,bool)",
"isApprovedForAll(address,address)",
"safeTransferFrom(address,address,uint256,uint256,bytes)",
"safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)",
],
ERC1155Receiver: [
"onERC1155Received(address,address,uint256,uint256,bytes)",
"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)",
],
AccessControl: [
"hasRole(bytes32,address)",
"getRoleAdmin(bytes32)",
"grantRole(bytes32,address)",
"revokeRole(bytes32,address)",
"renounceRole(bytes32,address)",
],
AccessControlEnumerable: [
"getRoleMember(bytes32,uint256)",
"getRoleMemberCount(bytes32)",
],
Governor: [
"name()",
"version()",
"COUNTING_MODE()",
"hashProposal(address[],uint256[],bytes[],bytes32)",
"state(uint256)",
"proposalSnapshot(uint256)",
"proposalDeadline(uint256)",
"votingDelay()",
"votingPeriod()",
"quorum(uint256)",
"getVotes(address,uint256)",
"hasVoted(uint256,address)",
"propose(address[],uint256[],bytes[],string)",
"execute(address[],uint256[],bytes[],bytes32)",
"castVote(uint256,uint8)",
"castVoteWithReason(uint256,uint8,string)",
"castVoteBySig(uint256,uint8,uint8,bytes32,bytes32)",
],
GovernorWithParams: [
"name()",
"version()",
"COUNTING_MODE()",
"hashProposal(address[],uint256[],bytes[],bytes32)",
"state(uint256)",
"proposalSnapshot(uint256)",
"proposalDeadline(uint256)",
"votingDelay()",
"votingPeriod()",
"quorum(uint256)",
"getVotes(address,uint256)",
"getVotesWithParams(address,uint256,bytes)",
"hasVoted(uint256,address)",
"propose(address[],uint256[],bytes[],string)",
"execute(address[],uint256[],bytes[],bytes32)",
"castVote(uint256,uint8)",
"castVoteWithReason(uint256,uint8,string)",
"castVoteWithReasonAndParams(uint256,uint8,string,bytes)",
"castVoteBySig(uint256,uint8,uint8,bytes32,bytes32)",
"castVoteWithReasonAndParamsBySig(uint256,uint8,string,bytes,uint8,bytes32,bytes32)",
],
GovernorTimelock: [
"timelock()",
"proposalEta(uint256)",
"queue(address[],uint256[],bytes[],bytes32)",
],
ERC2981: ["royaltyInfo(uint256,uint256)"],
};
function ERC165(functionSignatures = []) {
const INTERFACE_ID_LENGTH = 4;
const interfaceIdBuffer = functionSignatures
.map((signature) => soliditySha3(signature)) // keccak256
.map(
(h) => Buffer.from(h.substring(2), "hex").slice(0, 4) // bytes4()
)
.reduce((memo, bytes) => {
for (let i = 0; i < INTERFACE_ID_LENGTH; i++) {
memo[i] = memo[i] ^ bytes[i]; // xor
}
return memo;
}, Buffer.alloc(INTERFACE_ID_LENGTH));
return `0x${interfaceIdBuffer.toString("hex")}`;
}
const INTERFACE_IDS = {};
const FN_SIGNATURES = {};
for (const k of Object.getOwnPropertyNames(INTERFACES)) {
INTERFACE_IDS[k] = ERC165(INTERFACES[k]);
for (const fnName of INTERFACES[k]) {
// the interface id of a single function is equivalent to its function signature
FN_SIGNATURES[fnName] = ERC165([fnName]);
}
}
console.log({
INTERFACE_IDS,
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment