Skip to content

Commit 81e91cb

Browse files
committed
add governance contracts
1 parent 36615a3 commit 81e91cb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+16211
-0
lines changed

contracts/MarshallGovernor.sol

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity 0.8.19;
3+
4+
import {IVotes} from "./governance/IVotes.sol";
5+
import {IVotingEscrow} from "contracts/interfaces/IVotingEscrow.sol";
6+
7+
import {IVetoGovernor} from "./governance/IVetoGovernor.sol";
8+
import {VetoGovernor} from "./governance/VetoGovernor.sol";
9+
import {VetoGovernorCountingSimple} from "./governance/VetoGovernorCountingSimple.sol";
10+
import {VetoGovernorVotes} from "./governance/VetoGovernorVotes.sol";
11+
import {VetoGovernorVotesQuorumFraction} from "./governance/VetoGovernorVotesQuorumFraction.sol";
12+
13+
/// @title MarshallGovernor
14+
/// @author velodrome.finance, @figs999, @pegahcarter
15+
/// @notice Velodrome V2 governance with timestamp-based voting power from VotingEscrow NFTs
16+
/// Supports vetoing of proposals as mitigation for 51% attacks
17+
/// Votes are cast and counted on a per tokenId basis
18+
contract MarshallGovernor is
19+
VetoGovernor,
20+
VetoGovernorCountingSimple,
21+
VetoGovernorVotes,
22+
VetoGovernorVotesQuorumFraction
23+
{
24+
address public immutable ve;
25+
address public vetoer;
26+
address public pendingVetoer;
27+
uint256 public constant MAX_PROPOSAL_NUMERATOR = 500; // max 5%
28+
uint256 public constant PROPOSAL_DENOMINATOR = 10_000;
29+
uint256 public proposalNumerator = 2; // start at 0.02%
30+
31+
error NotTeam();
32+
error NotPendingVetoer();
33+
error NotVetoer();
34+
error ProposalNumeratorTooHigh();
35+
error ZeroAddress();
36+
37+
constructor(
38+
IVotes _ve
39+
)
40+
VetoGovernor("Velodrome Governor")
41+
VetoGovernorVotes(_ve)
42+
VetoGovernorVotesQuorumFraction(4) // 4%
43+
{
44+
ve = address(_ve);
45+
vetoer = msg.sender;
46+
}
47+
48+
function votingDelay() public pure override(IVetoGovernor) returns (uint256) {
49+
return (15 minutes);
50+
}
51+
52+
function votingPeriod() public pure override(IVetoGovernor) returns (uint256) {
53+
return (1 weeks);
54+
}
55+
56+
function setProposalNumerator(uint256 numerator) external {
57+
if (msg.sender != IVotingEscrow(ve).team()) revert NotTeam();
58+
if (numerator > MAX_PROPOSAL_NUMERATOR) revert ProposalNumeratorTooHigh();
59+
proposalNumerator = numerator;
60+
}
61+
62+
function proposalThreshold() public view override(VetoGovernor) returns (uint256) {
63+
return (token.getPastTotalSupply(block.timestamp - 1) * proposalNumerator) / PROPOSAL_DENOMINATOR;
64+
}
65+
66+
/// @dev Vetoer can be removed once the risk of a 51% attack becomes unfeasible.
67+
/// This can be done by transferring ownership of vetoer to a contract that is "bricked"
68+
/// i.e. a non-zero address contract that is immutable with no ability to call this function.
69+
function setVetoer(address _vetoer) external {
70+
if (msg.sender != vetoer) revert NotVetoer();
71+
if (_vetoer == address(0)) revert ZeroAddress();
72+
pendingVetoer = _vetoer;
73+
}
74+
75+
function acceptVetoer() external {
76+
if (msg.sender != pendingVetoer) revert NotPendingVetoer();
77+
vetoer = pendingVetoer;
78+
delete pendingVetoer;
79+
}
80+
81+
/// @notice Support for vetoer to protect against 51% attacks
82+
function veto(uint256 _proposalId) external {
83+
if (msg.sender != vetoer) revert NotVetoer();
84+
_veto(_proposalId);
85+
}
86+
87+
function renounceVetoer() external {
88+
if (msg.sender != vetoer) revert NotVetoer();
89+
delete vetoer;
90+
}
91+
}

0 commit comments

Comments
 (0)