导图社区 Compound治理合约
compound的治理合约,alpha版本,事件/结构/方法的结构化整理。
编辑于2020-10-12 05:58:33COMP Governor Alpha
合约描述
comp的治理合约, 定义了创建合约,投票等关键方法和事件
导入
pragma solidity ^0.5.16;
pragma experimental ABIEncoderV2;
还处于实验期的AVIEncoderV2
接口
TimelockInterface
delay()
GRACE_PERIOD()
acceptAdmin()
queuedTransactions(bytes32 hash)
queueTransaction(address target, uint value, string calldata signature, bytes calldata data, uint eta)
cancelTransaction(address target, uint value, string calldata signature, bytes calldata data, uint eta)
executeTransaction(address target, uint value, string calldata signature, bytes calldata data, uint eta)
CompInterface
getPriorVotes(address account, uint blockNumber)
常量
合约名字
string public constant name = "Compound Governor Alpha";
使提案通过需要的票数
方法名: quorumVotes()
返回值: 400000e18
400,000 = 4% of Comp
成为提案发起者需要的资金
方法名: proposalThreshold()
返回值: 100000e18
100,000 = 1% of Comp
提案中最大操作数
方法名: proposalMaxOperations()
返回值: 10
提案发起后多久可以开始投票
方法名: votingDelay()
返回值: 1
1个区块
提案持续时间
方法名: votingPeriod()
返回值: 17280
三天所需的区块数,按照15s一个区块来估算
时间锁的地址 timelock
结构: TimelockInterface
治理代币的地址 comp
结构: CompInterface
治理者的地址 guardian
address
合约域的EIP721typehash
keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");
合约投票结构的IP721typehash
bytes32 public constant BALLOT_TYPEHASH = keccak256("Ballot(uint256 proposalId,bool support)");
结构
Proposal (提案本体)
uint id
address proposer
发起提案的人
uint eta
提案可以执行的时间戳
address[] targets
被调用目标的有序列表
uint[] values
调用时要传入的msg.value的有序列表
string[] signatures;
调用时用到签名的有序列表
bytes[] calldatas;
调用数据的有序列表
uint startBlock;
uint endBlock;
uint forVotes;
当前赞成票数
uint againstVotes;
当前反对票数
bool canceled;
提案是否被取消
bool executed;
提案是否被执行
mapping (address => Receipt) receipts;
选票数据
Receipt (投票记录)
bool hasVoted;
是否进行了投票?
bool support;
是否赞成提案
uint96 votes;
投票者所投的票数
枚举
ProposalState(提案可能所处的状态)
Pending
Active
Canceled
Defeated
Succeeded
Queued
Expired
Executed
映射
所有提案
mapping (uint => Proposal) public proposals;
每一个提案发起者的最后一个提案
mapping (address => uint) public latestProposalIds;
事件
ProposalCreated
合约创建
参数
uint id
address proposer
address[] targets
uint[] values
string[] signatures
bytes[] calldatas
uint startBlock
uint endBlock
string description
VoteCast
对提案进行投票时发出的事件
参数
address voter
uint proposalId
bool support
uint votes
ProposalCanceled
被取消的提案
uint id
ProposalQueued
在时间锁中排队时的事件
参数
uint id
uint eta
ProposalExecuted
在时间锁中执行提案发出的事件
uint id
方法
构造方法
描述
给时间锁/comp治理合约以及治理负责人赋初值
参数
address timelock_
address comp_
address guardian_
管理员方法
校验:
必须是合约管理员
msg.sender == guardian
__acceptAdmin()
参数
无
描述
timelock.acceptAdmin();
设置合约管理员
__abdicate()
参数
无
描述
guardian = address(0);
放弃合约
__queueSetTimelockPendingAdmin
参数
address newPendingAdmin
uint eta
描述
准备管理员交接
__executeSetTimelockPendingAdmin
参数
address newPendingAdmin
uint eta
描述
执行管理员交接
内部方法
_queueOrRevert
描述
将提案成功后要调用的action放入时间锁的事务队列中
校验
必须是新的action
_castVote
见castVote
内部工具方法
sub256
add256
getChainId
外部工具方法
state
描述
获取提案状态
view
参数
uint proposalId
返回值
ProposalState 枚举
校验
当前最新的提案id要大于查询id
流程
如果proposal.canceled则直接返回Canceled
如果当前区块小于等于startBlock则返回Pending
如果当前区块小于等于endBlock则返回Active
如果支持票数小于反对票或者支持票数不足额定值返回Defeated
如果提案执行时间戳为0 则返回Succeeded
如果提案已经执行返回Executed
如果当前时间戳大于执行时间戳+宽限期 则返回Executed
此外返回Queued
getActions
描述
view
获得提案action
getReceipt
描述
view
获得投票者在提案投的票
参数
id
voter
返回值
Receipt
propose
描述
发起提案
参数
address[] memory targets
uint[] memory values
string[] memory signatures
bytes[] memory calldatas
string memory description
返回值
uint newProposal.id
流程
校验
1. 投票数大于阈值
comp.getPriorVotes(msg.sender, sub256(block.number, 1)) > proposalThreshold()
2.参数数组要等长
targets.length == values.length && targets.length == signatures.length && targets.length == calldatas.length
3.参数target数组不为空
targets.length != 0
4.参数target数组长度小于等于提案最大操作数
targets.length <= proposalMaxOperations()
5.如果发起者(msg.sender)发起过提案, 则要求上一次的提案不在活跃和等待的状态
构造一个提案对象
当前区块高度 +1 生成startBlock
startBlock + 投票持续时间常数 生成endBlock
proposalCount++ 作为提案id
对象装入proposals映射中
latestProposalIds 添加 sender => id
发起ProposalCreated事件
返回 id
queue
描述
将提案加入执行队列
参数
uint proposalId
返回值
无
流程
校验
提案状态必须为Succeded
生成投票成功的时间eta
uint eta = add256(block.timestamp, timelock.delay());
对提案中要调用的几个数组属性遍历,把每个任务放入时间锁执行事务的队列中
_queueOrRevert(proposal.targets[i], proposal.values[i], proposal.signatures[i], proposal.calldatas[i], eta);
发ProposalQueued事件
execute
描述
payable
执行提案
参数
uint proposalId
校验
. 提案状态为Queued
state(proposalId) == ProposalState.Queued
流程
逐个执行提案的action
timelock.executeTransaction.value(proposal.values[i])(proposal.targets[i], proposal.values[i], proposal.signatures[i], proposal.calldatas[i], proposal.eta);
发ProposalExecuted事件
cancel
描述
取消提案
参数
uint proposalId
校验
1.提案不能是已经执行了的
state != ProposalState.Executed题
2. 方法调用者是治理合约管理员或者投票已经通过
msg.sender == guardian || comp.getPriorVotes(proposal.proposer, sub256(block.number, 1)) < proposalThreshold()
流程
取消所有的action
触发ProposalCanceled事件
castVote
描述
调用_castVote
投票方法
参数
sender
proposalId
bool support
校验
提案必须在活跃状态
state(proposalId) == ProposalState.Active
保证投票者还未投票
receipt.hasVoted == false
流程
获得累计投票数量
根据是否支持提案, 将投票数量累加进支持或者反对的池子里
修改投票者在提案中的记录
hasVoted = true
support = support
votes= votes
触发VoteCast事件
castVoteBySig
描述
签名的方式调用投票
参数
提案id
support
uint8 v
bytes32 r
bytes32 s
返回值
无
校验
组装并校验签名
调用_castVote