Skip to main content

governance-patterns

Use when implementing onchain governance, DAO voting systems, or timelock-controlled execution. Covers OpenZeppelin Governor, TimelockController, voting strategies, quorum calculations, and proposal lifecycle.

Aller à l'installation

Informations de source

Dépôt
ccashwell/evm-cortex
Dernière activité de la source
10 avril 2026 à 16:31
Langue détectée de SKILL.md
anglais
Étoiles
131
Forks
18

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
governance-patterns
description
Use when implementing onchain governance, DAO voting systems, or timelock-controlled execution. Covers OpenZeppelin Governor, TimelockController, voting strategies, quorum calculations, and proposal lifecycle.
# Onchain Governance Patterns ## Governor Lifecycle ``` propose() -> Active (voting) -> Succeeded -> queue() -> Queued (timelock) -> execute() -> Defeated (quorum not met or majority against) -> Canceled (by proposer before execution) ``` ## OpenZeppelin Governor Setup ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {Governor} from "@openzeppelin/contracts/governance/Governor.sol"; import {GovernorSettings} from "@openzeppelin/contracts/governance/extensions/GovernorSettings.sol"; import {GovernorCountingSimple} from "@openzeppelin/contracts/governance/extensions/GovernorCountingSimple.sol"; import {GovernorVotes} from "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol"; import {GovernorVotesQuorumFraction} from "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol"; import {GovernorTimelockControl} from "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol"; import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol"; import {IVotes} from "@openzeppelin/contracts/governance/utils/IVotes.sol"; contract MyGovernor is Governor, GovernorSettings, GovernorCountingSimple, GovernorVotes, GovernorVotesQuorumFraction, GovernorTimelockControl { constructor( IVotes _token, TimelockController _timelock ) Governor("MyGovernor") GovernorSettings( 7200, // votingDelay: 1 day in blocks (12s blocks) 50400, // votingPeriod: 1 week in blocks 100e18 // proposalThreshold: 100 tokens to propose ) GovernorVotes(_token) GovernorVotesQuorumFraction(4) // 4% quorum GovernorTimelockControl(_timelock) {} // Required overrides for Solidity function votingDelay() public view override(Governor, GovernorSettings) returns (uint256) { return super.votingDelay(); } function votingPeriod() public view override(Governor, GovernorSettings) returns (uint256) { return super.votingPeriod(); } function quorum(uint256 blockNumber) public view override(Governor, GovernorVotesQuorumFraction) returns (uint256) { return super.quorum(blockNumber); } function state(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (ProposalState) { return super.state(proposalId); } function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { return super.proposalThreshold(); } function proposalNeedsQueuing(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (bool) { return super.proposalNeedsQueuing(proposalId); } function _queueOperations(uint256 id, address[] memory t, uint256[] memory v, bytes[] memory c, bytes32 h) internal override(Governor, GovernorTimelockControl) returns (uint48) { return super._queueOperations(id, t, v, c, h); } function _executeOperations(uint256 id, address[] memory t, uint256[] memory v, bytes[] memory c, bytes32 h) internal override(Governor, GovernorTimelockControl) { super._executeOperations(id, t, v, c, h); } function _cancel(address[] memory t, uint256[] memory v, bytes[] memory c, bytes32 h) internal override(Governor, GovernorTimelockControl) returns (uint256) { return super._cancel(t, v, c, h); } function _executor() internal view override(Governor, GovernorTimelockControl) returns (address) { return super._executor(); } } ``` ## TimelockController Deployment ```solidity uint256 minDelay = 2 days; address[] memory proposers = new address[](1); address[] memory executors = new address[](1); proposers[0] = address(0); // will be set to governor executors[0] = address(0); // anyone can execute after delay TimelockController timelock = new TimelockController( minDelay, proposers, executors, msg.sender ); MyGovernor governor = new MyGovernor(token, timelock); // Grant governor proposer and canceller roles timelock.grantRole(timelock.PROPOSER_ROLE(), address(governor)); timelock.grantRole(timelock.CANCELLER_ROLE(), address(governor)); // Revoke deployer's admin role timelock.revokeRole(timelock.DEFAULT_ADMIN_ROLE(), msg.sender); ``` ## Proposal Creation and Execution ```solidity // Create proposal address[] memory targets = new address[](1); uint256[] memory values = new uint256[](1); bytes[] memory calldatas = new bytes[](1); targets[0] = address(treasury); values[0] = 0; calldatas[0] = abi.encodeCall(Treasury.transfer, (recipient, amount)); uint256 proposalId = governor.propose(targets, values, calldatas, "Fund development team"); // Vote (after votingDelay) governor.castVote(proposalId, 1); // 0=Against, 1=For, 2=Abstain // Queue (after votingPeriod, if succeeded) governor.queue(targets, values, calldatas, keccak256("Fund development team")); // Execute (after timelock delay) governor.execute(targets, values, calldatas, keccak256("Fund development team")); ``` ## Governance Token with Votes ```solidity import {ERC20Votes} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol"; import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; contract GovToken is ERC20, ERC20Permit, ERC20Votes { constructor() ERC20("GovToken", "GOV") ERC20Permit("GovToken") {} // Users must delegate to activate voting power (even self-delegate) // token.delegate(msg.sender) to self-delegate } ``` ## Parameter Guidelines | Parameter | Conservative | Moderate | Aggressive | |-----------|-------------|----------|------------| | Voting Delay | 2 days | 1 day | 1 block | | Voting Period | 2 weeks | 1 week | 3 days | | Proposal Threshold | 1% supply | 0.1% supply | 0 | | Quorum | 10% supply | 4% supply | 2% supply | | Timelock Delay | 7 days | 2 days | 1 day | ## Checklist - [ ] Token holders must delegate (self-delegate) to activate voting power - [ ] Timelock admin role revoked from deployer after setup - [ ] Governor has PROPOSER and CANCELLER roles on timelock - [ ] Quorum fraction is appropriate for expected participation - [ ] Voting delay gives time for delegation before voting starts - [ ] Proposal description is hashed consistently for queue/execute - [ ] Test full lifecycle: propose -> vote -> queue -> execute - [ ] Consider emergency mechanisms (guardian multisig as canceller)
Voir sur GitHub