Compound 治理

Governance开发者文档

## 介绍 Compound 协议由 COMP Token 持有者管理和升级,使用三个不同的组件; COMP Token、治理模块(Governor Alpha)和 Timelock。这些合约一起,允许社区通过 cToken 或 Comproller 的管理功能提出、投票和实时更改。提案可以包括调整利率模型,到增加对新资产的支持等改变。 任何授权超过 10 万 COMP Token 的地址都可以提出治理活动,这些活动都是可执行的代码。提案产生后,社区可以在 3 天的投票期内提交投票。如果投票获得多数、且至少 40 万票以上,就会在 Timlock 中排队,2 天后可以实施。 ![image.png](https://img.learnblockchain.cn/attachments/2021/11/SuUUgiG761828cb5bc421.png) ## COMP COMP 是一个 [ERC-20](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md) 代币,允许所有者将投票权委托给任何地址,包括自己的地址。所有者的代币余额会自动调整被委托人的投票权。 ## 委托(Delegate) 将发送者的投票数委托给被委托人。用户每次可以委托给一个地址,被委托人的投票数相当于用户账号的 COMP 代币余额。投票将从当前区块开始进行委托,直到发送者再次委托或者转移其 COMP。 **COMP** ``` 1 function delegate(address delegatee) ``` - delegatee : 发送者希望委托投票的地址; - msg.sender : 试图委托投票的 COMP 代币持有者的地址; - 返回值 : 无返回值,错误时恢复。 **Solidity** ``` 1 Comp comp = Comp(0x123...); // contract address 2 comp.delegate(delegateeAddress); ``` **Web3 1.2.6** ``` 1 const tx = await comp.methods.delegate(delegateeAddress).send({ from: sender }); ``` ## 签名委托(Delegate By Signature) Delegate 投票从签名者到被委托人。这种方法与 Delegate 的目的相同,但它可以离线签名参与Compound 治理投票授权。有关如何创建离线签名的更多细节,请查看 [EIP-712](https://eips.ethereum.org/EIPS/eip-712)。 **COMP** ``` 1 function delegateBySig(address delegateeAddress,uint256 nonce,uint256 expiry,uint256 v,uint256 r,uint256 s); ``` - delegatee : 发送者希望委托投票的地址; - nonce : 合约状态要求与签名相匹配。这一点可以从合同的公共 nonce 映射中检索; - expiry : 签名过期时间。以 unix epoch (uint) 后的秒数表示的区块时间戳; - v : 签名恢复字节; - r : ECDSA 签名对的一部分; - s : ECDSA 签名对的一部分; - 返回值 : 无,错误时恢复。 **Solidity** ``` 1 Comp comp = Comp(0x123...); // contract address 2 comp.delegateBySig(delegateeAddress, nonce, expiry, v, r, s); ``` **Web3 1.2.6** ``` 1 const tx = await comp.methods.delegateBySig(delegateeAddress, nonce, expiry, v, r, s).send({}); ``` ## 获取当前投票数 获取一个账户当前区块的票数余额。 **COMP** ``` 1 function getCurrentVotes(address account) returns (uint96) ``` - account : 检索票数的账户地址; - RETURN : 票数(整型)。 **Solidity** ``` 1 Comp comp = Comp(0x123...); // contract address 2 uint votes = comp.getCurrentVotes(0xabc...); ``` **Web3 1.2.6** ``` 1 const account = '0x123...'; // contract address 2 const votes = await comp.methods.getCurrentVotes(account).call(); ``` ## 获取先前投票数 获取一个账户在特定区块上的投票数。传入的区块高度必须是最终确定的区块,否则函数将revert。 **COMP** ``` 1 function getPriorVotes(address account, uint blockNumber) returns (uint96) ``` - account : 检索先前的投票数的账户地址; - blockNumber : 取回之前的票数的区块高度; - 返回值 : 先前投票数; **Solidity** ``` 1 Comp comp = Comp(0x123...); // contract address 2 uint priorVotes = comp.getPriorVotes(account, blockNumber); ``` **Web3 1.2.6** ``` 1 const priorVotes = await comp.methods.getPriorVotes(account, blockNumber).call(); ``` ## Governor Alpha Governor Alpha 是协议的治理模块;它允许超过 10 万 COMP 代币的地址提出修改建议。在提案开始时,手握投票权(通过调用 getpriorvotes 方法)的地址可以在 3 天的投票期内提交投票。如果提取被投了多数,且至少有 40 万票,则会在 Timelock 中排队,2 两天后实施。 Govern Alpha 合约包含一个守卫者地址,由 Compound 团队控制,可以取消提案,或在紧急情况下禁用治理模块。在最初的沙盒期后,守护者可以放弃权利,标志着 COMP 代币持有者开始完全控制。 ## 法定投票数(Quorum Votes) 成功支持一项提案的最低票数要求。 **Governor Alpha** ``` 1 function quorumVotes() public pure returns (uint) ``` - 返回值 : 成功支持一项提案的最低票数。 **Solidity** ``` 1GovernorAlpha gov = GovernorAlpha(0x123...); // contract address 2 uint quorum = gov.quorumVotes(); ``` **Web3 1.2.6** ``` 1 const quorum = await gov.methods.quorumVotes().call(); ``` ## 提案门槛(Proposal Threshold) 账户创建一个提案所需的最低票数; **Governor Alpha** ``` 1 function proposalThreshold() returns (uint) ``` - 返回值ETURN : 账户创建一个提案所需的最低票数。 **Solidity** ``` 1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address 2 uint threshold = gov.proposalThreshold(); ``` **Web3 1.2.6** ``` 1 const threshold = await gov.methods.proposalThreshold().call(); ``` ## 提案最大操作量(Proposal Max Operations) 提案中可以包含的最大操作数量。操作是指提案成功并执行时将进行的函数调用。 **Governor Alpha** ``` 1 function proposalMaxOperations() returns (uint) ``` - 返回值 : 提案中可以包含的最大操作数量。 **Solidity** ``` 1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address 2 uint operations = gov.proposalMaxOperations(); ``` **Web3 1.2.6** ``` 1 const operations = await gov.methods.proposalMaxOperations().call(); ``` ## 投票延迟(Voting Delay) 在对一个提案投票前需要等到的以太坊区块数。当创建一个提案时,该值会被添加到当前区块高度上。 **Governor Alpha** ``` 1function votingDelay() returns (uint) ``` - 返回值:在对一个提案投票前需要等到的以太坊区块数。 **Solidity** ``` 1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address 2 uint blocks = gov.votingDelay(); ``` **Web3 1.2.6** ``` 1 const blocks = await gov.methods.votingDelay().call(); ``` ## 投票期(Voting Period) 以以太坊区块为单位,对提案进行投票的持续时间。 **Governor Alpha** ``` 1 function votingPeriod() returns (uint) ``` - RETURN : 对提案进行投票的持续时间。 **Solidity** ``` 1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address 2 uint blocks = gov.votingPeriod(); ``` **Web3 1.2.6** ``` 1 const blocks = await gov.methods.votingPeriod().call(); ``` ## 提案(Propose) 创建一个提案来改变协议。比如:一个提案能在 Comproller 上设置 cToken 的利率模型或者风险参数。 提案将委托投票人进行投票表决。如果在投票期结束前有足够的支持,提案将被自动颁布。已颁布的提案将在 Compound Timelock 合约中排队并执行。 发送者在紧邻的前一个区块中持有的 COMP 代币必须超过当前的提案阈值(proposalThreshold)。如果阈值是 10 万 COMP 代币,则发送者必须被委托超过所有 COMP 的 1% 才能创建一个提案。提案最多有 10 个操作(基于 proposalMaxOperations() )。 如果提案者当前有待处理或活动中的提案,则他们不能创建另一个提案。不可能在同一个区块中排队两个相同的操作(由于 Timelock 中的限制)。因此一个提案中的操作必须是唯一的,共享一个相同操作的唯一提案必须在不同的区块中排队。 **Governor Alpha** ``` 1 function propose(address[] memory targets, uint[] memory values, string[] memory signatures, bytes[] memory calldatas, string memory description) returns (uint) ``` - targets : 在提案执行过程中,将被调用的目标地址的有序列表。这个数组的长度必须和这个方法中所有其他数组参数的长度相同; - values : 在提案执行过程中要传递给调用的值(即msg.value)的有序列表。这个数组的长度必须和这个方法中所有其他数组参数的长度相同; - signatures : 提案执行过程中要传递的方法签名的有序列表。这个数组的长度必须和这个方法中所有其他数组参数的长度相同; - calldatas : 在提案执行过程中要传递给每个方法调用的数据的有序列表。这个数组必须和这个方法中所有其他数组参数的长度相同; - description : 对该提案的可读性说明及其将作出的修改; - 返回值 : 新创建的提案 ID。 **Solidity** ``` 1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address 2 uint proposalId = gov.propose(targets, values, signatures, calldatas, description); ``` **Web3 1.2.6** ``` 1const tx = gov.methods.propose(targets, values, signatures, calldatas, description).send({ from: sender }); ``` ## 队列(Queue) 提案通过后,任何地址可以调用 queue 方法将提案转移到 Timelock 队列中。提案只有在成功通过后,才能被排队。 **Governor Alpha** ``` 1 function queue(uint proposalId) ``` - proposalId : 已通过的提案 ID; - 返回值 : 无,错误时将 revert。 **Solidity** ``` 1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address 2 gov.queue(proposalId); ``` **Web3 1.2.6** ``` 1 const tx = gov.methods.queue(proposalId).send({ from: sender }); ``` ## 执行(Execute) 在 Timelock 延迟期之后,任何账户都可以调用 execu 方法将提案中的更改应用到目标合约中。这将调用提案中描述的每一个操作。 这个功能是可支付(payable)的,所以 Timelock 合约可以调用提案中选择的可支付功能。例如,A 提案可以 像cETH 一样在市场上添加准备金,设置 cToken 的利率模型,或者在 Comptroller上设置风险参数。 **Governor Alpha** ``` 1function execute(uint proposalId) payable returns (uint) ``` - proposalId : 要执行的成功提案 ID; - 返回值 : 无,错误时将 revert。 **Solidity** ``` 1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address 2 gov.execute(proposalId).value(999).gas(999)(); ``` **Web3 1.2.6** ``` 1 const tx = gov.methods.execute(proposalId).send({ from: sender, value: 1 }); ``` ## 取消(Cancel) 取消尚未执行的提案。除非提案人没有维持创建提案所需的委托量,否则监护人是唯一可以执行取消的人。如果提案人的委托人数没有超过提案的阈值,任何人都可以取消该提案。 **Governor Alpha** ``` 1 function cancel(uint proposalId) ``` - proposalId : 要取消的提案 ID。提案不能重复取消。 - RETURN : 无,错误时 revert。 **Solidity** ``` 1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address 2 gov.cancel(proposalId); ``` **Web3 1.2.6** ``` 1 const tx = gov.methods.cancel(proposalId).send({ from: sender }); ``` ## 获取操作(Get Actions) 获取所选提案的操作列表。传递一个提案 ID,获取该提案的目标对象、值、签名和调用数据。 **Governor Alpha** ``` 1 function getActions(uint proposalId) returns (uint proposalId) public view returns (address[] memory targets, uint[] memory values, string[] memory signatures, bytes[] memory calldatas) ``` - proposalId : 拟获取操作的提案 ID。 - RETURN : 如果提案 ID 非法,则 revert 。否则成功时返回以下 4 个 参考信息: 1. 提案调用的合约地址数组; 2. 提案中使用的值 - 无符号整数数组; 3. 提案签名的字符串数组; 4. 提案的 calldata 字节数组。 **Solidity** ``` 1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address 2 uint proposalId = 123; 3 (address[] memory targets, uint[] memory values, string[] memory signatures, bytes[] memory calldatas) = gov.getActions(proposalId); ``` **Web3 1.2.6** ``` 1 const {0: targets, 1: values, 2: signatures, 3: calldatas} = gov.methods.getActions(proposalId).call(); ``` ## 获取回执(Get Receipt) 获得指定投票者的提案选票。 **Governor Alpha** ``` 1 function getReceipt(uint proposalId, address voter) returns (Receipt memory) ``` - proposalId : 提案ID,以获取投票者的选票收据; - voter : 提案投票者的账户地址; - RETURN : 错误时 revert。成功时返回投票者地址的选票收据结构数据。 **Solidity** ``` 1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address 2 Receipt ballot = gov.getReceipt(proposalId, voterAddress); ``` **Web3 1.2.6** ``` 1 const proposalId = 11; 2 const voterAddress = '0x123...'; 3 const result = await gov.methods.getReceipt(proposalId, voterAddress).call(); 4 const { hasVoted, support, votes } = result; ``` ## 获取提案状态(State) 获取指定提案的提案状态。返回值 ProposalState 是一个 Governor Alpha 合约中定义的枚举类型。 **Governor Alpha** ``` 1 function state(uint proposalId) returns (ProposalState) ``` - proposalId : 提案ID,以获得其状态; - 返回值 : 枚举类型 ProposalState。类型有:Pending(等待中)、Active(活动中)、 Canceled(已取消)、Defeated(已败北)、 Succeeded(已成功)、Queued(已排队)、Expired(已过期)和Executed(已执行)。 **Solidity** ``` 1 overnorAlpha gov = GovernorAlpha(0x123...); // contract address 2 GovernorAlpha.ProposalState state = gov.state(123); ``` **Web3 1.2.6** ``` 1 const proposalStates = ['Pending', 'Active', 'Canceled', 'Defeated', 'Succeeded', 'Queued', 'Expired', 'Executed']; 2 const proposalId = 123; 3 result = await gov.methods.state(proposalId).call(); 4 const proposalState = proposalStates[result]; ``` ## 投票(Cast Vote) 对某项提案进行投票。该账户的表决权重取决于该账户在提案开始生效时的表决权重。 **Governor Alpha** ``` 1 function castVote(uint proposalId, bool support) ``` - proposalId : 提案ID,以进行投票; - support : 布尔值,赞同提案为 true ,反对为 false; - RETURN : 无返回值,错误时 revert。 **Solidity** ``` 1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address 2 gov.castVote(proposalId, true); ``` **Web3 1.2.6** ``` 1 const tx = gov.methods.castVote(proposalId, false).send({ from: sender }); ``` ## 通过签名投票(Cast Vote By Signature) 对某项提案进行投票。该账户的投票权重由该账户在该提案状态生效时的投票权重决定。此方法的目的与 "cast vote "相同,但它可以让脱机签名参与 Compound 治理投票。有关如何创建离线签名的详细信息,请查看 EIP-712。 **Governor Alpha** ``` 1 function castVoteBySig(uint proposalId, bool support, uint8 v, bytes32 r, bytes32 s) ``` - proposalId : 提案ID,以进行投票; - support : 布尔值,赞同提案为 true ,反对为 false; - v : 签名恢复字节; - r : ECDSA 签名对的一部分; - s : ECDSA 签名对的一部分; - 返回值 : 无,错误时恢复。 **Solidity** ``` 1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address 2 gov.castVoteBySig(proposalId, true, v, r, s); ``` **Web3 1.2.6** ``` 1 const tx = await gov.methods.castVoteBySig(proposalId, false, v, r, s).send({}); ``` ## 时间锁(Timelock) 每个 cToken 合约和 Comptroller 合约都允许 Timelock 地址修改。Timelock 合约可以修改系统参数、逻辑和合约,以 "延迟时间、选择退出 " 的升级模式进行修改。 Timelock 有一个 2 天的最小延迟时间硬性规定,这是治理行动的最小通知时间。每项拟采取的治理行动,都会在公告后至少 2 天内公布。重大升级,如变更风险系统等,可能会有 14 天的延迟时间。 时间锁由治理模块控制;待定和已完成的治理行动可以在[时间锁仪表板](https://app.compound.finance/timelock)上监控。 ## 暂停守护者(Pause Guardian) Comptroller 合约指定了一个能够禁用协议功能的暂停守护者地址。暂停守护者只有在出现不可预见的漏洞时才会使用,暂停守护者只有一种能力:禁用一组选定的功能。Mint、Borrow、Borrow、Transfer 和 Liquidate。暂停守护者不能解除一个动作,也不能阻止用户调用赎回、偿还借款以平仓和退出协议。 目前,Compound 团队控制了暂停守护者的地址。

介绍

Compound 协议由 COMP Token 持有者管理和升级,使用三个不同的组件; COMP Token、治理模块(Governor Alpha)和 Timelock。这些合约一起,允许社区通过 cToken 或 Comproller 的管理功能提出、投票和实时更改。提案可以包括调整利率模型,到增加对新资产的支持等改变。

任何授权超过 10 万 COMP Token 的地址都可以提出治理活动,这些活动都是可执行的代码。提案产生后,社区可以在 3 天的投票期内提交投票。如果投票获得多数、且至少 40 万票以上,就会在 Timlock 中排队,2 天后可以实施。

Compound 治理插图

COMP

COMP 是一个 ERC-20 代币,允许所有者将投票权委托给任何地址,包括自己的地址。所有者的代币余额会自动调整被委托人的投票权。

委托(Delegate)

将发送者的投票数委托给被委托人。用户每次可以委托给一个地址,被委托人的投票数相当于用户账号的 COMP 代币余额。投票将从当前区块开始进行委托,直到发送者再次委托或者转移其 COMP。

COMP

1 function delegate(address delegatee)
  • delegatee : 发送者希望委托投票的地址;
  • msg.sender : 试图委托投票的 COMP 代币持有者的地址;
  • 返回值 : 无返回值,错误时恢复。

Solidity

1 Comp comp = Comp(0x123...); // contract address
2 comp.delegate(delegateeAddress);

Web3 1.2.6

1 const tx = await comp.methods.delegate(delegateeAddress).send({ from: sender });

签名委托(Delegate By Signature)

Delegate 投票从签名者到被委托人。这种方法与 Delegate 的目的相同,但它可以离线签名参与Compound 治理投票授权。有关如何创建离线签名的更多细节,请查看 EIP-712。

COMP

1 function delegateBySig(address delegateeAddress,uint256 nonce,uint256 expiry,uint256 v,uint256 r,uint256 s);
  • delegatee : 发送者希望委托投票的地址;
  • nonce : 合约状态要求与签名相匹配。这一点可以从合同的公共 nonce 映射中检索;
  • expiry : 签名过期时间。以 unix epoch (uint) 后的秒数表示的区块时间戳;
  • v : 签名恢复字节;
  • r : ECDSA 签名对的一部分;
  • s : ECDSA 签名对的一部分;
  • 返回值 : 无,错误时恢复。

Solidity

1 Comp comp = Comp(0x123...); // contract address
2 comp.delegateBySig(delegateeAddress, nonce, expiry, v, r, s);

Web3 1.2.6

1 const tx = await comp.methods.delegateBySig(delegateeAddress, nonce, expiry, v, r, s).send({});

获取当前投票数

获取一个账户当前区块的票数余额。

COMP

1 function getCurrentVotes(address account) returns (uint96)
  • account : 检索票数的账户地址;
  • RETURN : 票数(整型)。

Solidity

1 Comp comp = Comp(0x123...); // contract address
2 uint votes = comp.getCurrentVotes(0xabc...);

Web3 1.2.6

1 const account = '0x123...'; // contract address
2 const votes = await comp.methods.getCurrentVotes(account).call();

获取先前投票数

获取一个账户在特定区块上的投票数。传入的区块高度必须是最终确定的区块,否则函数将revert。

COMP

1 function getPriorVotes(address account, uint blockNumber) returns (uint96)
  • account : 检索先前的投票数的账户地址;
  • blockNumber : 取回之前的票数的区块高度;
  • 返回值 : 先前投票数;

Solidity

1 Comp comp = Comp(0x123...); // contract address
2 uint priorVotes = comp.getPriorVotes(account, blockNumber);

Web3 1.2.6

1 const priorVotes = await comp.methods.getPriorVotes(account, blockNumber).call();

Governor Alpha

Governor Alpha 是协议的治理模块;它允许超过 10 万 COMP 代币的地址提出修改建议。在提案开始时,手握投票权(通过调用 getpriorvotes 方法)的地址可以在 3 天的投票期内提交投票。如果提取被投了多数,且至少有 40 万票,则会在 Timelock 中排队,2 两天后实施。

Govern Alpha 合约包含一个守卫者地址,由 Compound 团队控制,可以取消提案,或在紧急情况下禁用治理模块。在最初的沙盒期后,守护者可以放弃权利,标志着 COMP 代币持有者开始完全控制。

法定投票数(Quorum Votes)

成功支持一项提案的最低票数要求。

Governor Alpha

1 function quorumVotes() public pure returns (uint)
  • 返回值 : 成功支持一项提案的最低票数。

Solidity

1GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2 uint quorum = gov.quorumVotes();

Web3 1.2.6

1 const quorum = await gov.methods.quorumVotes().call();

提案门槛(Proposal Threshold)

账户创建一个提案所需的最低票数;

Governor Alpha

1 function proposalThreshold() returns (uint)
  • 返回值ETURN : 账户创建一个提案所需的最低票数。

Solidity

1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2 uint threshold = gov.proposalThreshold();

Web3 1.2.6

1 const threshold = await gov.methods.proposalThreshold().call();

提案最大操作量(Proposal Max Operations)

提案中可以包含的最大操作数量。操作是指提案成功并执行时将进行的函数调用。

Governor Alpha

1 function proposalMaxOperations() returns (uint)
  • 返回值 : 提案中可以包含的最大操作数量。

Solidity

1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2 uint operations = gov.proposalMaxOperations();

Web3 1.2.6

1 const operations = await gov.methods.proposalMaxOperations().call();

投票延迟(Voting Delay)

在对一个提案投票前需要等到的以太坊区块数。当创建一个提案时,该值会被添加到当前区块高度上。

Governor Alpha

1function votingDelay() returns (uint)
  • 返回值:在对一个提案投票前需要等到的以太坊区块数。

Solidity

1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2 uint blocks = gov.votingDelay();

Web3 1.2.6

1 const blocks = await gov.methods.votingDelay().call();

投票期(Voting Period)

以以太坊区块为单位,对提案进行投票的持续时间。

Governor Alpha

1 function votingPeriod() returns (uint)
  • RETURN : 对提案进行投票的持续时间。

Solidity

1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2 uint blocks = gov.votingPeriod();

Web3 1.2.6

1 const blocks = await gov.methods.votingPeriod().call();

提案(Propose)

创建一个提案来改变协议。比如:一个提案能在 Comproller 上设置 cToken 的利率模型或者风险参数。

提案将委托投票人进行投票表决。如果在投票期结束前有足够的支持,提案将被自动颁布。已颁布的提案将在 Compound Timelock 合约中排队并执行。

发送者在紧邻的前一个区块中持有的 COMP 代币必须超过当前的提案阈值(proposalThreshold)。如果阈值是 10 万 COMP 代币,则发送者必须被委托超过所有 COMP 的 1% 才能创建一个提案。提案最多有 10 个操作(基于 proposalMaxOperations() )。

如果提案者当前有待处理或活动中的提案,则他们不能创建另一个提案。不可能在同一个区块中排队两个相同的操作(由于 Timelock 中的限制)。因此一个提案中的操作必须是唯一的,共享一个相同操作的唯一提案必须在不同的区块中排队。

Governor Alpha

1 function propose(address[] memory targets, uint[] memory values, string[] memory signatures, bytes[] memory calldatas, string memory description) returns (uint)
  • targets : 在提案执行过程中,将被调用的目标地址的有序列表。这个数组的长度必须和这个方法中所有其他数组参数的长度相同;
  • values : 在提案执行过程中要传递给调用的值(即msg.value)的有序列表。这个数组的长度必须和这个方法中所有其他数组参数的长度相同;
  • signatures : 提案执行过程中要传递的方法签名的有序列表。这个数组的长度必须和这个方法中所有其他数组参数的长度相同;
  • calldatas : 在提案执行过程中要传递给每个方法调用的数据的有序列表。这个数组必须和这个方法中所有其他数组参数的长度相同;
  • description : 对该提案的可读性说明及其将作出的修改;
  • 返回值 : 新创建的提案 ID。

Solidity

1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2 uint proposalId = gov.propose(targets, values, signatures, calldatas, description);

Web3 1.2.6

1const tx = gov.methods.propose(targets, values, signatures, calldatas, description).send({ from: sender });

队列(Queue)

提案通过后,任何地址可以调用 queue 方法将提案转移到 Timelock 队列中。提案只有在成功通过后,才能被排队。

Governor Alpha

1 function queue(uint proposalId)
  • proposalId : 已通过的提案 ID;
  • 返回值 : 无,错误时将 revert。

Solidity

1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2 gov.queue(proposalId);

Web3 1.2.6

1 const tx = gov.methods.queue(proposalId).send({ from: sender });

执行(Execute)

在 Timelock 延迟期之后,任何账户都可以调用 execu 方法将提案中的更改应用到目标合约中。这将调用提案中描述的每一个操作。

这个功能是可支付(payable)的,所以 Timelock 合约可以调用提案中选择的可支付功能。例如,A 提案可以 像cETH 一样在市场上添加准备金,设置 cToken 的利率模型,或者在 Comptroller上设置风险参数。

Governor Alpha

1function execute(uint proposalId) payable returns (uint)
  • proposalId : 要执行的成功提案 ID;
  • 返回值 : 无,错误时将 revert。

Solidity

1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2 gov.execute(proposalId).value(999).gas(999)();

Web3 1.2.6

1 const tx = gov.methods.execute(proposalId).send({ from: sender, value: 1 });

取消(Cancel)

取消尚未执行的提案。除非提案人没有维持创建提案所需的委托量,否则监护人是唯一可以执行取消的人。如果提案人的委托人数没有超过提案的阈值,任何人都可以取消该提案。

Governor Alpha

1 function cancel(uint proposalId)
  • proposalId : 要取消的提案 ID。提案不能重复取消。
  • RETURN : 无,错误时 revert。

Solidity

1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2 gov.cancel(proposalId);

Web3 1.2.6

1 const tx = gov.methods.cancel(proposalId).send({ from: sender });

获取操作(Get Actions)

获取所选提案的操作列表。传递一个提案 ID,获取该提案的目标对象、值、签名和调用数据。

Governor Alpha

1 function getActions(uint proposalId) returns (uint proposalId) public view returns (address[] memory targets, uint[] memory values, string[] memory signatures, bytes[] memory calldatas)
  • proposalId : 拟获取操作的提案 ID。
  • RETURN : 如果提案 ID 非法,则 revert 。否则成功时返回以下 4 个 参考信息:
    1. 提案调用的合约地址数组;
    2. 提案中使用的值 - 无符号整数数组;
    3. 提案签名的字符串数组;
    4. 提案的 calldata 字节数组。

Solidity

1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2 uint proposalId = 123;
3 (address[] memory targets, uint[] memory values, string[] memory signatures, bytes[] memory calldatas) = gov.getActions(proposalId);

Web3 1.2.6

1 const {0: targets, 1: values, 2: signatures, 3: calldatas} = gov.methods.getActions(proposalId).call();

获取回执(Get Receipt)

获得指定投票者的提案选票。

Governor Alpha

1 function getReceipt(uint proposalId, address voter) returns (Receipt memory)
  • proposalId : 提案ID,以获取投票者的选票收据;
  • voter : 提案投票者的账户地址;
  • RETURN : 错误时 revert。成功时返回投票者地址的选票收据结构数据。

Solidity

1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2 Receipt ballot = gov.getReceipt(proposalId, voterAddress);

Web3 1.2.6

1 const proposalId = 11;
2 const voterAddress = '0x123...';
3 const result = await gov.methods.getReceipt(proposalId, voterAddress).call();
4 const { hasVoted, support, votes } = result;

获取提案状态(State)

获取指定提案的提案状态。返回值 ProposalState 是一个 Governor Alpha 合约中定义的枚举类型。

Governor Alpha

1 function state(uint proposalId) returns (ProposalState)
  • proposalId : 提案ID,以获得其状态;
  • 返回值 : 枚举类型 ProposalState。类型有:Pending(等待中)、Active(活动中)、

    Canceled(已取消)、Defeated(已败北)、 Succeeded(已成功)、Queued(已排队)、Expired(已过期)和Executed(已执行)。

Solidity

1 overnorAlpha gov = GovernorAlpha(0x123...); // contract address
2 GovernorAlpha.ProposalState state = gov.state(123);

Web3 1.2.6

1 const proposalStates = ['Pending', 'Active', 'Canceled', 'Defeated', 'Succeeded', 'Queued', 'Expired', 'Executed'];
2 const proposalId = 123;
3 result = await gov.methods.state(proposalId).call();
4 const proposalState = proposalStates[result];

投票(Cast Vote)

对某项提案进行投票。该账户的表决权重取决于该账户在提案开始生效时的表决权重。

Governor Alpha

1 function castVote(uint proposalId, bool support)
  • proposalId : 提案ID,以进行投票;
  • support : 布尔值,赞同提案为 true ,反对为 false;
  • RETURN : 无返回值,错误时 revert。

Solidity

1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2 gov.castVote(proposalId, true);

Web3 1.2.6

1 const tx = gov.methods.castVote(proposalId, false).send({ from: sender });

通过签名投票(Cast Vote By Signature)

对某项提案进行投票。该账户的投票权重由该账户在该提案状态生效时的投票权重决定。此方法的目的与 "cast vote "相同,但它可以让脱机签名参与 Compound 治理投票。有关如何创建离线签名的详细信息,请查看 EIP-712。

Governor Alpha

1 function castVoteBySig(uint proposalId, bool support, uint8 v, bytes32 r, bytes32 s)
  • proposalId : 提案ID,以进行投票;
  • support : 布尔值,赞同提案为 true ,反对为 false;
  • v : 签名恢复字节;
  • r : ECDSA 签名对的一部分;
  • s : ECDSA 签名对的一部分;
  • 返回值 : 无,错误时恢复。

Solidity

1 GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2 gov.castVoteBySig(proposalId, true, v, r, s);

Web3 1.2.6

1 const tx = await gov.methods.castVoteBySig(proposalId, false, v, r, s).send({});

时间锁(Timelock)

每个 cToken 合约和 Comptroller 合约都允许 Timelock 地址修改。Timelock 合约可以修改系统参数、逻辑和合约,以 "延迟时间、选择退出 " 的升级模式进行修改。

Timelock 有一个 2 天的最小延迟时间硬性规定,这是治理行动的最小通知时间。每项拟采取的治理行动,都会在公告后至少 2 天内公布。重大升级,如变更风险系统等,可能会有 14 天的延迟时间。

时间锁由治理模块控制;待定和已完成的治理行动可以在时间锁仪表板上监控。

暂停守护者(Pause Guardian)

Comptroller 合约指定了一个能够禁用协议功能的暂停守护者地址。暂停守护者只有在出现不可预见的漏洞时才会使用,暂停守护者只有一种能力:禁用一组选定的功能。Mint、Borrow、Borrow、Transfer 和 Liquidate。暂停守护者不能解除一个动作,也不能阻止用户调用赎回、偿还借款以平仓和退出协议。

目前,Compound 团队控制了暂停守护者的地址。

区块链技术网。

  • 发表于 2021-03-04 13:47
  • 阅读 ( 160 )
  • 学分 ( 5 )
  • 分类:DeFi
  • 专栏:Compound 研究

评论