Skip to content

Commit

Permalink
More code efficient approach to settable quorum
Browse files Browse the repository at this point in the history
  • Loading branch information
jferas committed Nov 21, 2023
1 parent 741c4ea commit ff62acd
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 157 deletions.
2 changes: 1 addition & 1 deletion script/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ contract Deploy is DeployInput, Script {
function run() public returns (RadworksGovernor) {
vm.startBroadcast(deployerPrivateKey);
RadworksGovernor _governor =
new RadworksGovernor(INITIAL_VOTING_DELAY, INITIAL_VOTING_PERIOD, INITIAL_PROPOSAL_THRESHOLD);
new RadworksGovernor(INITIAL_VOTING_DELAY, INITIAL_VOTING_PERIOD, INITIAL_PROPOSAL_THRESHOLD, INITIAL_QUORUM_VALUE);
vm.stopBroadcast();

return _governor;
Expand Down
6 changes: 3 additions & 3 deletions script/DeployInput.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity ^0.8.20;

contract DeployInput {
uint256 constant INITIAL_VOTING_DELAY = 7200; // 24 hours
uint256 constant INITIAL_VOTING_PERIOD = 17_280; // matches existing config
uint256 constant INITIAL_PROPOSAL_THRESHOLD = 1_000_000e18; // matches existing config
uint256 constant INITIAL_QUORUM_PCT = 4;
uint256 constant INITIAL_VOTING_PERIOD = 17_280; // matches existing alpha config
uint256 constant INITIAL_PROPOSAL_THRESHOLD = 1_000_000e18; // matches alpha (1% of total supply)
uint256 constant INITIAL_QUORUM_VALUE = 4_000_000e18; // matches alpha (4% of total supply)
}
37 changes: 22 additions & 15 deletions src/RadworksGovernor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {IGovernor} from "@openzeppelin/contracts/governance/IGovernor.sol";
import {ICompoundTimelock} from
"@openzeppelin/contracts/governance/extensions/GovernorTimelockCompound.sol";
import {GovernorSettings} from "@openzeppelin/contracts/governance/extensions/GovernorSettings.sol";
import {GovernorVotesCompQuorumFraction} from "./lib/GovernorVotesCompQuorumFraction.sol";
import {
GovernorTimelockCompound,
ICompoundTimelock
Expand All @@ -22,10 +21,12 @@ import {GovernorCompatibilityBravo} from
/// @notice The upgraded Radworks Governor: Bravo compatible and extended from OpenZeppelin.
contract RadworksGovernor is
Governor,
GovernorVotesCompQuorumFraction,
GovernorVotesComp,
GovernorTimelockCompound,
GovernorSettings
{
event QuorumSet(uint256 newQuorum);

error VoteWouldExceedWeight(uint256 weight);

struct ProposalVote {
Expand All @@ -34,6 +35,9 @@ contract RadworksGovernor is
uint256 abstainVotes;
}

/// @notice The number of RAD (in "wei") that must participate in a vote to meet quorum threshold.
uint256 _quorum = 4_000_000e18; // 4,000,000 RAD (4% of total supply)

/// @notice The address of the RAD token on Ethereum mainnet from which this Governor derives
/// delegated voting weight.
ERC20VotesComp private constant RAD_TOKEN =
Expand All @@ -50,18 +54,20 @@ contract RadworksGovernor is
/// @param _initialVotingDelay The initial voting delay this Governor will enforce.
/// @param _initialVotingPeriod The initial voting period this Governor will enforce.
/// @param _initialProposalThreshold The initial number of RAD required to submit
/// a proposal this Governor will enforce.
/// @param _initialQuorum The initial number of RAD required to meet quorum threshold
constructor(
uint256 _initialVotingDelay,
uint256 _initialVotingPeriod,
uint256 _initialProposalThreshold
uint256 _initialProposalThreshold,
uint256 _initialQuorum
)
GovernorVotesCompQuorumFraction(4)
GovernorVotesComp(RAD_TOKEN)
GovernorSettings(_initialVotingDelay, _initialVotingPeriod, _initialProposalThreshold)
GovernorTimelockCompound(TIMELOCK)
Governor(GOVERNOR_NAME)
{}
{
_quorum = _initialQuorum;
}

/// @dev Mapping from proposal ID to vote tallies for that proposal.
mapping(uint256 => ProposalVote) private _proposalVotes;
Expand Down Expand Up @@ -172,16 +178,17 @@ contract RadworksGovernor is
return GovernorTimelockCompound.state(proposalId);
}

/// @notice The amount of RAD required to meet the quorum threshold for a proposal
/// as of a given block.
/// @notice The amount of RAD required to meet the quorum threshold for a proposal.
/// @dev Our implementation ignores the block number parameter and returns a constant.
function quorum(uint256 timepoint)
public
view
override(IGovernor, GovernorVotesCompQuorumFraction)
returns (uint256)
{
return GovernorVotesCompQuorumFraction.quorum(timepoint);
function quorum(uint256) public view override returns (uint256) {
return _quorum;
}

/// @notice Set the amount of RAD required to meet the quorum threshold for a proposal.
/// @dev This function is only callable by executed governance proposals (thus, the Timelock).
function setQuorum(uint256 _newQuorum) public onlyGovernance {
emit QuorumSet(_newQuorum);
_quorum = _newQuorum;
}

/// @inheritdoc Governor
Expand Down
125 changes: 0 additions & 125 deletions src/lib/GovernorVotesCompQuorumFraction.sol

This file was deleted.

18 changes: 5 additions & 13 deletions test/RadworksGovernor.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,7 @@ abstract contract Constructor is RadworksGovernorTest {

assertEq(governorBravo.proposalThreshold(), INITIAL_PROPOSAL_THRESHOLD);

assertEq(
governorBravo.quorum(block.number),
(governorBravo.token().totalSupply() * INITIAL_QUORUM_PCT) / 100
);
assertEq(governorBravo.quorum(block.number), INITIAL_QUORUM_VALUE);
assertEq(governorBravo.timelock(), TIMELOCK);
assertEq(governorBravo.COUNTING_MODE(), "support=bravo&quorum=bravo");
}
Expand Down Expand Up @@ -446,13 +443,13 @@ abstract contract Propose is ProposalTest {
uint256 _newDelay,
uint256 _newVotingPeriod,
uint256 _newProposalThreshold,
uint256 _newQuorumNumerator
uint256 _newQuorumValue
) public {
// The upper bounds are arbitrary here.
_newDelay = bound(_newDelay, 0, 50_000); // about a week at 1 block per 12s
_newVotingPeriod = bound(_newVotingPeriod, 1, 200_000); // about a month
_newProposalThreshold = bound(_newProposalThreshold, 0, 42 ether);
_newQuorumNumerator = bound(_newQuorumNumerator, 0, 99);
_newQuorumValue = bound(_newQuorumValue, INITIAL_QUORUM_VALUE / 2, INITIAL_QUORUM_VALUE / 2);

_upgradeToBravoGovernor();

Expand All @@ -472,8 +469,7 @@ abstract contract Propose is ProposalTest {
_buildProposalData("setProposalThreshold(uint256)", abi.encode(_newProposalThreshold));

_targets[3] = address(governorBravo);
_calldatas[3] =
_buildProposalData("updateQuorumNumerator(uint256)", abi.encode(_newQuorumNumerator));
_calldatas[3] = _buildProposalData("setQuorum(uint256)", abi.encode(_newQuorumValue));

// Submit the new proposal
vm.prank(PROPOSER);
Expand Down Expand Up @@ -512,11 +508,7 @@ abstract contract Propose is ProposalTest {
assertEq(governorBravo.votingDelay(), _newDelay);
assertEq(governorBravo.votingPeriod(), _newVotingPeriod);
assertEq(governorBravo.proposalThreshold(), _newProposalThreshold);
assertEq(governorBravo.quorumNumerator(block.number), _newQuorumNumerator);
assertEq(
governorBravo.quorum(block.number),
(governorBravo.token().totalSupply() * _newQuorumNumerator) / 100
);
assertEq(governorBravo.quorum(block.number), _newQuorumValue);
}

function testFuzz_NewGovernorCanPassMixedProposal(
Expand Down

0 comments on commit ff62acd

Please sign in to comment.