SupportsInterface.behavior.js 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. const { makeInterfaceId } = require('openzeppelin-test-helpers');
  2. const INTERFACES = {
  3. ERC165: [
  4. 'supportsInterface(bytes4)',
  5. ],
  6. ERC721: [
  7. 'balanceOf(address)',
  8. 'ownerOf(uint256)',
  9. 'approve(address,uint256)',
  10. 'getApproved(uint256)',
  11. 'setApprovalForAll(address,bool)',
  12. 'isApprovedForAll(address,address)',
  13. 'transferFrom(address,address,uint256)',
  14. 'safeTransferFrom(address,address,uint256)',
  15. 'safeTransferFrom(address,address,uint256,bytes)',
  16. ],
  17. ERC721Enumerable: [
  18. 'totalSupply()',
  19. 'tokenOfOwnerByIndex(address,uint256)',
  20. 'tokenByIndex(uint256)',
  21. ],
  22. ERC721Metadata: [
  23. 'name()',
  24. 'symbol()',
  25. 'tokenURI(uint256)',
  26. ],
  27. };
  28. const INTERFACE_IDS = {};
  29. const FN_SIGNATURES = {};
  30. for (const k of Object.getOwnPropertyNames(INTERFACES)) {
  31. INTERFACE_IDS[k] = makeInterfaceId.ERC165(INTERFACES[k]);
  32. for (const fnName of INTERFACES[k]) {
  33. // the interface id of a single function is equivalent to its function signature
  34. FN_SIGNATURES[fnName] = makeInterfaceId.ERC165([fnName]);
  35. }
  36. }
  37. function shouldSupportInterfaces (interfaces = []) {
  38. describe('Contract interface', function () {
  39. beforeEach(function () {
  40. this.contractUnderTest = this.mock || this.token;
  41. });
  42. for (const k of interfaces) {
  43. const interfaceId = INTERFACE_IDS[k];
  44. describe(k, function () {
  45. describe('ERC165\'s supportsInterface(bytes4)', function () {
  46. it('should use less than 30k gas', async function () {
  47. (await this.contractUnderTest.supportsInterface.estimateGas(interfaceId)).should.be.lte(30000);
  48. });
  49. it('should claim support', async function () {
  50. (await this.contractUnderTest.supportsInterface(interfaceId)).should.equal(true);
  51. });
  52. });
  53. for (const fnName of INTERFACES[k]) {
  54. const fnSig = FN_SIGNATURES[fnName];
  55. describe(fnName, function () {
  56. it('should be implemented', function () {
  57. this.contractUnderTest.abi.filter(fn => fn.signature === fnSig).length.should.equal(1);
  58. });
  59. });
  60. }
  61. });
  62. }
  63. });
  64. }
  65. module.exports = {
  66. shouldSupportInterfaces,
  67. };