-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
CCIP-4659 New Modified ERC165Checker library (#15743)
* New Modified ERC165Checker library * [Bot] Update changeset file with jira issues * fix gas snapshot * Update gethwrappers * fill in coverage gaps * so many snapshots i might as well open a photography studio * formatting * change name for specificity and update tests, and change gas check to assembl * Update gethwrappers * fix snapshot issues from duplicate tests * remove unnec. functions and better format library to conform to CL style guide. * Update gethwrappers * Optimize library with better boolean logic. * formatting * Update gethwrappers * fix compiler version, snapshot, and wrappers broke in merge conflict resolution --------- Co-authored-by: app-token-issuer-infra-releng[bot] <120227048+app-token-issuer-infra-releng[bot]@users.noreply.github.com>
- Loading branch information
1 parent
7743429
commit 4a19318
Showing
7 changed files
with
179 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
--- | ||
'@chainlink/contracts': patch | ||
--- | ||
|
||
Create a new version of the ERC165Checker library which checks for sufficient gas before making an external call to prevent message delivery issues. #bugfix | ||
|
||
|
||
PR issue: CCIP-4659 | ||
|
||
Solidity Review issue: CCIP-3966 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
65 changes: 65 additions & 0 deletions
65
contracts/src/v0.8/ccip/libraries/ERC165CheckerReverting.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol"; | ||
|
||
/// @notice Library used to query support of an interface declared via {IERC165}. | ||
/// @dev These functions return the actual result of the query: they do not `revert` if an interface is not supported. | ||
library ERC165CheckerReverting { | ||
error InsufficientGasForStaticCall(); | ||
|
||
// As per the EIP-165 spec, no interface should ever match 0xffffffff. | ||
bytes4 private constant INTERFACE_ID_INVALID = 0xffffffff; | ||
|
||
/// @dev 30k gas is required to make the staticcall. Under the 63/64 rule this means that 30,477 gas must be available | ||
/// to ensure that at least 30k is forwarded. Checking for at least 31,000 ensures that after additional | ||
/// operations are performed there is still >= 30,477 gas remaining. | ||
/// 30,000 = ((30,477 * 63) / 64) | ||
uint256 private constant MINIMUM_GAS_REQUIREMENT = 31_000; | ||
|
||
/// @notice Returns true if `account` supports a defined interface. | ||
/// @dev The function must support both the interfaceId and interfaces specified by ERC165 generally as per the standard. | ||
/// @param account the contract to be queried for support. | ||
/// @param interfaceId the interface being checked for support. | ||
/// @return true if the contract at account indicates support of the interface with, false otherwise. | ||
function _supportsInterfaceReverting(address account, bytes4 interfaceId) internal view returns (bool) { | ||
// As a gas optimization, short circuit return false if interfaceId is not supported, as it is most likely interfaceId | ||
// to be unsupported by the target. | ||
return _supportsERC165InterfaceUncheckedReverting(account, interfaceId) | ||
&& !_supportsERC165InterfaceUncheckedReverting(account, INTERFACE_ID_INVALID) | ||
&& _supportsERC165InterfaceUncheckedReverting(account, type(IERC165).interfaceId); | ||
} | ||
|
||
/// @notice Query if a contract implements an interface, does not check ERC165 support | ||
/// @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 true if the contract at account indicates support of the interface with | ||
/// identifier interfaceId, false otherwise | ||
/// @dev Assumes that account contains a contract that supports ERC165, otherwise | ||
/// the behavior of this method is undefined. This precondition can be checked. | ||
/// @dev Function will only revert if the minimum gas requirement is not met before the staticcall is performed. | ||
function _supportsERC165InterfaceUncheckedReverting(address account, bytes4 interfaceId) internal view returns (bool) { | ||
bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId); | ||
|
||
bool success; | ||
uint256 returnSize; | ||
uint256 returnValue; | ||
|
||
bytes4 notEnoughGasSelector = InsufficientGasForStaticCall.selector; | ||
|
||
assembly { | ||
// The EVM does not return a specific error code if a revert is due to OOG. This check ensures that | ||
// the message will not throw an OOG error by requiring that the amount of gas for the following | ||
// staticcall exists before invoking it. | ||
if lt(gas(), MINIMUM_GAS_REQUIREMENT) { | ||
mstore(0x0, notEnoughGasSelector) | ||
revert(0x0, 0x4) | ||
} | ||
|
||
success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20) | ||
returnSize := returndatasize() | ||
returnValue := mload(0x00) | ||
} | ||
return success && returnSize >= 0x20 && returnValue > 0; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 44 additions & 0 deletions
44
...acts/src/v0.8/ccip/test/libraries/ERC165CheckerReverting.supportsInterfaceReverting.t.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
pragma solidity ^0.8.24; | ||
|
||
import {IAny2EVMMessageReceiver} from "../../interfaces/IAny2EVMMessageReceiver.sol"; | ||
|
||
import {ERC165CheckerReverting} from "../../libraries/ERC165CheckerReverting.sol"; | ||
import {MaybeRevertMessageReceiver} from "../helpers/receivers/MaybeRevertMessageReceiver.sol"; | ||
|
||
import {Test} from "forge-std/Test.sol"; | ||
|
||
contract ERC165CheckerReverting_supportsInterfaceReverting is Test { | ||
using ERC165CheckerReverting for address; | ||
|
||
address internal s_receiver; | ||
|
||
bytes4 internal constant EXAMPLE_INTERFACE_ID = 0xdeadbeef; | ||
|
||
error InsufficientGasForStaticCall(); | ||
|
||
constructor() { | ||
s_receiver = address(new MaybeRevertMessageReceiver(false)); | ||
} | ||
|
||
function test__supportsInterfaceReverting() public view { | ||
assertTrue(s_receiver._supportsInterfaceReverting(type(IAny2EVMMessageReceiver).interfaceId)); | ||
} | ||
|
||
// Reverts | ||
|
||
function test__supportsInterfaceReverting_RevertWhen_NotEnoughGasForSupportsInterface() public { | ||
vm.expectRevert(InsufficientGasForStaticCall.selector); | ||
|
||
// Library calls cannot be called with gas limit overrides, so a public function must be exposed | ||
// instead which can proxy the call to the library. | ||
|
||
// The gas limit was chosen so that after overhead, <31k would remain to trigger the error. | ||
this.invokeERC165Checker{gas: 33_000}(); | ||
} | ||
|
||
// Meant to test the call with a manual gas limit override | ||
function invokeERC165Checker() external view { | ||
s_receiver._supportsInterfaceReverting(EXAMPLE_INTERFACE_ID); | ||
} | ||
} |
Large diffs are not rendered by default.
Oops, something went wrong.
Oops, something went wrong.