Skip to content

Commit

Permalink
Add Governance Whitelist Users Feature (#149)
Browse files Browse the repository at this point in the history
Governance whitelist allows anyone on the whitelist to make a proposal without meeting the COMP threshold requirements.
  • Loading branch information
arr00 authored Nov 16, 2021
1 parent 6548ec3 commit 3bb6de7
Show file tree
Hide file tree
Showing 11 changed files with 832 additions and 14 deletions.
50 changes: 47 additions & 3 deletions contracts/Governance/GovernorBravoDelegate.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma experimental ABIEncoderV2;

import "./GovernorBravoInterfaces.sol";

contract GovernorBravoDelegate is GovernorBravoDelegateStorageV1, GovernorBravoEvents {
contract GovernorBravoDelegate is GovernorBravoDelegateStorageV2, GovernorBravoEvents {

/// @notice The name of this contract
string public constant name = "Compound Governor Bravo";
Expand Down Expand Up @@ -74,7 +74,8 @@ contract GovernorBravoDelegate is GovernorBravoDelegateStorageV1, GovernorBravoE
function propose(address[] memory targets, uint[] memory values, string[] memory signatures, bytes[] memory calldatas, string memory description) public returns (uint) {
// Reject proposals before initiating as Governor
require(initialProposalId != 0, "GovernorBravo::propose: Governor Bravo not active");
require(comp.getPriorVotes(msg.sender, sub256(block.number, 1)) > proposalThreshold, "GovernorBravo::propose: proposer votes below proposal threshold");
// Allow addresses above proposal threshold and whitelisted addresses to propose
require(comp.getPriorVotes(msg.sender, sub256(block.number, 1)) > proposalThreshold || isWhitelisted(msg.sender), "GovernorBravo::propose: proposer votes below proposal threshold");
require(targets.length == values.length && targets.length == signatures.length && targets.length == calldatas.length, "GovernorBravo::propose: proposal function information arity mismatch");
require(targets.length != 0, "GovernorBravo::propose: must provide actions");
require(targets.length <= proposalMaxOperations, "GovernorBravo::propose: too many actions");
Expand Down Expand Up @@ -156,8 +157,18 @@ contract GovernorBravoDelegate is GovernorBravoDelegateStorageV1, GovernorBravoE
require(state(proposalId) != ProposalState.Executed, "GovernorBravo::cancel: cannot cancel executed proposal");

Proposal storage proposal = proposals[proposalId];
require(msg.sender == proposal.proposer || comp.getPriorVotes(proposal.proposer, sub256(block.number, 1)) < proposalThreshold, "GovernorBravo::cancel: proposer above threshold");

// Proposer can cancel
if(msg.sender != proposal.proposer) {
// Whitelisted proposers can't be canceled for falling below proposal threshold
if(isWhitelisted(proposal.proposer)) {
require((comp.getPriorVotes(proposal.proposer, sub256(block.number, 1)) < proposalThreshold) && msg.sender == whitelistGuardian, "GovernorBravo::cancel: whitelisted proposer");
}
else {
require((comp.getPriorVotes(proposal.proposer, sub256(block.number, 1)) < proposalThreshold), "GovernorBravo::cancel: proposer above threshold");
}
}

proposal.canceled = true;
for (uint i = 0; i < proposal.targets.length; i++) {
timelock.cancelTransaction(proposal.targets[i], proposal.values[i], proposal.signatures[i], proposal.calldatas[i], proposal.eta);
Expand Down Expand Up @@ -275,6 +286,15 @@ contract GovernorBravoDelegate is GovernorBravoDelegateStorageV1, GovernorBravoE
return votes;
}

/**
* @notice View function which returns if an account is whitelisted
* @param account Account to check white list status of
* @return If the account is whitelisted
*/
function isWhitelisted(address account) public view returns (bool) {
return (whitelistAccountExpirations[account] > now);
}

/**
* @notice Admin function for setting the voting delay
* @param newVotingDelay new voting delay, in blocks
Expand Down Expand Up @@ -315,6 +335,30 @@ contract GovernorBravoDelegate is GovernorBravoDelegateStorageV1, GovernorBravoE
emit ProposalThresholdSet(oldProposalThreshold, proposalThreshold);
}

/**
* @notice Admin function for setting the whitelist expiration as a timestamp for an account. Whitelist status allows accounts to propose without meeting threshold
* @param account Account address to set whitelist expiration for
* @param expiration Expiration for account whitelist status as timestamp (if now < expiration, whitelisted)
*/
function _setWhitelistAccountExpiration(address account, uint expiration) external {
require(msg.sender == admin || msg.sender == whitelistGuardian, "GovernorBravo::_setWhitelistAccountExpiration: admin only");
whitelistAccountExpirations[account] = expiration;

emit WhitelistAccountExpirationSet(account, expiration);
}

/**
* @notice Admin function for setting the whitelistGuardian. WhitelistGuardian can cancel proposals from whitelisted addresses
* @param account Account to set whitelistGuardian to (0x0 to remove whitelistGuardian)
*/
function _setWhitelistGuardian(address account) external {
require(msg.sender == admin, "GovernorBravo::_setWhitelistGuardian: admin only");
address oldGuardian = whitelistGuardian;
whitelistGuardian = account;

emit WhitelistGuardianSet(oldGuardian, whitelistGuardian);
}

/**
* @notice Initiate the GovernorBravo contract
* @dev Admin only. Sets initial proposal id which initiates the contract, ensuring a continuous proposal id count
Expand Down
Loading

0 comments on commit 3bb6de7

Please sign in to comment.