Skip to content
Merged
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
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ The test suite (`test/`) is still being built.
`script/DeployGitcoinGovernorWithGuardianMainnet.s.sol` supplies the mainnet configuration: the GTC
token and Compound Timelock addresses (fixed since 2021), plus governance parameters that mirror the
active "GTC Governor Bravo" so the upgrade preserves current behavior. The new late-quorum vote
extension and the Governor name carry `TODO`s to confirm with stakeholders before deploying.
extension, the initial proposal guardian, and the Governor name carry `TODO`s to confirm with
stakeholders before deploying.

Dry-run first to simulate the deployment and print the transaction it would send, and review that
before broadcasting:
Expand Down
24 changes: 23 additions & 1 deletion script/DeployGitcoinGovernorWithGuardian.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ abstract contract DeployGitcoinGovernorWithGuardian is Script {
uint256 initialProposalThreshold;
IComp token;
ICompoundTimelock timelock;
address initialProposalGuardian;
}

GitcoinGovernorWithGuardian public governor;
Expand All @@ -40,6 +41,9 @@ abstract contract DeployGitcoinGovernorWithGuardian is Script {
);
_log(string.concat(" token: ", vm.toString(address(_params.token))));
_log(string.concat(" timelock: ", vm.toString(address(_params.timelock))));
_log(
string.concat(" initialProposalGuardian: ", vm.toString(_params.initialProposalGuardian))
);

vm.startBroadcast();
// BROADCAST: deploy the GitcoinGovernorWithGuardian
Expand All @@ -52,7 +56,8 @@ abstract contract DeployGitcoinGovernorWithGuardian is Script {
_params.initialVotingPeriod,
_params.initialProposalThreshold,
address(_params.token),
_params.timelock
_params.timelock,
_params.initialProposalGuardian
);
vm.stopBroadcast();

Expand Down Expand Up @@ -86,6 +91,13 @@ abstract contract DeployGitcoinGovernorWithGuardian is Script {
"set it to the address of Gitcoin's Compound Timelock"
);
}
if (_params.initialProposalGuardian == address(0)) {
revert(
"DeployGitcoinGovernorWithGuardian: initialProposalGuardian is the zero address; "
"deploying without a guardian would let every proposer cancel their own proposals at "
"any lifecycle stage, so set it to the address that should hold cancel authority"
);
}
}

function _revertIfDeploymentIsInvalid(DeploymentParams memory _params) internal view {
Expand All @@ -109,5 +121,15 @@ abstract contract DeployGitcoinGovernorWithGuardian is Script {
)
);
}
if (governor.proposalGuardian() != _params.initialProposalGuardian) {
revert(
string.concat(
"DeployGitcoinGovernorWithGuardian: deployed governor proposal guardian is ",
vm.toString(governor.proposalGuardian()),
" but expected ",
vm.toString(_params.initialProposalGuardian)
)
);
}
}
}
10 changes: 9 additions & 1 deletion script/DeployGitcoinGovernorWithGuardianMainnet.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ contract DeployGitcoinGovernorWithGuardianMainnet is DeployGitcoinGovernorWithGu
// voting period ending.
uint48 constant INITIAL_VOTE_EXTENSION = 14_400;

// TODO: Confirm the proposal guardian address with Gitcoin stakeholders before deploying —
// presumably the DAO's security-council multisig. Defaulted here to the Timelock, i.e. the DAO
// itself, so that until a dedicated guardian is chosen, cancel authority rests with governance
// rather than with no one (an unset guardian would let every proposer cancel their own proposals
// at any lifecycle stage).
address constant INITIAL_PROPOSAL_GUARDIAN = 0x57a8865cfB1eCEf7253c27da6B4BC3dAEE5Be518;

function _getDeploymentParams() internal pure override returns (DeploymentParams memory) {
return DeploymentParams({
name: GOVERNOR_NAME,
Expand All @@ -45,7 +52,8 @@ contract DeployGitcoinGovernorWithGuardianMainnet is DeployGitcoinGovernorWithGu
initialVotingPeriod: INITIAL_VOTING_PERIOD,
initialProposalThreshold: INITIAL_PROPOSAL_THRESHOLD,
token: GTC_TOKEN,
timelock: TIMELOCK
timelock: TIMELOCK,
initialProposalGuardian: INITIAL_PROPOSAL_GUARDIAN
});
}
}
11 changes: 9 additions & 2 deletions src/GitcoinGovernorWithGuardian.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ contract GitcoinGovernorWithGuardian is
/// @param _token The address of the COMP-style legacy governance token used to source voting
/// weight.
/// @param _timelockAddress The address of Gitcoin's Timelock address.
/// @param _initialProposalGuardian The deployment value for the proposal guardian, the address
/// empowered to cancel proposals at any point in their lifecycle before execution. Set at
/// deployment so the Governor is never live without a guardian; the DAO can replace it later via
/// a governance proposal calling `setProposalGuardian`.
constructor(
string memory _name,
uint256 _initialQuorum,
Expand All @@ -66,15 +70,18 @@ contract GitcoinGovernorWithGuardian is
uint32 _initialVotingPeriod,
uint256 _initialProposalThreshold,
address _token,
ICompoundTimelock _timelockAddress
ICompoundTimelock _timelockAddress,
address _initialProposalGuardian
)
Governor(_name)
GovernorSettableFixedQuorum(_initialQuorum)
GovernorPreventLateQuorum(_initialVoteExtension)
GovernorSettings(_initialVotingDelay, _initialVotingPeriod, _initialProposalThreshold)
GovernorVotesComp(_token)
GovernorTimelockCompound(_timelockAddress)
{}
{
_setProposalGuardian(_initialProposalGuardian);
}

/// @inheritdoc GovernorSettings
/// @dev We override this function to resolve ambiguity between inherited contracts.
Expand Down
Loading