這個章節說到”治理“,再去中心化裡很多人想像可以將一些治理的模式寫在智能合約裡面,而現在被嘗試出來較完整的幾個行為來致Compound 所設計的推動決策模型。
OpenZeppelin 基於Compound 設計了共同的核心模組(當然有通過審計和模組化)
這邊先解釋一下 Compound 的框架 如下圖:
流程解釋:
建立提案(待處理2天) → 社區投票(3天) → 投票結束(成功) → 鎖定期(排隊)→ 執行 或 過期
明白了這個架構我們說一下需要哪些串連
首先會有幾個要素:
Governor 核心操作(提案)
GovernorVotes 投票權
GovernorVotesQuorumFraction 投票通過人數
GovernorTimelockControl 時間軸
這點很重要其實要做比較複雜的合約操作建議都是把每個功能分開引入!
開始來看合約:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
**//Governor 操作必須引入**
import "@openzeppelin/contracts/governance/Governor.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorCountingSimple.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol";
contract MyGovernor is Governor, GovernorCountingSimple, GovernorVotes, GovernorVotesQuorumFraction, GovernorTimelockControl {
constructor(IVotes _token, TimelockController _timelock)
Governor("MyGovernor")
GovernorVotes(_token)
GovernorVotesQuorumFraction(4)
GovernorTimelockControl(_timelock)
{}
function votingDelay() public pure override returns (uint256) {
return 1; // 1 block
}
function votingPeriod() public pure override returns (uint256) {
return 45818; // 1 week
}
// The following functions are overrides required by Solidity.
function quorum(uint256 blockNumber)
public
view
override(IGovernor, GovernorVotesQuorumFraction)
returns (uint256)
{
return super.quorum(blockNumber);
}
function state(uint256 proposalId)
public
view
override(Governor, GovernorTimelockControl)
returns (ProposalState)
{
return super.state(proposalId);
}
function propose(address[] memory targets, uint256[] memory values, bytes[] memory calldatas, string memory description)
public
override(Governor, IGovernor)
returns (uint256)
{
return super.propose(targets, values, calldatas, description);
}
function _execute(uint256 proposalId, address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash)
internal
override(Governor, GovernorTimelockControl)
{
super._execute(proposalId, targets, values, calldatas, descriptionHash);
}
function _cancel(address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash)
internal
override(Governor, GovernorTimelockControl)
returns (uint256)
{
return super._cancel(targets, values, calldatas, descriptionHash);
}
function _executor()
internal
view
override(Governor, GovernorTimelockControl)
returns (address)
{
return super._executor();
}
function supportsInterface(bytes4 interfaceId)
public
view
override(Governor, GovernorTimelockControl)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}
合約初始部署
constructor(IVotes _token, TimelockController _timelock)
Governor("MyGovernor")
GovernorVotes(_token)
GovernorVotesQuorumFraction(4)
GovernorTimelockControl(_timelock)
{}
**我們會發現 _token & _timelock,這兩個我們很明白如果要部署Governor合約必須要有
token 和 timelock 兩個合約地址才能部署
也就是ERC20.sol+GovernorTimelockControl.sol**
votingDelay()
投票延遲
<aside> 👉 提案的建立後需要等待區塊數才能啟動允許投票
</aside>
(有點繞口,但就想像是透過鏈上的機制成立),這部分設立時間如果較長。
可以再開始投票之前去設置他們的選票數(一但啟動就不能更改)。
votingPeriod()
提案時間
<aside> 👉 就是投票時間,設定越大投票時間越大
</aside>
假設出塊時間約為 13.14 秒,我們將設置votingDelay = 1 天 = 6570 個塊,votingPeriod = 1 週 = 45992 個塊。
quorum()
人數
<aside> 👉 提案通過所需的最低”Yes”票數
</aside>
state()
提案狀態
<aside> 👉 可以取得目前提案的狀態
</aside>
狀態分四個 Unset 、 Pending 、 Ready 、 Done
propose()
提案
<aside> 👉 提出提案(建立)
</aside>
_execute()
執行
<aside> 👉 執行提案,提案必須超過所需的時間鎖定延遲
</aside>
_cancel()
取消
<aside> 👉 取消提案,如果設定的啟動閾值沒過,則取消這個提案
</aside>