Skip to content

Commit

Permalink
Merge branch 'vg/feat/onchain-governor' into vg/spike/treasury
Browse files Browse the repository at this point in the history
  • Loading branch information
victorges committed Aug 18, 2023
2 parents 77408d4 + b59a538 commit 6ec40e4
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 68 deletions.
6 changes: 1 addition & 5 deletions contracts/test/mocks/GovernorCountingOverridableHarness.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,13 @@ contract GovernorCountingOverridableHarness is
);

__GovernorVotes_init(iVotes);
__GovernorCountingOverridable_init();
__GovernorCountingOverridable_init(QUOTA);
}

function votes() public view override returns (IVotes) {
return iVotes;
}

function quota() public pure override returns (uint256) {
return QUOTA;
}

function quorum(uint256 timepoint) public view virtual override returns (uint256) {
uint256 totalSupply = iVotes.getPastTotalSupply(timepoint);
return MathUtils.percOf(totalSupply, QUORUM);
Expand Down
40 changes: 20 additions & 20 deletions contracts/treasury/GovernorCountingOverridable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity 0.8.9;

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/governance/extensions/GovernorVotesQuorumFractionUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/governance/GovernorUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/interfaces/IERC5805Upgradeable.sol";

import "../bonding/libraries/EarningsPool.sol";
Expand All @@ -19,17 +19,9 @@ import "./IVotes.sol";
* delegated transcoder's vote. This module is used through inheritance by the Governor contract.
*/
abstract contract GovernorCountingOverridable is Initializable, GovernorUpgradeable {
using SafeMath for uint256;

error InvalidVoteType(uint8 voteType);
error VoteAlreadyCast();

function __GovernorCountingOverridable_init() internal onlyInitializing {
__GovernorCountingOverridable_init_unchained();
}

function __GovernorCountingOverridable_init_unchained() internal onlyInitializing {}

/**
* @dev Supported vote types. Matches Governor Bravo ordering.
*/
Expand Down Expand Up @@ -60,8 +52,23 @@ abstract contract GovernorCountingOverridable is Initializable, GovernorUpgradea
mapping(address => ProposalVoterState) voters;
}

/**
* @notice The required percentage of "for" votes in relation to the total opinionated votes (for and abstain) for
* a proposal to succeed. Represented as a MathUtils percentage value (e.g. 6 decimal places).
*/
uint256 public quota;

// Maps proposal IDs to their corresponding vote tallies.
mapping(uint256 => ProposalTally) private _proposalTallies;

function __GovernorCountingOverridable_init(uint256 _quota) internal onlyInitializing {
__GovernorCountingOverridable_init_unchained(_quota);
}

function __GovernorCountingOverridable_init_unchained(uint256 _quota) internal onlyInitializing {
quota = _quota;
}

/**
* @dev See {IGovernor-COUNTING_MODE}.
*/
Expand Down Expand Up @@ -101,7 +108,7 @@ abstract contract GovernorCountingOverridable is Initializable, GovernorUpgradea
function _quorumReached(uint256 _proposalId) internal view virtual override returns (bool) {
(uint256 againstVotes, uint256 forVotes, uint256 abstainVotes) = proposalVotes(_proposalId);

uint256 totalVotes = againstVotes.add(forVotes).add(abstainVotes);
uint256 totalVotes = againstVotes + forVotes + abstainVotes;

return totalVotes >= quorum(proposalSnapshot(_proposalId));
}
Expand All @@ -113,9 +120,9 @@ abstract contract GovernorCountingOverridable is Initializable, GovernorUpgradea
(uint256 againstVotes, uint256 forVotes, ) = proposalVotes(_proposalId);

// we ignore abstain votes for vote succeeded calculation
uint256 totalValidVotes = againstVotes.add(forVotes);
uint256 opinionatedVotes = againstVotes + forVotes;

return forVotes >= MathUtils.percOf(totalValidVotes, quota());
return forVotes >= MathUtils.percOf(opinionatedVotes, quota);
}

/**
Expand Down Expand Up @@ -149,7 +156,6 @@ abstract contract GovernorCountingOverridable is Initializable, GovernorUpgradea
} else if (support == VoteType.For) {
tally.forVotes += _weight;
} else {
assert(support == VoteType.Abstain);
tally.abstainVotes += _weight;
}
}
Expand Down Expand Up @@ -211,16 +217,10 @@ abstract contract GovernorCountingOverridable is Initializable, GovernorUpgradea
*/
function votes() public view virtual returns (IVotes);

/**
* @dev Implement in inheriting contract to provide quota value to use to decide proposal success.
* @return quota value as a MathUtils percentage value (e.g. 6 decimal places).
*/
function quota() public view virtual returns (uint256);

/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
uint256[48] private __gap;
}
24 changes: 4 additions & 20 deletions contracts/treasury/LivepeerGovernor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import "@openzeppelin/contracts-upgradeable/governance/extensions/GovernorTimelo

import "../bonding/libraries/EarningsPool.sol";
import "../bonding/libraries/EarningsPoolLIP36.sol";
import "../polling/PollCreator.sol";

import "../ManagerProxyTarget.sol";
import "../IController.sol";
Expand Down Expand Up @@ -54,7 +53,9 @@ contract LivepeerGovernor is
function initialize(
uint256 initialVotingDelay,
uint256 initialVotingPeriod,
uint256 initialProposalThreshold
uint256 initialProposalThreshold,
uint256 initialQuorum,
uint256 quota
) public initializer {
__Governor_init("LivepeerGovernor");
__GovernorSettings_init(initialVotingDelay, initialVotingPeriod, initialProposalThreshold);
Expand All @@ -64,11 +65,9 @@ contract LivepeerGovernor is
// need to call the {bumpGovernorVotesTokenAddress} function to update it in here as well.
__GovernorVotes_init(votes());

// Initialize with the same value from the existing polling system.
uint256 initialQuorum = pollCreator().QUORUM();
__GovernorVotesQuorumFraction_init(initialQuorum);

__GovernorCountingOverridable_init();
__GovernorCountingOverridable_init(quota);
}

/**
Expand All @@ -86,14 +85,6 @@ contract LivepeerGovernor is
return bondingVotes();
}

/**
* @dev See {GovernorCountingOverridable-quota}. We use the same QUOTA value from the protocol governance system for
* now, but can consider changing this in the future (e.g. to make it updateable through proposals without deploys).
*/
function quota() public view override returns (uint256) {
return pollCreator().QUOTA();
}

/**
* @dev This should be called if we ever change the address of the BondingVotes contract. Not a normal flow, but its
* address could still eventually change in the controller so we provide this function as a future-proof commodity.
Expand All @@ -110,13 +101,6 @@ contract LivepeerGovernor is
return IVotes(controller.getContract(keccak256("BondingVotes")));
}

/**
* @dev Returns the PollCreator contract address from the controller.
*/
function pollCreator() internal view returns (PollCreator) {
return PollCreator(controller.getContract(keccak256("PollCreator")));
}

/**
* @dev Returns the Treasury contract address from the controller.
*/
Expand Down
22 changes: 4 additions & 18 deletions deploy/deploy_livepeer_governor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const isProdNetwork = (name: string): boolean => {

const func: DeployFunction = async function(hre: HardhatRuntimeEnvironment) {
const {deployments, getNamedAccounts} = hre // Get the deployments and getNamedAccounts which are provided by hardhat-deploy
const {deploy, get} = deployments // the deployments object itself contains the deploy function
const {deploy} = deployments // the deployments object itself contains the deploy function

const {deployer} = await getNamedAccounts() // Fetch named accounts from hardhat.config.ts

Expand All @@ -24,22 +24,6 @@ const func: DeployFunction = async function(hre: HardhatRuntimeEnvironment) {
const contractDeployer = new ContractDeployer(deploy, deployer, deployments)
const controller = await contractDeployer.fetchDeployedController()

// PollCreator is deployed without being registered to Controller, so we do that here
const registeredPollCreator = await controller.getContract(
ethers.utils.solidityKeccak256(["string"], ["PollCreator"])
)
if (registeredPollCreator === constants.AddressZero) {
const pollCreator = await ethers.getContractAt(
"PollCreator",
isProdNetwork(hre.network.name) ?
config.livepeerGovernor.pollCreatorAddress :
await get("PollCreator").then(p => p.address)
)

await contractDeployer.register("PollCreator", pollCreator.address)
}

// Onchain treasury governor (LivepeerGovernor)
const treasury = await contractDeployer.deployAndRegister({
contract: "Treasury",
name: "Treasury",
Expand Down Expand Up @@ -71,7 +55,9 @@ const func: DeployFunction = async function(hre: HardhatRuntimeEnvironment) {
await LivepeerGovernor.initialize(
config.livepeerGovernor.initialVotingDelay,
config.livepeerGovernor.initialVotingPeriod,
config.livepeerGovernor.initialProposalThreshold
config.livepeerGovernor.initialProposalThreshold,
config.livepeerGovernor.initialQuorum,
config.livepeerGovernor.quota
).then(tx => tx.wait())

// Now grant proposer and executor roles to governor and renounce deployer admin role
Expand Down
6 changes: 4 additions & 2 deletions deploy/migrations.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,14 @@ const defaultConfig = {
targetBondingRate: 500000
},
treasury: {
minDelay: 0 // 0s initial proposal delay
minDelay: 0 // 0s initial proposal execution delay
},
livepeerGovernor: {
initialVotingDelay: 1, // 1 round
initialVotingPeriod: 10, // 10 rounds
initialProposalThreshold: ethers.utils.parseEther("100") // 100 LPT
initialProposalThreshold: ethers.utils.parseEther("100"), // 100 LPT
initialQuorum: 333300, // 33%
quota: 500000 // 50%
}
}

Expand Down
10 changes: 7 additions & 3 deletions test/integration/LivepeerGovernor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ describe("LivepeerGovernor", () => {
it("should not be initializable", async () => {
// revert msg is misleading, but it's not initializable because initializers are disabled
await expect(
governorTarget.initialize(0, 0, 0)
governorTarget.initialize(0, 0, 0, 0, 0)
).to.be.revertedWith(
"Initializable: contract is already initialized"
)
Expand Down Expand Up @@ -246,7 +246,9 @@ describe("LivepeerGovernor", () => {
})

it("should not be re-initializable", async () => {
await expect(governor.initialize(0, 0, 0)).to.be.revertedWith(
await expect(
governor.initialize(0, 0, 0, 0, 0)
).to.be.revertedWith(
"Initializable: contract is already initialized"
)

Expand All @@ -268,7 +270,9 @@ describe("LivepeerGovernor", () => {
)

// should keep initialized state
await expect(governor.initialize(0, 0, 0)).to.be.revertedWith(
await expect(
governor.initialize(0, 0, 0, 0, 0)
).to.be.revertedWith(
"Initializable: contract is already initialized"
)

Expand Down

0 comments on commit 6ec40e4

Please sign in to comment.