Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
77 changes: 70 additions & 7 deletions contracts/token/GovernorMills.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
pragma solidity ^0.5.16;
pragma experimental ABIEncoderV2;

import {Guardian} from "./Guardian.sol";

interface InvInterface {
function getPriorVotes(address account, uint blockNumber) external view returns (uint96);
function totalSupply() external view returns (uint256);
Expand Down Expand Up @@ -31,11 +33,14 @@ contract GovernorMills {
/// @notice The maximum number of actions that can be included in a proposal
function proposalMaxOperations() public pure returns (uint) { return 20; } // 20 actions

/// @notice The delay before voting on a proposal may take place, once proposed
function votingDelay() public pure returns (uint) { return 1; } // 1 block
/// @notice The delay before voting on a proposal may take place, once proposed (in blocks)
uint256 public votingDelay = 1; // 1 block

/// @notice The duration of voting on a proposal, in blocks
function votingPeriod() public pure returns (uint) { return 17280; } // ~3 days in blocks (assuming 15s blocks)
uint256 public votingPeriod = 23564; // ~3 days in blocks (assuming 11s blocks)

/// @notice The duration for which a proposal is queueable after succeeding
uint256 public queuePeriod = 23564;

/// @notice The address of the Protocol Timelock
TimelockInterface public timelock;
Expand Down Expand Up @@ -171,11 +176,20 @@ contract GovernorMills {
/// @notice An event emitted when an address is added or removed from the proposer whitelist
event ProposerWhitelistUpdated(address proposer, bool value);

/// @notice An event emitted when the voting delay is updated
event VotingDelayUpdated(uint256 oldVotingDelay, uint256 newVotingDelay);

/// @notice An event emitted when the voting period is updated
event VotingPeriodUpdated(uint256 oldVotingPeriod, uint256 newVotingPeriod);

/// @notice An event emitted when the queue period is updated
event QueuePeriodUpdated(uint256 oldQueuePeriod, uint256 newQueuePeriod);

constructor(TimelockInterface timelock_, InvInterface inv_, XinvInterface xinv_) public {
timelock = timelock_;
inv = inv_;
xinv = xinv_;
guardian = msg.sender;
guardian = address(new Guardian(msg.sender));
}

function _getPriorVotes(address _proposer, uint256 _blockNumber, uint256 _exchangeRate) internal view returns (uint96) {
Expand Down Expand Up @@ -226,8 +240,8 @@ contract GovernorMills {
require(proposersLatestProposalState != ProposalState.Pending, "GovernorMills::propose: one live proposal per proposer, found an already pending proposal");
}

uint startBlock = add256(block.number, votingDelay());
uint endBlock = add256(startBlock, votingPeriod());
uint startBlock = add256(block.number, votingDelay);
uint endBlock = add256(startBlock, votingPeriod);

proposalCount++;
Proposal memory newProposal = Proposal({
Expand Down Expand Up @@ -325,6 +339,52 @@ contract GovernorMills {
emit QuorumUpdated(oldQuorum, newQuorum);
}

/**
* @notice Update the voting delay (in blocks) before voting on a proposal may take place.
* @param newVotingDelay The new voting delay to set.
*/
function updateVotingDelay(uint256 newVotingDelay) public {
require(msg.sender == address(timelock), "GovernorMills::updateVotingDelay: sender must be timelock");
require(newVotingDelay != votingDelay, "GovernorMills::updateVotingDelay: no change in value");

uint256 oldVotingDelay = votingDelay;
votingDelay = newVotingDelay;

emit VotingDelayUpdated(oldVotingDelay, newVotingDelay);
}

/**
* @notice Update the voting period (in blocks) for a proposal.
* @param newVotingPeriod The new voting period to set.
*/
function updateVotingPeriod(uint256 newVotingPeriod) public {
require(msg.sender == address(timelock), "GovernorMills::updateVotingPeriod: sender must be timelock");
//Minimum voting period of 12 hours at 11s per block
require(newVotingPeriod >= 3927, "GovernorMills::updateVotingPeriod: voting period too short");
require(newVotingPeriod != votingPeriod, "GovernorMills::updateVotingPeriod: no change in value");

uint256 oldVotingPeriod = votingPeriod;
votingPeriod = newVotingPeriod;

emit VotingPeriodUpdated(oldVotingPeriod, newVotingPeriod);
}

/**
* @notice Update the queue period (in blocks) for a proposal.
* @param newQueuePeriod The new queue period to set.
*/
function updateQueuePeriod(uint256 newQueuePeriod) public {
require(msg.sender == address(timelock), "GovernorMills::updateQueuePeriod: sender must be timelock");
//Minimum queuing period of 12 hours at 11s per block
require(newQueuePeriod >= 3927, "GovernorMills::updateQueuePeriod: queue period too short");
require(newQueuePeriod != queuePeriod, "GovernorMills::updateQueuePeriod: no change in value");

uint256 oldQueuePeriod = queuePeriod;
queuePeriod = newQueuePeriod;

emit QueuePeriodUpdated(oldQueuePeriod, newQueuePeriod);
}

function acceptAdmin() public {
require(msg.sender == guardian, "GovernorMills::acceptAdmin: sender must be gov guardian");
timelock.acceptAdmin();
Expand Down Expand Up @@ -364,6 +424,9 @@ contract GovernorMills {
} else if (proposal.forVotes <= proposal.againstVotes || proposal.forVotes < quorumVotes) {
return ProposalState.Defeated;
} else if (proposal.eta == 0) {
if (block.number > add256(proposal.endBlock, queuePeriod)) {
return ProposalState.Expired;
}
return ProposalState.Succeeded;
} else if (proposal.executed) {
return ProposalState.Executed;
Expand Down Expand Up @@ -430,4 +493,4 @@ contract GovernorMills {
return chainId;
}

}
}
87 changes: 87 additions & 0 deletions contracts/token/Guardian.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.5.16;

interface IGovernorMills {
function cancel(uint256 proposalId) external;
function __queueSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) external;
function __executeSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) external;
}

contract Guardian {
IGovernorMills public governorMills;
address public constant oldGovernor = 0x926dF14a23BE491164dCF93f4c468A50ef659D5B;
uint256 public revertDeadline;
address public deployer;
address public pendingDeployer;
address public rwg = 0xE3eD95e130ad9E15643f5A5f232a3daE980784cd;
address public pendingRwg;
mapping(uint256 => bool) public cancellableProposals;

event GovernanceRevertQueued(uint256 indexed eta);
event GovernanceReverted(uint256 indexed eta);
event AllowCancel(uint256 indexed proposalId, bool decision);
event ExecuteCancel(uint256 indexed proposalId);
event PendingRwgSet(address indexed newPendingRwg);
event RwgSet(address indexed oldRwg, address indexed newRwg);
event PendingDeployerSet(address indexed newPendingDeployer);
event DeployerSet(address indexed oldDeployer, address indexed newDeployer);

constructor(address _deployer) public {
revertDeadline = block.timestamp + 180 days; //6 month rollback window
governorMills = IGovernorMills(msg.sender);
deployer = _deployer;
}

function queueRevertToPreviousGovernance(uint256 eta) external {
require(msg.sender == deployer || msg.sender == rwg, "Guardian: not deployer or rwg");
require(block.timestamp <= revertDeadline, "Guardian: revert deadline exceeded");
governorMills.__queueSetTimelockPendingAdmin(oldGovernor, eta);
emit GovernanceRevertQueued(eta);
}

function executeRevertToPreviousGovernance(uint256 eta) external {
require(msg.sender == deployer || msg.sender == rwg, "Guardian: not deployer or rwg");
governorMills.__executeSetTimelockPendingAdmin(oldGovernor, eta);
emit GovernanceReverted(eta);
}

function allowCancel(uint256 proposalId, bool decision) external {
require(msg.sender == deployer, "Guardian: not deployer");
cancellableProposals[proposalId] = decision;
emit AllowCancel(proposalId, decision);
}

function executeCancel(uint256 proposalId) external {
require(msg.sender == rwg, "Guardian: not rwg");
require(cancellableProposals[proposalId], "Guardian: not cancellable");
governorMills.cancel(proposalId);
cancellableProposals[proposalId] = false;
emit ExecuteCancel(proposalId);
}

function setPendingRwg(address _rwg) external {
require(msg.sender == rwg, "Guardian: not rwg");
emit PendingRwgSet(_rwg);
pendingRwg = _rwg;
}

function claimRwg() external {
require(msg.sender == pendingRwg, "Guardian: not pending rwg");
emit RwgSet(rwg, pendingRwg);
rwg = pendingRwg;
pendingRwg = address(0);
}

function setPendingDeployer(address _deployer) external {
require(msg.sender == deployer, "Guardian: not deployer");
emit PendingDeployerSet(_deployer);
pendingDeployer = _deployer;
}

function claimDeployer() external {
require(msg.sender == pendingDeployer, "Guardian: not pending deployer");
emit DeployerSet(deployer, pendingDeployer);
deployer = pendingDeployer;
pendingDeployer = address(0);
}
}