Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

treasury: Delta Governor v1 #615

Merged
merged 32 commits into from
Aug 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
cc315d1
package.json: Update @openzeppelin libraries
victorges Jul 7, 2023
d42e92c
bonding: Create SortedArrays library
victorges Jul 7, 2023
2abf207
bonding: Create BondingCheckpoints contract
victorges Jul 7, 2023
a9dde9d
bonding: Checkpoint bonding state on changes
victorges Jul 7, 2023
078f348
test/bonding: Test BondingManager and Checkpoints
victorges Jul 7, 2023
22ee2db
bonding: Migrate to custom error types
victorges Jul 14, 2023
2e4157b
bonding: Allow querying unbonded+uncheckpointed accounts
victorges Jul 17, 2023
06b7100
treasury: Create treasury governance contracts
victorges Jul 17, 2023
0aa6cd0
test/treasury: Add unit test fro BondingCheckpointsVotes
victorges Jul 17, 2023
9f007ba
test/treasury: Test GovernorCountingOverridable
victorges Jul 18, 2023
2fd7abb
test/treasury: Test LivepeerGovernor
victorges Jul 20, 2023
34cb455
test/treasury: A couple additional Governor tests
victorges Jul 20, 2023
e970472
test/treasury: Rename Counting unit test mock
victorges Jul 20, 2023
a6db562
Apply suggestions from code review
victorges Jul 26, 2023
0ad3a8f
treasury: Fix storage layout situation
victorges Jul 27, 2023
bb9ff45
treasury: Move governor initial params to configs
victorges Aug 4, 2023
0c41f78
bonding: Make sure we checkpoint up to once per op
victorges Aug 12, 2023
d518cd6
bonding: Make bonding checkpoints implement IVotes
victorges Aug 13, 2023
ccc3ddf
bonding: Read votes from the end of the round
victorges Aug 15, 2023
d5062fe
bonding: Make checkpoint reading revert-free
victorges Aug 17, 2023
292f954
bonding: Address minor code review comments
victorges Aug 16, 2023
4f12ce9
Merge branch 'vg/feat/bonding-checkpoints' into vg/feat/onchain-governor
victorges Aug 17, 2023
e9d3339
treasury: Migrate to the new BondingVotes contract
victorges Aug 17, 2023
f0fb8ee
treasury: Address PR comments
victorges Aug 17, 2023
9dbb0ae
bonding: Move constructor to after modifiers
victorges Aug 17, 2023
b59a538
test/mocks: Remove mock functions that moved to other mock
victorges Aug 18, 2023
1692ec1
bonding: Implement ERC20 metadata on votes
victorges Aug 21, 2023
fecf5a2
bonding: Address PR comments
victorges Aug 22, 2023
4246474
bonding: Address BondingVotes review comments
victorges Aug 23, 2023
63d1d19
Merge branch 'vg/feat/bonding-checkpoints' into vg/feat/onchain-governor
victorges Aug 23, 2023
8c57a4d
treasury: Merge BondingCheckpoints and nits
victorges Aug 23, 2023
ddaf2bd
Merge branch 'delta' into vg/feat/onchain-governor
victorges Aug 25, 2023
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
51 changes: 51 additions & 0 deletions contracts/test/mocks/GovenorInterfacesFixture.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

import "@openzeppelin/contracts-upgradeable/governance/IGovernorUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/governance/extensions/IGovernorTimelockUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155ReceiverUpgradeable.sol";

/**
* @dev This is a helper contract to return the expected interface values that the LivepeerGovenor interface should
* support. This only exists in Solidity since generating these interfaces in JS is kinda of a pain.
*/
contract GovernorInterfacesFixture {
function TimelockUpgradeableInterface() external pure returns (bytes4) {
return type(IGovernorTimelockUpgradeable).interfaceId;
}

/**
* @dev ID calculation logic copied from {GovernorUpgradeable-supportsInterface}.
*/
function GovernorInterfaces() external pure returns (bytes4[] memory) {
IGovernorUpgradeable governor;
// <begin of copy, replacing `this` with `governor`>
bytes4 governorCancelId = governor.cancel.selector ^ governor.proposalProposer.selector;

bytes4 governorParamsId = governor.castVoteWithReasonAndParams.selector ^
governor.castVoteWithReasonAndParamsBySig.selector ^
governor.getVotesWithParams.selector;

// The original interface id in v4.3.
bytes4 governor43Id = type(IGovernorUpgradeable).interfaceId ^
type(IERC6372Upgradeable).interfaceId ^
governorCancelId ^
governorParamsId;

// An updated interface id in v4.6, with params added.
bytes4 governor46Id = type(IGovernorUpgradeable).interfaceId ^
type(IERC6372Upgradeable).interfaceId ^
governorCancelId;

// For the updated interface id in v4.9, we use governorCancelId directly.
// </end of copy>

// replace the interface checks with return the expected interface ids
bytes4[] memory ids = new bytes4[](4);
ids[0] = governor43Id;
ids[1] = governor46Id;
ids[2] = governorCancelId;
ids[3] = type(IERC1155ReceiverUpgradeable).interfaceId;
return ids;
}
}
74 changes: 74 additions & 0 deletions contracts/test/mocks/GovernorCountingOverridableHarness.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

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

import "../../treasury/GovernorCountingOverridable.sol";

/**
* @dev This is a concrete contract to test the GovernorCountingOverridable extension. It implements the minimum
* necessary to get a working Governor to test the extension.
*/
contract GovernorCountingOverridableHarness is
Initializable,
GovernorUpgradeable,
GovernorSettingsUpgradeable,
GovernorVotesUpgradeable,
GovernorCountingOverridable
{
// use non-standard values for these to test if it's really used
uint256 constant QUOTA = 420000; // 42%
uint256 constant QUORUM = 370000; // 37%

IVotes internal iVotes; // 🍎

function initialize(IVotes _votes) public initializer {
iVotes = _votes;

__Governor_init("GovernorCountingOverridableConcrete");
__GovernorSettings_init(
0, /* no voting delay */
100, /* 100 blocks voting period */
0 /* no minimum proposal threshold */
);

__GovernorVotes_init(iVotes);
__GovernorCountingOverridable_init(QUOTA);
}

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

function quorum(uint256 timepoint) public view virtual override returns (uint256) {
uint256 totalSupply = iVotes.getPastTotalSupply(timepoint);
return MathUtils.percOf(totalSupply, QUORUM);
}

/**
* @dev Expose internal _quorumReached function for testing.
*/
function quorumReached(uint256 proposalId) public view returns (bool) {
return super._quorumReached(proposalId);
}

/**
* @dev Expose internal _voteSucceeded function for testing.
*/
function voteSucceeded(uint256 proposalId) public view returns (bool) {
return super._voteSucceeded(proposalId);
}

function proposalThreshold()
public
view
override(GovernorUpgradeable, GovernorSettingsUpgradeable)
returns (uint256)
{
return super.proposalThreshold();
}
}
14 changes: 14 additions & 0 deletions contracts/test/mocks/LivepeerGovernorUpgradeMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

import "../../treasury/LivepeerGovernor.sol";

contract LivepeerGovernorUpgradeMock is LivepeerGovernor {
uint256 public customField;

constructor(address _controller) LivepeerGovernor(_controller) {}

function setCustomField(uint256 _customField) external {
customField = _customField;
}
}
112 changes: 112 additions & 0 deletions contracts/test/mocks/VotesMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20SnapshotUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20VotesUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

import { IVotes } from "../../treasury/GovernorCountingOverridable.sol";
import "../../bonding/libraries/SortedArrays.sol";

/**
* @dev Minimum implementation of an IVotes interface to test the GovernorCountingOverridable extension. It inherits
* from the default ERC20VotesUpgradeable implementation but overrides the voting power functions to provide power to
* delegators as well (to be made overridable by the GovernorCountingOverridable extension).
*/
contract VotesMock is
Initializable,
ERC20Upgradeable,
ERC20BurnableUpgradeable,
OwnableUpgradeable,
ERC20VotesUpgradeable,
IVotes
{
function initialize() public initializer {
__ERC20_init("VotesMock", "VTCK");
__ERC20Burnable_init();
__Ownable_init();
__ERC20Votes_init();
}

function delegatedAt(address _account, uint256 _timepoint) external view returns (address) {
_timepoint; // unused
// Blatant simplification that only works in our tests where we never change participants balance during
// proposal voting period. We check and return delegators current state instead of tracking historical values.
return delegates(_account);
}

/**
* @dev Simulates the behavior of our actual voting power, where the delegator also has voting power which can
* override their transcoder's vote. This is not the case in the OpenZeppelin implementation.
*/
function getPastVotes(address account, uint256 blockNumber)
public
view
override(IVotesUpgradeable, ERC20VotesUpgradeable)
returns (uint256)
{
// Blatant simplification that only works in our tests where we never change participants balance during
// proposal voting period. We check and return delegators current state instead of tracking historical values.
if (delegates(account) != account) {
return balanceOf(account);
}
return super.getPastVotes(account, blockNumber);
}

/**
* @dev Same as above. Still don't understand why the OZ implementation for these 2 is incompatible, with getPast*
* reverting if you query it with the current round.
*/
function getVotes(address account)
public
view
override(IVotesUpgradeable, ERC20VotesUpgradeable)
returns (uint256)
{
if (delegates(account) != account) {
return balanceOf(account);
}
return super.getVotes(account);
}

function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}

// The following functions are overrides required by Solidity.

function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal override(ERC20Upgradeable, ERC20VotesUpgradeable) {
super._afterTokenTransfer(from, to, amount);
}

function _mint(address to, uint256 amount) internal override(ERC20Upgradeable, ERC20VotesUpgradeable) {
super._mint(to, amount);
}

function _burn(address account, uint256 amount) internal override(ERC20Upgradeable, ERC20VotesUpgradeable) {
super._burn(account, amount);
}

function name() public view override(IVotes, ERC20Upgradeable) returns (string memory) {
return super.name();
}

function symbol() public view override(IVotes, ERC20Upgradeable) returns (string memory) {
return super.symbol();
}

function decimals() public view override(IVotes, ERC20Upgradeable) returns (uint8) {
return super.decimals();
}

function totalSupply() public view override(IVotes, ERC20Upgradeable) returns (uint256) {
return super.totalSupply();
}
}
Loading
Loading