Skip to content

Commit a827be1

Browse files
committed
Fix ERC165
1 parent 3635d3c commit a827be1

7 files changed

Lines changed: 125 additions & 91 deletions

File tree

contracts/mocks/ERC165/ERC165MaliciousData.sol

Lines changed: 0 additions & 12 deletions
This file was deleted.

contracts/mocks/ERC165/ERC165MissingData.sol

Lines changed: 0 additions & 7 deletions
This file was deleted.

contracts/mocks/ERC165/ERC165NotSupported.sol

Lines changed: 0 additions & 5 deletions
This file was deleted.

contracts/mocks/ERC165/ERC165ReturnBomb.sol

Lines changed: 0 additions & 18 deletions
This file was deleted.

contracts/mocks/ERC165/ERC165InterfacesSupported.sol renamed to contracts/mocks/ERC165Mock.sol

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
pragma solidity ^0.8.20;
44

5-
import {IERC165} from "../../utils/introspection/IERC165.sol";
5+
import {IERC165} from "../utils/introspection/IERC165.sol";
66

77
/**
88
* https://eips.ethereum.org/EIPS/eip-214#specification
@@ -56,3 +56,40 @@ contract ERC165InterfacesSupported is SupportsInterfaceWithLookupMock {
5656
}
5757
}
5858
}
59+
60+
contract ERC165MaliciousData {
61+
function supportsInterface(bytes4) public pure returns (bool) {
62+
assembly {
63+
mstore(0, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
64+
return(0, 32)
65+
}
66+
}
67+
}
68+
69+
contract ERC165MissingData {
70+
function supportsInterface(bytes4 interfaceId) public view {} // missing return
71+
}
72+
73+
contract ERC165NotSupported {}
74+
75+
contract ERC165ReturnBombMock is IERC165 {
76+
function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
77+
if (interfaceId == type(IERC165).interfaceId) {
78+
assembly {
79+
mstore(0, 1)
80+
}
81+
}
82+
assembly {
83+
return(0, 101500)
84+
}
85+
}
86+
}
87+
88+
contract ERC165RevertInvalid is IERC165 {
89+
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
90+
if (interfaceId == 0xffffffff) {
91+
revert();
92+
}
93+
return interfaceId == type(IERC165).interfaceId; // 0x01ffc9a7
94+
}
95+
}

contracts/utils/introspection/ERC165Checker.sol

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ library ERC165Checker {
2222
function supportsERC165(address account) internal view returns (bool) {
2323
// Any contract that implements ERC-165 must explicitly indicate support of
2424
// InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
25-
return
26-
supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) &&
27-
!supportsERC165InterfaceUnchecked(account, INTERFACE_ID_INVALID);
25+
if (!supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId)) return false;
26+
(bool success, bool supported) = trySupportsInterface(account, INTERFACE_ID_INVALID);
27+
return success && !supported;
2828
}
2929

3030
/**
@@ -106,19 +106,32 @@ library ERC165Checker {
106106
* Interface identification is specified in ERC-165.
107107
*/
108108
function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {
109-
// prepare call
110-
bytes memory encodedParams = abi.encodeCall(IERC165.supportsInterface, (interfaceId));
109+
(bool success, bool supported) = trySupportsInterface(account, interfaceId);
110+
return success && supported;
111+
}
111112

112-
// perform static call
113-
bool success;
113+
/**
114+
* @dev Attempts to call `supportsInterface` on a contract and returns both the call
115+
* success status and the interface support result.
116+
*
117+
* This function performs a low-level static call to the contract's `supportsInterface`
118+
* function. It returns:
119+
*
120+
* * `success`: true if the call didn't revert, false if it did
121+
* * `supported`: true if the call succeeded AND returned data indicating the interface is supported
122+
*/
123+
function trySupportsInterface(
124+
address account,
125+
bytes4 interfaceId
126+
) internal view returns (bool success, bool supported) {
114127
uint256 returnSize;
115128
uint256 returnValue;
129+
bytes memory encodedParams = abi.encodeCall(IERC165.supportsInterface, (interfaceId));
116130
assembly ("memory-safe") {
117131
success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
118132
returnSize := returndatasize()
119133
returnValue := mload(0x00)
120134
}
121-
122-
return success && returnSize >= 0x20 && returnValue > 0;
135+
return (success, returnSize >= 0x20 && returnValue > 0);
123136
}
124137
}

0 commit comments

Comments
 (0)