From c42f573d4d518bd7c78afbe9d2d8547d2418ce26 Mon Sep 17 00:00:00 2001 From: ashhanai Date: Tue, 12 Apr 2022 17:48:02 +0200 Subject: [PATCH 1/6] Enable using ERC165 check for one supported interface directly --- contracts/utils/introspection/ERC165Checker.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/utils/introspection/ERC165Checker.sol b/contracts/utils/introspection/ERC165Checker.sol index 6a240e15531..34050091a45 100644 --- a/contracts/utils/introspection/ERC165Checker.sol +++ b/contracts/utils/introspection/ERC165Checker.sol @@ -104,7 +104,7 @@ library ERC165Checker { * with {supportsERC165}. * Interface identification is specified in ERC-165. */ - function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) { + function _supportsERC165Interface(address account, bytes4 interfaceId) internal view returns (bool) { bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId); (bool success, bytes memory result) = account.staticcall{gas: 30000}(encodedParams); if (result.length < 32) return false; From f70a9dd466a6a3bec6ad2b08cf8a6abde0daa2d9 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 24 Jun 2022 10:09:25 +0200 Subject: [PATCH 2/6] rename _supportsERC165Interface to supportsERC165InterfaceRaw --- contracts/utils/introspection/ERC165Checker.sol | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/utils/introspection/ERC165Checker.sol b/contracts/utils/introspection/ERC165Checker.sol index 34050091a45..24179074544 100644 --- a/contracts/utils/introspection/ERC165Checker.sol +++ b/contracts/utils/introspection/ERC165Checker.sol @@ -23,8 +23,8 @@ library ERC165Checker { // Any contract that implements ERC165 must explicitly indicate support of // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid return - _supportsERC165Interface(account, type(IERC165).interfaceId) && - !_supportsERC165Interface(account, _INTERFACE_ID_INVALID); + supportsERC165InterfaceRaw(account, type(IERC165).interfaceId) && + !supportsERC165InterfaceRaw(account, _INTERFACE_ID_INVALID); } /** @@ -35,7 +35,7 @@ library ERC165Checker { */ 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) && _supportsERC165Interface(account, interfaceId); + return supportsERC165(account) && supportsERC165InterfaceRaw(account, interfaceId); } /** @@ -60,7 +60,7 @@ library ERC165Checker { if (supportsERC165(account)) { // query support of each interface in interfaceIds for (uint256 i = 0; i < interfaceIds.length; i++) { - interfaceIdsSupported[i] = _supportsERC165Interface(account, interfaceIds[i]); + interfaceIdsSupported[i] = supportsERC165InterfaceRaw(account, interfaceIds[i]); } } @@ -84,7 +84,7 @@ library ERC165Checker { // query support of each interface in _interfaceIds for (uint256 i = 0; i < interfaceIds.length; i++) { - if (!_supportsERC165Interface(account, interfaceIds[i])) { + if (!supportsERC165InterfaceRaw(account, interfaceIds[i])) { return false; } } @@ -104,7 +104,7 @@ library ERC165Checker { * with {supportsERC165}. * Interface identification is specified in ERC-165. */ - function _supportsERC165Interface(address account, bytes4 interfaceId) internal view returns (bool) { + function supportsERC165InterfaceRaw(address account, bytes4 interfaceId) internal view returns (bool) { bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId); (bool success, bytes memory result) = account.staticcall{gas: 30000}(encodedParams); if (result.length < 32) return false; From 78416c3cddf58dc1d95944fbaba6a145d3fa60d2 Mon Sep 17 00:00:00 2001 From: ashhanai Date: Mon, 27 Jun 2022 19:27:42 +0200 Subject: [PATCH 3/6] Rename supportsERC165InterfaceRaw to supportsERC165InterfaceUnchecked --- contracts/utils/introspection/ERC165Checker.sol | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/utils/introspection/ERC165Checker.sol b/contracts/utils/introspection/ERC165Checker.sol index 24179074544..c936d3f31ae 100644 --- a/contracts/utils/introspection/ERC165Checker.sol +++ b/contracts/utils/introspection/ERC165Checker.sol @@ -23,8 +23,8 @@ library ERC165Checker { // Any contract that implements ERC165 must explicitly indicate support of // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid return - supportsERC165InterfaceRaw(account, type(IERC165).interfaceId) && - !supportsERC165InterfaceRaw(account, _INTERFACE_ID_INVALID); + supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) && + !supportsERC165InterfaceUnchecked(account, _INTERFACE_ID_INVALID); } /** @@ -35,7 +35,7 @@ library ERC165Checker { */ 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) && supportsERC165InterfaceRaw(account, interfaceId); + return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId); } /** @@ -60,7 +60,7 @@ library ERC165Checker { if (supportsERC165(account)) { // query support of each interface in interfaceIds for (uint256 i = 0; i < interfaceIds.length; i++) { - interfaceIdsSupported[i] = supportsERC165InterfaceRaw(account, interfaceIds[i]); + interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]); } } @@ -84,7 +84,7 @@ library ERC165Checker { // query support of each interface in _interfaceIds for (uint256 i = 0; i < interfaceIds.length; i++) { - if (!supportsERC165InterfaceRaw(account, interfaceIds[i])) { + if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) { return false; } } @@ -104,7 +104,7 @@ library ERC165Checker { * with {supportsERC165}. * Interface identification is specified in ERC-165. */ - function supportsERC165InterfaceRaw(address account, bytes4 interfaceId) internal view returns (bool) { + function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) { bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId); (bool success, bytes memory result) = account.staticcall{gas: 30000}(encodedParams); if (result.length < 32) return false; From e5d327dad4d475eb9da0ba7cdd65c2d0c46b3854 Mon Sep 17 00:00:00 2001 From: ashhanai Date: Mon, 27 Jun 2022 19:33:27 +0200 Subject: [PATCH 4/6] Update changed with ERC165Checker changes --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ee50f71f81..9cbaab67fbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ * `PaymentSplitter`: add `releasable` getters. ([#3350](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3350)) * `Initializable`: refactored implementation of modifiers for easier understanding. ([#3450](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3450)) * `Proxies`: remove runtime check of ERC1967 storage slots. ([#3455](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3455)) + * `ERC165Checker`: rename `_supportsERC165Interface` to `supportsERC165InterfaceUnchecked` and change its visibility to `internal`. ([#3339](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3339)) ### Breaking changes From bef68329d79ccf0a75c77d9a1fcc5ee98ab5a9d0 Mon Sep 17 00:00:00 2001 From: ashhanai Date: Mon, 27 Jun 2022 19:46:34 +0200 Subject: [PATCH 5/6] Update ERC165Checker tests --- contracts/mocks/ERC165CheckerMock.sol | 4 +++ .../utils/introspection/ERC165Checker.test.js | 32 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/contracts/mocks/ERC165CheckerMock.sol b/contracts/mocks/ERC165CheckerMock.sol index bda5cfc78c2..9ff7e7df6cf 100644 --- a/contracts/mocks/ERC165CheckerMock.sol +++ b/contracts/mocks/ERC165CheckerMock.sol @@ -22,4 +22,8 @@ contract ERC165CheckerMock { function getSupportedInterfaces(address account, bytes4[] memory interfaceIds) public view returns (bool[] memory) { return account.getSupportedInterfaces(interfaceIds); } + + function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) public view returns (bool) { + return account.supportsERC165InterfaceUnchecked(interfaceId); + } } diff --git a/test/utils/introspection/ERC165Checker.test.js b/test/utils/introspection/ERC165Checker.test.js index c3a6cdc66e4..c325adb7e0f 100644 --- a/test/utils/introspection/ERC165Checker.test.js +++ b/test/utils/introspection/ERC165Checker.test.js @@ -44,6 +44,11 @@ contract('ERC165Checker', function (accounts) { expect(supported.length).to.equal(1); expect(supported[0]).to.equal(false); }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); }); context('ERC165 not supported', function () { @@ -71,6 +76,11 @@ contract('ERC165Checker', function (accounts) { expect(supported.length).to.equal(1); expect(supported[0]).to.equal(false); }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); }); context('ERC165 supported', function () { @@ -98,6 +108,11 @@ contract('ERC165Checker', function (accounts) { expect(supported.length).to.equal(1); expect(supported[0]).to.equal(false); }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); }); context('ERC165 and single interface supported', function () { @@ -125,6 +140,11 @@ contract('ERC165Checker', function (accounts) { expect(supported.length).to.equal(1); expect(supported[0]).to.equal(true); }); + + it('supports mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(true); + }); }); context('ERC165 and many interfaces supported', function () { @@ -191,6 +211,13 @@ contract('ERC165Checker', function (accounts) { expect(supported[2]).to.equal(true); expect(supported[3]).to.equal(false); }); + + it('supports each interfaceId via supportsERC165InterfaceUnchecked', async function () { + for (const interfaceId of this.supportedInterfaces) { + const supported = await this.mock.supportsERC165InterfaceUnchecked(this.target.address, interfaceId); + expect(supported).to.equal(true); + }; + }); }); context('account address does not support ERC165', function () { @@ -214,5 +241,10 @@ contract('ERC165Checker', function (accounts) { expect(supported.length).to.equal(1); expect(supported[0]).to.equal(false); }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.supportsERC165InterfaceUnchecked(DUMMY_ACCOUNT, DUMMY_ID); + expect(supported).to.equal(false); + }); }); }); From 28b3e54575d79aa2959a24325ceb28aa887be607 Mon Sep 17 00:00:00 2001 From: Francisco Date: Mon, 27 Jun 2022 17:00:41 -0300 Subject: [PATCH 6/6] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cbaab67fbb..23fee4b218b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,7 @@ * `PaymentSplitter`: add `releasable` getters. ([#3350](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3350)) * `Initializable`: refactored implementation of modifiers for easier understanding. ([#3450](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3450)) * `Proxies`: remove runtime check of ERC1967 storage slots. ([#3455](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3455)) - * `ERC165Checker`: rename `_supportsERC165Interface` to `supportsERC165InterfaceUnchecked` and change its visibility to `internal`. ([#3339](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3339)) + * `ERC165Checker`: add `supportsERC165InterfaceUnchecked` for consulting individual interfaces without the full ERC165 protocol. ([#3339](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3339)) ### Breaking changes