Browse Source

Create ProposalSalt event for TimelockController (#4001)

Co-authored-by: Francisco <frangio.1@gmail.com>
JulissaDantes 2 years ago
parent
commit
bc6de21fe2

+ 5 - 0
.changeset/five-poets-mix.md

@@ -0,0 +1,5 @@
+---
+'openzeppelin-solidity': patch
+---
+
+`TimelockController`: Add the `CallSalt` event to emit on operation schedule.

+ 13 - 2
contracts/governance/TimelockController.sol

@@ -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.
      */
@@ -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:
      *
@@ -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:
      *
@@ -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);
+        }
     }
 
     /**

+ 23 - 0
test/governance/TimelockController.test.js

@@ -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(
@@ -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 () {
@@ -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);

+ 3 - 0
test/governance/extensions/GovernorTimelockControl.test.js

@@ -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 });