Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/hot-plums-approve.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openzeppelin-solidity': minor
---

`GovernorTimelockControl`: Clean up timelock id on execution for gas refund.
16 changes: 13 additions & 3 deletions contracts/governance/extensions/GovernorTimelockControl.sol
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ abstract contract GovernorTimelockControl is IGovernorTimelock, Governor {
return ProposalState.Executed;
} else if (_timelock.isOperationPending(queueid)) {
return ProposalState.Queued;
} else if (_timelock.isOperationDone(queueid)) {
// This can happen if the proposal is executed directly on the timelock.
return ProposalState.Executed;
} else {
// This can happen if the proposal is canceled directly on the timelock.
return ProposalState.Canceled;
}
}
Expand Down Expand Up @@ -117,12 +121,15 @@ abstract contract GovernorTimelockControl is IGovernorTimelock, Governor {
* @dev Overridden execute function that run the already queued proposal through the timelock.
*/
function _execute(
uint256 /* proposalId */,
uint256 proposalId,
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) internal virtual override {
// cleanup for refund
delete _timelockIds[proposalId];
// execute
_timelock.executeBatch{value: msg.value}(targets, values, calldatas, 0, descriptionHash);
}

Expand All @@ -140,10 +147,13 @@ abstract contract GovernorTimelockControl is IGovernorTimelock, Governor {
bytes32 descriptionHash
) internal virtual override returns (uint256) {
uint256 proposalId = super._cancel(targets, values, calldatas, descriptionHash);
bytes32 timelockId = _timelockIds[proposalId];

if (_timelockIds[proposalId] != 0) {
_timelock.cancel(_timelockIds[proposalId]);
if (timelockId != 0) {
// cleanup
delete _timelockIds[proposalId];
// cancel
_timelock.cancel(timelockId);
}

return proposalId;
Expand Down