Compound系列(2)

Posted by Thomas_Xu on 2022-12-05

author:Thomas_Xu

Compound系列(2) 治理

我们都知道很多Defi项目都有治理机制,来看看Compound的治理有什么独特之处吧

COMP是Coumpound发行的官方代币。而COMP是一个治理代币。Compound作为一个完全去中心化的系统(或者至少是在走向它的路上),基于COMP实现了一个去中心化的治理机制。

什么是Compound治理?

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

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

合约

现在让我们详细研究一下治理合约,包括:

  • 核心治理合约(GovernorAlpha.sol
  • 时间锁合约(Timelock.sol)。
  • 和COMP代币合约本身

Comp.sol

先从最基础的CompToken讲起吧,这其实就是一个普通的ERC-20代币,COMP合约还包括了一些相关的治理方法。

delegate()

用户可以将COMP的投票权委托给另外一个地址。被委托人的投票权是他自己的COMP余额+所有委托给他的COMP余额。

就像以前一样,也存在一个delegateBySig,用于EIP-712离线签名投票:

1
2
3
function delegate(
address delegatee
)

delegateBySig

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

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

getCurrentVotes

获取当前投票数

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

getPriorVotes()

为了获得某个区块号下的投票权,我们可以调用getPriorVotes来检索该值。显然,这只对过去的区块号有效。

1
2
3
4
function getPriorVotes(
address account,
uint blockNumber
) returns (uint96)

重要的函数就这两个,其他的相关函数大家可以自己去看Comp.sol

GovernorAlpha.sol

核心治理合约为GovernorAlpha,它包含了创建和执行提案的所有逻辑。

propose-提案函数

1
2
3
4
5
6
7
8
function propose(
address[] memory targets, // 所执动作作的目标地址。
uint[] memory values, //
要传递给调用的`msg.value`
string[] memory signatures, // 调用的函数签名,例如:`transfer(address, amount)`
bytes[] memory calldatas, // 要传递给函数调用的数据(参数)
string memory description
) returns (uint)
  • target: 所执动作作的目标地址。
  • value: 要传递给调用的msg.value
  • signature: 调用的函数签名,例如:transfer(address, amount)
  • calldata: 要传递给函数调用的数据(参数)

castVote() - 投票函数

对一个提案进行投票。该账户的投票权重由该账户在提案状态生效时委托给它的投票数决定。

还有一个使用EIP-712离线签名投票的方法。它的思路与我们之前讨论的ERC-20-Permit是一样的,可以参考阅读无需gas代币的ERC20-Permit

1
2
3
4
5
6
7
8
9
10
11
function castVote(
uint proposalId,
bool support
)
function castVoteBySig(
uint proposalId,
bool support,
uint8 v,
bytes32 r,
bytes32 s
)

queue() - 加入到执行队列

提案公投成功的条件是:

  • 大多数人投票支持该提案
  • 并且至少有400,000张投票,即≥4%的发行量。

在提案成功后,任何地址都可以调用queue方法,将提案移入Timelock队列。

1
2
3
function queue(
uint proposalId
)

execute() - 执行函数

一旦时间锁定延迟过去,任何人都可以调用执行方法。它将依次运行提案中的每个动作。

1
2
3
function execute(
uint proposalId
)

对于任何动作(target、value、signature、calldata),都通过这样的方式执行:

1
2
bytes memory callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);
(bool success,) = target.call.value(value)(callData);

calldata以函数选择器开始,它是函数签名字符串的哈希值的前四个字节。所以在这里我们只需将结果拼在现有的calldata中,然后在目标地址上进行call调用。

cancel() - 取消提案函数

在极少数情况下,被通过的提案仍然可以被取消。目前,仍然存在一个有权取消任何提案的监护人地址。它目前是由Compound Labs, Inc.自己持有。在未来,这个监护人地址可能会被删除。

如果最初的提议者在加入提案后失去了创建提案所需的COMP代币数量,那么提案也可以被取消。这可以防止有人进行恶意的提案,例如:COMP的价值可能因恶意提案被接受而下降之前立即卖掉他所有的COMP, cancel() 可以防止这样的情况。

1
2
3
function cancel(
uint proposalId
)

state-获取提案状态

1
function state(uint proposalId) returns (ProposalState)
  • proposalId : 提案ID,以获得其状态;

  • 返回值 : 枚举类型 ProposalState。类型有:Pending(等待中)、Active(活动中)、

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

getReceipt-获取提案回执

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

TimeLock.sol

Timelock合约是对提案执行的一个包装。它由以下部分组成:

  • delay(延时):一个提案被接受后,需要等待多少天之后才能被执行。这个时间可以由治理合约改变为2至30天之间。目前设置为2天。
  • 提案执行期限(grace period):在延时到达时间之后,如果超过了grace period期,那么提案将不能再执行,被设置为14天。

所有的函数都是围绕着这两个变量进行的操作


notice

true

This is copyright.

...

...

00:00
00:00