-
Notifications
You must be signed in to change notification settings - Fork 12.4k
Fix ERC165Checker detection #5880
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
a827be1
ed19036
49ef98f
b3a2c82
e3c2544
75ae31b
0b37c2f
6093319
1950904
7416347
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| 'openzeppelin-solidity': minor | ||
| --- | ||
|
|
||
| `ERC165Checker`: Condition the `0xffffff` check in `supportsERC165` to return false if the underlying call reverts. | ||
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,9 +22,12 @@ library ERC165Checker { | |
| function supportsERC165(address account) internal view returns (bool) { | ||
| // Any contract that implements ERC-165 must explicitly indicate support of | ||
| // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid | ||
| return | ||
| supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) && | ||
| !supportsERC165InterfaceUnchecked(account, INTERFACE_ID_INVALID); | ||
| if (supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId)) { | ||
| (bool success, bool supported) = _trySupportsInterface(account, INTERFACE_ID_INVALID); | ||
| return success && !supported; | ||
| } else { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -106,19 +109,34 @@ library ERC165Checker { | |
| * Interface identification is specified in ERC-165. | ||
| */ | ||
| function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) { | ||
| // prepare call | ||
| bytes memory encodedParams = abi.encodeCall(IERC165.supportsInterface, (interfaceId)); | ||
| (bool success, bool supported) = _trySupportsInterface(account, interfaceId); | ||
| return success && supported; | ||
| } | ||
|
|
||
| /** | ||
| * @dev Attempts to call `supportsInterface` on a contract and returns both the call | ||
| * success status and the interface support result. | ||
| * | ||
| * This function performs a low-level static call to the contract's `supportsInterface` | ||
| * function. It returns: | ||
| * | ||
| * * `success`: true if the call didn't revert, false if it did | ||
| * * `supported`: true if the call succeeded AND returned data indicating the interface is supported | ||
| */ | ||
| function _trySupportsInterface( | ||
| address account, | ||
| bytes4 interfaceId | ||
| ) private view returns (bool success, bool supported) { | ||
| bytes4 selector = IERC165.supportsInterface.selector; | ||
|
|
||
| // perform static call | ||
| bool success; | ||
| uint256 returnSize; | ||
| uint256 returnValue; | ||
| assembly ("memory-safe") { | ||
| success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20) | ||
| returnSize := returndatasize() | ||
| returnValue := mload(0x00) | ||
| mstore(0x00, selector) | ||
| mstore(0x04, interfaceId) | ||
| success := staticcall(30000, account, 0x00, 0x24, 0x00, 0x20) | ||
| supported := and( | ||
| gt(returndatasize(), 0x1F), // we have at least 20 bytes of returndata | ||
| iszero(iszero(mload(0x00))) // the first 20 bytes of returndata are non-zero | ||
|
||
| ) | ||
| } | ||
|
|
||
| return success && returnSize >= 0x20 && returnValue > 0; | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.