Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create ProposalSalt event for TimelockController #4001

Merged
merged 11 commits into from
Jan 27, 2023
5 changes: 5 additions & 0 deletions .changeset/five-poets-mix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openzeppelin-solidity': patch
---

`TimelockController`: Add the `CallSalt` event to emit on operation schedule.
15 changes: 13 additions & 2 deletions contracts/governance/TimelockController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver
*/
event CallExecuted(bytes32 indexed id, uint256 indexed index, address target, uint256 value, bytes data);

/**
* @dev Emitted when new proposal is scheduled with non-zero salt.
*/
event CallSalt(bytes32 indexed id, bytes32 salt);

/**
* @dev Emitted when operation `id` is cancelled.
*/
Expand Down Expand Up @@ -206,7 +211,7 @@ contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver
/**
* @dev Schedule an operation containing a single transaction.
*
* Emits a {CallScheduled} event.
* Emits events {CallScheduled} and {CallSalt}.
*
* Requirements:
*
Expand All @@ -223,12 +228,15 @@ contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver
bytes32 id = hashOperation(target, value, data, predecessor, salt);
_schedule(id, delay);
emit CallScheduled(id, 0, target, value, data, predecessor, delay);
if (salt != bytes32(0)) {
emit CallSalt(id, salt);
}
}

/**
* @dev Schedule an operation containing a batch of transactions.
*
* Emits one {CallScheduled} event per transaction in the batch.
* Emits a {CallSalt} event and one {CallScheduled} event per transaction in the batch.
*
* Requirements:
*
Expand All @@ -250,6 +258,9 @@ contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver
for (uint256 i = 0; i < targets.length; ++i) {
emit CallScheduled(id, i, targets[i], values[i], payloads[i], predecessor, delay);
}
if (salt != bytes32(0)) {
emit CallSalt(id, salt);
}
}

/**
Expand Down
23 changes: 23 additions & 0 deletions test/governance/TimelockController.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,11 @@ contract('TimelockController', function (accounts) {
delay: MINDELAY,
});

expectEvent(receipt, 'CallSalt', {
id: this.operation.id,
salt: this.operation.salt,
});

const block = await web3.eth.getBlock(receipt.receipt.blockHash);

expect(await this.mock.getTimestamp(this.operation.id)).to.be.bignumber.equal(
Expand Down Expand Up @@ -219,6 +224,19 @@ contract('TimelockController', function (accounts) {
'TimelockController: insufficient delay',
);
});

it('schedule operation with salt zero', async function () {
const { receipt } = await this.mock.schedule(
this.operation.target,
this.operation.value,
this.operation.data,
this.operation.predecessor,
ZERO_BYTES32,
MINDELAY,
{ from: proposer },
);
expectEvent.notEmitted(receipt, 'CallSalt');
});
});

describe('execute', function () {
Expand Down Expand Up @@ -364,6 +382,11 @@ contract('TimelockController', function (accounts) {
predecessor: this.operation.predecessor,
delay: MINDELAY,
});

expectEvent(receipt, 'CallSalt', {
id: this.operation.id,
salt: this.operation.salt,
});
}

const block = await web3.eth.getBlock(receipt.receipt.blockHash);
Expand Down
3 changes: 3 additions & 0 deletions test/governance/extensions/GovernorTimelockControl.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ contract('GovernorTimelockControl', function (accounts) {

expectEvent(txQueue, 'ProposalQueued', { proposalId: this.proposal.id });
await expectEvent.inTransaction(txQueue.tx, this.timelock, 'CallScheduled', { id: this.proposal.timelockid });
await expectEvent.inTransaction(txQueue.tx, this.timelock, 'CallSalt', {
id: this.proposal.timelockid,
});

expectEvent(txExecute, 'ProposalExecuted', { proposalId: this.proposal.id });
await expectEvent.inTransaction(txExecute.tx, this.timelock, 'CallExecuted', { id: this.proposal.timelockid });
Expand Down