Enable using ERC165 check for one supported interface directly (#3339)
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com> Co-authored-by: Francisco <frangio.1@gmail.com>
This commit is contained in:
@ -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`: add `supportsERC165InterfaceUnchecked` for consulting individual interfaces without the full ERC165 protocol. ([#3339](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3339))
|
||||
* `Address`: optimize `functionCall` functions by checking contract size only if there is no returned data. ([#3469](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3469))
|
||||
|
||||
### Breaking changes
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
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) && _supportsERC165Interface(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] = _supportsERC165Interface(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 (!_supportsERC165Interface(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 _supportsERC165Interface(address account, bytes4 interfaceId) private 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;
|
||||
|
||||
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user