@@ -10,7 +10,7 @@ import "@openzeppelin/utils/math/SafeCast.sol";
10
10
import "@openzeppelin/utils/Address.sol " ;
11
11
import "@openzeppelin/utils/Context.sol " ;
12
12
import "./IGovernor.sol " ;
13
- import "./extensions/ GovernorMerkleVotes.sol " ;
13
+ import "./GovernorMerkleVotes.sol " ;
14
14
15
15
/**
16
16
* @dev Core of the governance system, designed to be extended though various modules.
@@ -29,14 +29,8 @@ abstract contract Governor is Context, ERC165, EIP712, GovernorMerkleVotes, IGov
29
29
bytes32 public constant BALLOT_TYPEHASH = keccak256 ("Ballot(uint256 proposalId,uint8 support) " );
30
30
uint64 public constant AMOUNT_FOR_SUMBITTER_PROOF = 10000000000000000000 ;
31
31
mapping (address => uint256 ) public addressTotalVotes;
32
- mapping (address => bool ) private _addressTotalVotesVerified;
33
- mapping (address => bool ) private _addressSubmitterVerified;
34
-
35
- struct ProposalCore {
36
- address author;
37
- string description;
38
- bool exists;
39
- }
32
+ mapping (address => bool ) public addressTotalVotesVerified;
33
+ mapping (address => bool ) public addressSubmitterVerified;
40
34
41
35
uint256 [] private _proposalIds;
42
36
mapping (uint256 => uint256 ) private _deletedProposalIds;
@@ -46,6 +40,9 @@ abstract contract Governor is Context, ERC165, EIP712, GovernorMerkleVotes, IGov
46
40
mapping (uint256 => ProposalCore) private _proposals;
47
41
mapping (address => uint256 ) private _numSubmissions;
48
42
43
+ /// @notice Thrown if there is metadata included in a proposal that isn't covered in data validation
44
+ error TooManyMetadatas ();
45
+
49
46
/**
50
47
* @dev Restrict access of functions to the governance executor, which may be the Governor itself or a timelock
51
48
* contract, as specified by {_executor}. This generally means that function with this modifier must be voted on and
@@ -116,8 +113,8 @@ abstract contract Governor is Context, ERC165, EIP712, GovernorMerkleVotes, IGov
116
113
* accross multiple networks. This also means that in order to execute the same operation twice (on the same
117
114
* governor) the proposer will have to change the description in order to avoid proposal id conflicts.
118
115
*/
119
- function hashProposal (string memory proposalDescription ) public pure virtual override returns (uint256 ) {
120
- return uint256 (keccak256 (abi.encode (proposalDescription )));
116
+ function hashProposal (ProposalCore memory proposal ) public pure virtual override returns (uint256 ) {
117
+ return uint256 (keccak256 (abi.encode (proposal )));
121
118
}
122
119
123
120
/**
@@ -225,56 +222,78 @@ abstract contract Governor is Context, ERC165, EIP712, GovernorMerkleVotes, IGov
225
222
* @dev See {IGovernor-verifySubmitter}.
226
223
*/
227
224
function verifySubmitter (address account , bytes32 [] calldata proof ) public override returns (bool verified ) {
228
- if (! _addressSubmitterVerified [account]) {
225
+ if (! addressSubmitterVerified [account]) {
229
226
checkProof (account, AMOUNT_FOR_SUMBITTER_PROOF, proof, false ); // will revert with NotInMerkle if not valid
230
- _addressSubmitterVerified [account] = true ;
227
+ addressSubmitterVerified [account] = true ;
231
228
}
232
229
return true ;
233
230
}
234
231
235
232
/**
236
- * @dev See {IGovernor-verifyTotalVotes }.
233
+ * @dev See {IGovernor-validateProposalData }.
237
234
*/
238
- function verifyTotalVotes (address account , uint256 totalVotes , bytes32 [] calldata proof )
239
- public
240
- override
241
- returns (bool verified )
242
- {
243
- if (! _addressTotalVotesVerified[account]) {
244
- checkProof (account, totalVotes, proof, false ); // will revert with NotInMerkle if not valid
245
- addressTotalVotes[account] = totalVotes;
246
- _addressTotalVotesVerified[account] = true ;
235
+ function validateProposalData (ProposalCore memory proposal ) public virtual override returns (bool dataValidated ) {
236
+ for (uint256 index = 0 ; index < METADATAS_COUNT; index++ ) {
237
+ Metadatas currentMetadata = Metadatas (index);
238
+ if (currentMetadata == Metadatas.Target) {
239
+ continue ; // Nothing to check here since strictly typed to address
240
+ } else if (currentMetadata == Metadatas.Safe) {
241
+ require (
242
+ proposal.safeMetadata.signers.length != 0 ,
243
+ "GovernorMetadataValidation: there cannot be zero signers in safeMetadata "
244
+ );
245
+ require (
246
+ proposal.safeMetadata.threshold != 0 ,
247
+ "GovernorMetadataValidation: threshold cannot be zero in safeMetadata "
248
+ );
249
+ require (proposal.safeMetadata.signers.length != 0 );
250
+ } else {
251
+ revert TooManyMetadatas ();
252
+ }
247
253
}
254
+ require (bytes (proposal.description).length != 0 , "Governor: empty proposal " );
248
255
return true ;
249
256
}
250
257
251
258
/**
252
259
* @dev See {IGovernor-propose}.
253
260
*/
254
- function propose (string memory proposalDescription , bytes32 [] calldata proof )
261
+ function propose (ProposalCore memory proposal , bytes32 [] calldata proof )
255
262
public
256
263
virtual
257
264
override
258
265
returns (uint256 )
259
266
{
267
+ require (verifySubmitter (msg .sender , proof), "Governor: address is not permissioned to submit " );
268
+ validateProposalData (proposal);
269
+ return _castProposal (proposal);
270
+ }
271
+
272
+ /**
273
+ * @dev See {IGovernor-proposeWithoutProof}.
274
+ */
275
+ function proposeWithoutProof (ProposalCore memory proposal ) public virtual override returns (uint256 ) {
276
+ require (addressSubmitterVerified[msg .sender ], "Governor: address is not permissioned to submit " );
277
+ validateProposalData (proposal);
278
+ return _castProposal (proposal);
279
+ }
280
+
281
+ function _castProposal (ProposalCore memory proposal ) internal virtual returns (uint256 ) {
260
282
require (state () == ContestState.Queued, "Governor: contest must be queued for proposals to be submitted " );
261
283
require (
262
284
_numSubmissions[msg .sender ] < numAllowedProposalSubmissions (),
263
285
"Governor: the same cannot submit more than the numAllowedProposalSubmissions for this contest "
264
286
);
265
287
require (_proposalIds.length < maxProposalCount (), "Governor: the max number of proposals have been submitted " );
266
- require (verifySubmitter (msg .sender , proof), "Governor: address is not permissioned to submit " );
267
-
268
- require (bytes (proposalDescription).length != 0 , "Governor: empty proposal " );
269
288
270
- uint256 proposalId = hashProposal (proposalDescription );
289
+ uint256 proposalId = hashProposal (proposal );
271
290
require (! _proposals[proposalId].exists, "Governor: duplicate proposals not allowed " );
272
291
273
292
_proposalIds.push (proposalId);
274
- _proposals[proposalId] = ProposalCore ({author: msg . sender , description: proposalDescription, exists: true }) ;
293
+ _proposals[proposalId] = proposal ;
275
294
_numSubmissions[msg .sender ] += 1 ;
276
295
277
- emit ProposalCreated (proposalId, proposalDescription, _msgSender ());
296
+ emit ProposalCreated (proposalId, _msgSender ());
278
297
279
298
return proposalId;
280
299
}
@@ -318,6 +337,22 @@ abstract contract Governor is Context, ERC165, EIP712, GovernorMerkleVotes, IGov
318
337
emit ContestCanceled ();
319
338
}
320
339
340
+ /**
341
+ * @dev See {IGovernor-verifyTotalVotes}.
342
+ */
343
+ function verifyTotalVotes (address account , uint256 totalVotes , bytes32 [] calldata proof )
344
+ public
345
+ override
346
+ returns (bool verified )
347
+ {
348
+ if (! addressTotalVotesVerified[account]) {
349
+ checkProof (account, totalVotes, proof, false ); // will revert with NotInMerkle if not valid
350
+ addressTotalVotes[account] = totalVotes;
351
+ addressTotalVotesVerified[account] = true ;
352
+ }
353
+ return true ;
354
+ }
355
+
321
356
/**
322
357
* @dev See {IGovernor-castVote}.
323
358
*/
@@ -343,7 +378,7 @@ abstract contract Governor is Context, ERC165, EIP712, GovernorMerkleVotes, IGov
343
378
{
344
379
address voter = _msgSender ();
345
380
require (
346
- _addressTotalVotesVerified [voter],
381
+ addressTotalVotesVerified [voter],
347
382
"Governor: you need to cast a vote with the proof at least once and you haven't yet "
348
383
);
349
384
return _castVote (proposalId, voter, support, numVotes, "" );
@@ -364,7 +399,7 @@ abstract contract Governor is Context, ERC165, EIP712, GovernorMerkleVotes, IGov
364
399
require (numVotes > 0 , "Governor: cannot vote with 0 or fewer votes " );
365
400
366
401
require (
367
- _addressTotalVotesVerified [account],
402
+ addressTotalVotesVerified [account],
368
403
"Governor: you need to verify your number of votes against the merkle root first "
369
404
);
370
405
_countVote (proposalId, account, support, numVotes, addressTotalVotes[account]);
0 commit comments