Adopt new Solidity features interfaceId, try/catch, keccak constants (#2487)

* Clean code

-  using type().interfaceId to improve readeability of ERC165 registration
- hardcoding some keccak256 that are otherwise computed at construction.

* hardcode keccak256 result

* Improve code readeability using try/catch

* Remove hardcoded hash 

tests show that solc 0.8.0 does the optimization as expected

* Use try/catch to improve readability

* ERC165Checker: Do not revert when returndata is empty + new test

* Address PR comments

* improve testing of ERC721Receiver errors

* put back comment about invalid interface id

* coverage does not support 0.8.1. Reverting back to 0.8.0

* bubble all data with length > 0 if onERC721Receive fails.

* Fix test: revert without message trigger is bubble with the default message

* using enum object to improve readability
This commit is contained in:
Hadrien Croubois
2021-01-29 22:20:49 +01:00
committed by GitHub
parent 03832c130c
commit 60205944bb
12 changed files with 134 additions and 136 deletions

View File

@ -11,11 +11,6 @@ import "./IERC165.sol";
* their support of an interface.
*/
abstract contract ERC165 is IERC165 {
/*
* bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
*/
bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
/**
* @dev Mapping of interface ids to whether or not it's supported.
*/
@ -24,7 +19,7 @@ abstract contract ERC165 is IERC165 {
constructor () {
// Derived contracts need only register support for their own interfaces,
// we register support for ERC165 itself here
_registerInterface(_INTERFACE_ID_ERC165);
_registerInterface(type(IERC165).interfaceId);
}
/**

View File

@ -2,6 +2,8 @@
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Library used to query support of an interface declared via {IERC165}.
*
@ -13,18 +15,13 @@ library ERC165Checker {
// As per the EIP-165 spec, no interface should ever match 0xffffffff
bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;
/*
* bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
*/
bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
/**
* @dev Returns true if `account` supports the {IERC165} interface,
*/
function supportsERC165(address account) internal view returns (bool) {
// Any contract that implements ERC165 must explicitly indicate support of
// InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
return _supportsERC165Interface(account, _INTERFACE_ID_ERC165) &&
return _supportsERC165Interface(account, type(IERC165).interfaceId) &&
!_supportsERC165Interface(account, _INTERFACE_ID_INVALID);
}
@ -101,29 +98,9 @@ library ERC165Checker {
* Interface identification is specified in ERC-165.
*/
function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) {
// success determines whether the staticcall succeeded and result determines
// whether the contract at account indicates support of _interfaceId
(bool success, bool result) = _callERC165SupportsInterface(account, interfaceId);
return (success && result);
}
/**
* @notice Calls the function with selector 0x01ffc9a7 (ERC165) and suppresses throw
* @param account The address of the contract to query for support of an interface
* @param interfaceId The interface identifier, as specified in ERC-165
* @return success true if the STATICCALL succeeded, false otherwise
* @return result true if the STATICCALL succeeded and the contract at account
* indicates support of the interface with identifier interfaceId, false otherwise
*/
function _callERC165SupportsInterface(address account, bytes4 interfaceId)
private
view
returns (bool, bool)
{
bytes memory encodedParams = abi.encodeWithSelector(_INTERFACE_ID_ERC165, interfaceId);
bytes memory encodedParams = abi.encodeWithSelector(IERC165(account).supportsInterface.selector, interfaceId);
(bool success, bytes memory result) = account.staticcall{ gas: 30000 }(encodedParams);
if (result.length < 32) return (false, false);
return (success, abi.decode(result, (bool)));
if (result.length < 32) return false;
return success && abi.decode(result, (bool));
}
}

View File

@ -13,7 +13,7 @@ import "./IERC1820Implementer.sol";
* registration to be complete.
*/
contract ERC1820Implementer is IERC1820Implementer {
bytes32 constant private _ERC1820_ACCEPT_MAGIC = keccak256(abi.encodePacked("ERC1820_ACCEPT_MAGIC"));
bytes32 private constant _ERC1820_ACCEPT_MAGIC = keccak256("ERC1820_ACCEPT_MAGIC");
mapping(bytes32 => mapping(address => bool)) private _supportedInterfaces;