diff --git a/CHANGELOG.md b/CHANGELOG.md index e3394576a22..ae7826d50e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased * `ERC2981`: make `royaltiInfo` public to allow super call in overrides. ([#3305](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3305)) + * `TimelockController`: Migrate `_call` to `_execute` and allow inheritance and overriding similar to `Governor`. ([#3317](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3317)) ## Unreleased diff --git a/contracts/governance/TimelockController.sol b/contracts/governance/TimelockController.sol index 376023fe35b..cef21d6cd18 100644 --- a/contracts/governance/TimelockController.sol +++ b/contracts/governance/TimelockController.sol @@ -6,6 +6,7 @@ pragma solidity ^0.8.0; import "../access/AccessControl.sol"; import "../token/ERC721/IERC721Receiver.sol"; import "../token/ERC1155/IERC1155Receiver.sol"; +import "../utils/Address.sol"; /** * @dev Contract module which acts as a timelocked controller. When set as the @@ -288,13 +289,15 @@ contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver function execute( address target, uint256 value, - bytes calldata data, + bytes calldata payload, bytes32 predecessor, bytes32 salt ) public payable virtual onlyRoleOrOpenRole(EXECUTOR_ROLE) { - bytes32 id = hashOperation(target, value, data, predecessor, salt); + bytes32 id = hashOperation(target, value, payload, predecessor, salt); + _beforeCall(id, predecessor); - _call(id, 0, target, value, data); + _execute(target, value, payload); + emit CallExecuted(id, 0, target, value, payload); _afterCall(id); } @@ -318,13 +321,30 @@ contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver require(targets.length == payloads.length, "TimelockController: length mismatch"); bytes32 id = hashOperationBatch(targets, values, payloads, predecessor, salt); + _beforeCall(id, predecessor); for (uint256 i = 0; i < targets.length; ++i) { - _call(id, i, targets[i], values[i], payloads[i]); + address target = targets[i]; + uint256 value = values[i]; + bytes calldata payload = payloads[i]; + _execute(target, value, payload); + emit CallExecuted(id, i, target, value, payload); } _afterCall(id); } + /** + * @dev Execute an operation's call. + */ + function _execute( + address target, + uint256 value, + bytes calldata data + ) internal virtual { + (bool success, ) = target.call{value: value}(data); + require(success, "TimelockController: underlying transaction reverted"); + } + /** * @dev Checks before execution of an operation's calls. */ @@ -341,24 +361,6 @@ contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver _timestamps[id] = _DONE_TIMESTAMP; } - /** - * @dev Execute an operation's call. - * - * Emits a {CallExecuted} event. - */ - function _call( - bytes32 id, - uint256 index, - address target, - uint256 value, - bytes calldata data - ) private { - (bool success, ) = target.call{value: value}(data); - require(success, "TimelockController: underlying transaction reverted"); - - emit CallExecuted(id, index, target, value, data); - } - /** * @dev Changes the minimum timelock duration for future operations. *