治理 - OpenZeppelin 文档

本文档介绍了用于链上治理的 Governor 合约,它是一个模块化的系统,允许部署类似于 Compound 的 Governor Alpha & Bravo 的链上投票协议。该系统具有高度的可定制性,通过选择不同的模块(如投票模块、计数模块、时间锁扩展等)和实现特定的虚拟函数,可以满足各种治理需求。

治理

此文档在 https://docs.openzeppelin.com/contracts/api/governance 上查看效果更佳

此目录包含链上治理的基本要素。

Governor

Governor 合约的这个模块化系统允许部署类似于 Compound 的 Governor Alpha & Bravo 以及更高级的链上投票协议,因为它能够轻松自定义协议的多个方面。

为了获得指导体验,请使用 Contracts Wizard 设置你的 Governor 合约。<br>有关书面演练,请查看我们的 如何设置链上治理 指南。
  • Governor: 包含所有逻辑和基本要素的核心合约。它是抽象的,需要选择下面每个模块中的一个,或者自定义的模块。

投票模块决定投票权力的来源,有时也决定法定人数。

计数模块决定有效的投票选项。

  • GovernorCountingSimple:简单的投票机制,有 3 个投票选项:反对、赞成和弃权。

  • GovernorCountingFractional:一个更模块化的投票系统,允许用户仅使用其部分投票权进行投票,并在 3 个不同选项(反对、赞成和弃权)之间任意分配该权重。

  • GovernorCountingOverridableGovernorCountingSimple 的扩展版本,允许被委托人在投票进行时覆盖其委托人。必须与 VotesExtended 结合使用。

时间锁扩展为治理决策的执行增加了一个延迟。工作流程被扩展为在执行之前需要一个 queue 步骤。使用这些模块,提案由外部时间锁合约执行,因此时间锁必须持有被治理的资产。

其他扩展可以以多种方式自定义行为或界面。

  • GovernorStorage:将提案详细信息存储在链上,并提供提案的可枚举性。这对于某些 L2 链可能很有用,因为与 calldata 相比,存储成本较低。

  • GovernorSettings:以可以通过治理提案更新的方式管理某些设置(投票延迟、投票期持续时间和提案阈值),而无需升级。

  • GovernorPreventLateQuorum:确保在达到法定人数后有一个最短的投票期,作为针对大型投票者的安全保护。

  • GovernorProposalGuardian:添加一个提案 guardian,可以在提案生命周期的任何阶段取消提案——如果未设置 guardian,则此权限将传递给提案人。

  • GovernorSuperQuorumGovernor 的扩展,具有超级法定人数。符合超级法定人数(并且大多数票数为赞成票)的提案将在提案截止日期之前进入 Succeeded 状态。

除了模块和扩展之外,核心合约还需要实现一些虚拟函数以满足你的特定规范:

  • votingDelay():自提案提交到投票权固定且投票开始的延迟(以 ERC-6372 时钟为单位)。这可以用于在发布提案后强制延迟,以便用户购买 token 或委托其投票。

  • votingPeriod():自提案开始到投票结束的延迟(以 ERC-6372 时钟为单位)。

  • quorum(uint256 timepoint):提案成功所需的法定人数。此函数包含一个 timepoint 参数(参见 ERC-6372),因此法定人数可以随着时间的推移而调整,例如,跟随 token 的 totalSupply

Governor 合约的函数不包含访问控制。如果你想限制访问,你应该通过重载特定函数来添加这些检查。其中,Governor._cancel 默认是内部的,如果需要此功能,你将必须自己公开它(使用正确的访问控制机制)。

核心

IGovernor

import "@openzeppelin/contracts/governance/IGovernor.sol";

Governor 核心的接口。

事件参数缺少 indexed 关键字,以与 GovernorBravo 事件兼容。<br>加粗动事件参数会影响事件的解码方式,可能会破坏现有的索引器。

函数

IERC6372

IERC165

事件

错误

name() → string external

governor 实例的名称(用于构建 EIP-712 域分隔符)。

version() → string external

governor 实例的版本(用于构建 EIP-712 域分隔符)。默认值:"1"

COUNTING_MODE() → string external

castVote 的可能 support 值的描述,以及这些选票的计算方式,旨在 供 UI 使用,以显示正确的投票选项并解释结果。该字符串是一个 URL 编码的键值对序列,每个键值对描述一个方面,例如 support=bravo&quorum=for,abstain

有 2 个标准键:supportquorum

  • support=bravo 指的是投票选项 0 = 反对,1 = 赞成,2 = 弃权,如 GovernorBravo 中所示。

  • quorum=bravo 意味着只有赞成票才计入法定人数。

  • quorum=for,abstain 意味着赞成票和弃权票都计入法定人数。

如果计数模块使用编码的 params,它应该将其包含在 params 键下,并使用描述该行为的唯一名称。例如:

  • params=fractional 可能指的是在赞成/反对/弃权之间按比例分配选票的方案。

  • params=erc721 可能指的是将特定的 NFT 委托进行投票的方案。

该字符串可以被标准的<br>加粗URLSearchParams<br>加粗JavaScript 类解码。
hashProposal(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash) → uint256 external

哈希函数,用于从提案详细信息中(重新)构建提案 ID。

对于所有链下和外部调用,请使用 getProposalId
getProposalId(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash) → uint256 external

用于从提案详细信息中获取提案 ID 的函数。

state(uint256 proposalId) → enum IGovernor.ProposalState external

提案的当前状态,遵循 Compound 的惯例

proposalThreshold() → uint256 external

投票者成为提案者所需的票数。

proposalSnapshot(uint256 proposalId) → uint256 external

用于检索用户的选票和法定人数的时间点。如果使用区块号(如 Compound 的 Comp),则快照在此区块结束时执行。因此,对此提案的投票从下一个区块的开始开始。

proposalDeadline(uint256 proposalId) → uint256 external

投票结束的时间点。如果使用区块号,则投票在此区块结束时结束,因此可以在此区块期间投票。

proposalProposer(uint256 proposalId) → address external

创建提案的帐户。

proposalEta(uint256 proposalId) → uint256 external

排队的提案变为可执行的时间("ETA")。与 proposalSnapshotproposalDeadline 不同,这不使用 governor 时钟,而是依赖于执行者的时钟,该时钟可能不同。在大多数情况下,这将是一个时间戳。

proposalNeedsQueuing(uint256 proposalId) → bool external

提案在执行之前是否需要排队。

votingDelay() → uint256 external

提案创建和投票开始之间的延迟。此持续时间以哪个单位表示取决于此合约使用的时钟(参见 ERC-6372)。

可以增加此延迟,以便用户在提案开始投票之前有时间购买投票权或委托它。

虽然此接口返回一个 uint256,但时间点以 uint48 存储,遵循 ERC-6372 时钟类型。<br>加粗果后续要参与计算,该值应适合 uint48(添加到当前时钟时)。请参见 IERC6372.clock
votingPeriod() → uint256 external

投票开始和投票结束延迟。此持续时间以哪个单位表示取决于此合约使用的时钟 (参见 ERC-6372)。

votingDelay 可以延迟投票的开始。与投票延迟相比,设置投票<br>加粗需要考虑持续时间。
此值在提交提案时存储,以便对该值的可能更改不影响<br>加粗已提交的提案。用于保存它的类型是 uint32。因此,虽然此<br>加粗接口返回一个 uint256,但它返回的值应该适合 uint32。
quorum(uint256 timepoint) → uint256 external

提案成功所需的最低投票数。

timepoint 参数对应于用于计算选票的快照。这允许根据诸如Token在该时间点的 totalSupply 之类的值缩放<br>加粗totalSupply(请参见 ERC20Votes)。
getVotes(address account, uint256 timepoint) → uint256 external

account 在特定 timepoint 的投票权。

注意:这可以通过多种方式实现,例如通过从一个(或多个)ERC20Votes Token中读取委托的余额。

getVotesWithParams(address account, uint256 timepoint, bytes params) → uint256 external

account 在特定 timepoint 的投票权,给定附加的编码参数。

hasVoted(uint256 proposalId, address account) → bool external

返回 account 是否已在 proposalId 上投票。

propose(address[] targets, uint256[] values, bytes[] calldatas, string description) → uint256 proposalId external

创建一个新提案。在 IGovernor.votingDelay 指定的延迟后开始投票,并持续 IGovernor.votingPeriod 指定的持续时间。

发出一个 ProposalCreated 事件。

在提案创建和执行之间,Governor 和 targets 的状态可能会更改。<br>加粗可能是由于第三方对目标合约的操作或其他 governor 提案造成的。<br>加粗例如,此合约的余额可能会更新,或者其访问控制权限可能会被修改,<br>加粗可能会危及提案成功执行的能力(例如,governor 没有足够的<br>加粗价值来支付具有多个转账的提案)。
queue(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash) → uint256 proposalId external

排队一个提案。一些 governor 要求在执行之前执行此步骤。如果排队不是必需的,则此函数可能会还原。 排队提案要求达到法定人数、投票成功并且达到截止日期。

发出一个 ProposalQueued 事件。

execute(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash) → uint256 proposalId external

执行一个成功的提案。这要求达到法定人数、投票成功并且达到截止日期。根据 governor 的不同,可能还需要对提案进行排队并且经过一些延迟。

发出一个 ProposalExecuted 事件。

一些模块可以修改执行的要求,例如通过添加额外的时间锁。
cancel(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash) → uint256 proposalId external

取消一个提案。提案可以由提案人取消,但只能在其处于 Pending 状态时取消,即在投票开始之前。

发出一个 ProposalCanceled 事件。

castVote(uint256 proposalId, uint8 support) → uint256 balance external

投票

发出一个 VoteCast 事件。

castVoteWithReason(uint256 proposalId, uint8 support, string reason) → uint256 balance external

带理由的投票

发出一个 VoteCast 事件。

castVoteWithReasonAndParams(uint256 proposalId, uint8 support, string reason, bytes params) → uint256 balance external

使用理由和附加的编码参数进行投票

发出一个 VoteCastVoteCastWithParams 根据 params 的长度发出事件。

castVoteBySig(uint256 proposalId, uint8 support, address voter, bytes signature) → uint256 balance external

使用投票者的签名进行投票,包括 ERC-1271 签名支持。

发出一个 VoteCast 事件。

castVoteWithReasonAndParamsBySig(uint256 proposalId, uint8 support, address voter, string reason, bytes params, bytes signature) → uint256 balance external

使用投票者的签名,包括 ERC-1271 签名支持,对带有理由和附加编码参数的投票进行投票。

发出一个 VoteCastVoteCastWithParams 根据 params 的长度发出事件。

ProposalCreated(uint256 proposalId, address proposer, address[] targets, uint256[] values, string[] signatures, bytes[] calldatas, uint256 voteStart, uint256 voteEnd, string description) event

在创建提案时发出。

ProposalQueued(uint256 proposalId, uint256 etaSeconds) event

在提案排队时发出。

ProposalExecuted(uint256 proposalId) event

在提案执行时发出。

ProposalCanceled(uint256 proposalId) event

在提案取消时发出。

VoteCast(address indexed voter, uint256 proposalId, uint8 support, uint256 weight, string reason) event

在没有参数的情况下投出选票时发出。

注意:support 值应被视为存储桶。他们的解释取决于所使用的投票模块。

VoteCastWithParams(address indexed voter, uint256 proposalId, uint8 support, uint256 weight, string reason, bytes params) event

在有参数的情况下投出选票时发出。

注意:support 值应被视为存储桶。他们的解释取决于所使用的投票模块。 params 是附加的编码参数。它们的解释还取决于所使用的投票模块。

GovernorInvalidProposalLength(uint256 targets, uint256 calldatas, uint256 values) error

空提案或提案调用的参数长度不匹配。

GovernorAlreadyCastVote(address voter) error

选票已被投出。

GovernorDisabledDeposit() error

在此合约中禁用 token 存款。

GovernorOnlyExecutor(address account) error

account 不是治理执行者。

GovernorNonexistentProposal(uint256 proposalId) error

proposalId 不存在。

GovernorUnexpectedProposalState(uint256 proposalId, enum IGovernor.ProposalState current, bytes32 expectedStates) error

提案的当前状态不是执行操作所需的。 expectedStates 是一个位图,其中为每个 ProposalState 枚举位置启用位 从右到左计数。

如果 expectedStatebytes32(0),则预计提案不处于任何状态(即不存在)。<br>加粗这是一个预计要取消设置的提案已经被初始化(重复提案)的情况。

请参见 Governor._encodeStateBitmap

GovernorInvalidVotingPeriod(uint256 votingPeriod) error

设置的投票期不是有效期限。

GovernorInsufficientProposerVotes(address proposer, uint256 votes, uint256 threshold) error

proposer 没有创建提案所需的选票。

GovernorRestrictedProposer(address proposer) error

不允许 proposer 创建提案。

GovernorInvalidVoteType() error

使用的投票类型对于相应的计数模块无效。

GovernorInvalidVoteParams() error

计数模块不支持提供的参数缓冲区。

GovernorQueueNotImplemented() error

未为此 governor 实现队列操作。应直接调用 Execute。

GovernorNotQueuedProposal(uint256 proposalId) error

提案尚未排队。

GovernorAlreadyQueuedProposal(uint256 proposalId) error

提案已排队。

GovernorInvalidSignature(address voter) error

对于预期的 voter,提供的签名无效。 如果 voter 是一个合约,则使用 IERC1271.isValidSignature时签名无效。

GovernorUnableToCancel(uint256 proposalId, address account) error

给定的 account 无法取消具有给定 proposalId 的提案。

Governor

import "@openzeppelin/contracts/governance/Governor.sol";

治理系统的核心,旨在通过各种模块进行扩展。

此合约是抽象的,需要通过各种模块实现多个函数:

IGovernor

Nonces

EIP712

Events

IGovernor

IERC5267

Errors

IGovernor

Nonces

onlyGovernance() modifier

限制一个函数,使其只能通过治理提案执行。例如,GovernorSettings 中的治理参数设置器使用此修饰符进行保护。

治理执行地址可能与 Governor 自身的地址不同,例如它可以是一个时间锁。这可以通过重写 _executor 来由模块进行自定义。执行者只能在 governor 的 execute 函数执行期间调用这些函数,而不能在任何其他情况下调用。因此,例如,额外的时间锁提议者无法在不经过治理协议的情况下更改治理参数(自 v4.6 起)。

constructor(string name_) internal

设置 nameversion 的值

receive() external

接收 ETH 的函数,该 ETH 将由 governor 处理(如果执行者是第三方合约,则禁用)

supportsInterface(bytes4 interfaceId) → bool public

参见 IERC165.supportsInterface

name() → string public

参见 IGovernor.name

version() → string public

参见 IGovernor.version

hashProposal(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash) → uint256 public

参见 IGovernor.hashProposal

提案 id 通过哈希 ABI 编码的 targets 数组、values 数组、calldatas 数组和 descriptionHash(bytes32 本身是描述字符串的 keccak256 哈希)来生成。此提案 id 可以从提案数据中生成,提案数据是 ProposalCreated 事件的一部分。它甚至可以在提案提交之前提前计算出来。

请注意,chainId 和 governor 地址不是提案 id 计算的一部分。因此,如果相同的提案(具有相同的操作和相同的描述)在多个网络上的多个 governor 上提交,则将具有相同的 id。这也意味着为了(在同一 governor 上)执行相同的操作两次,提议者将必须更改描述,以避免提案 id 冲突。

getProposalId(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash) → uint256 public

参见 IGovernor.getProposalId

state(uint256 proposalId) → enum IGovernor.ProposalState public

参见 IGovernor.state

proposalThreshold() → uint256 public

参见 IGovernor.proposalThreshold

proposalSnapshot(uint256 proposalId) → uint256 public

参见 IGovernor.proposalSnapshot

proposalDeadline(uint256 proposalId) → uint256 public

参见 IGovernor.proposalDeadline

proposalProposer(uint256 proposalId) → address public

参见 IGovernor.proposalProposer

proposalEta(uint256 proposalId) → uint256 public

参见 IGovernor.proposalEta

proposalNeedsQueuing(uint256) → bool public

参见 IGovernor.proposalNeedsQueuing

_checkGovernance() internal

如果 msg.sender 不是执行者,则还原。如果执行者不是此合约本身,则如果 msg.data 未被列入白名单作为 execute 操作的结果,则该函数将还原。参见 onlyGovernance

_quorumReached(uint256 proposalId) → bool internal

已投出的票数是否超过了阈值限制。

_voteSucceeded(uint256 proposalId) → bool internal

提案是否成功。

_getVotes(address account, uint256 timepoint, bytes params) → uint256 internal

获取 account 在特定 timepoint 的投票权重,用于 params 描述的投票。

_countVote(uint256 proposalId, address account, uint8 support, uint256 totalWeight, bytes params) → uint256 internal

proposalId 注册由 account 投票,具有给定的 support、投票 weight 和投票 params

注意:支持是通用的,并且可以代表各种事物,具体取决于所使用的投票系统。

_tallyUpdated(uint256 proposalId) internal

每次更新提案的计票时都应调用的Hook。

注意:此函数必须成功运行。还原将导致治理崩溃

_defaultParams() → bytes internal

castVote 方法使用的默认附加编码参数,不包括这些参数

注意:应由特定实现重写以使用适当的值,附加参数的含义,在该实现的上下文中

propose(address[] targets, uint256[] values, bytes[] calldatas, string description) → uint256 public

参见 IGovernor.propose。此函数具有选择加入的前端运行保护,如 _isValidDescriptionForProposer 中所述。

_propose(address[] targets, uint256[] values, bytes[] calldatas, string description, address proposer) → uint256 proposalId internal

内部提议机制。可以重写以在提案创建时添加更多逻辑。

发出一个 IGovernor.ProposalCreated 事件。

queue(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash) → uint256 public

参见 IGovernor.queue

_queueOperations(uint256, address[], uint256[], bytes[], bytes32) → uint48 internal

内部排队机制。可以重写(无需超级调用)以修改执行排队的方式(例如添加 vault/timelock)。

默认情况下,此项为空,必须重写才能实现排队。

此函数返回一个时间戳,该时间戳描述了预期的执行 ETA。如果返回值是 0(这是默认值),则核心将认为排队未成功,并且公共 queue 函数将还原。

直接调用此函数将不会检查提案的当前状态,也不会发出 ProposalQueued 事件。应使用 queue 对提案进行排队。
execute(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash) → uint256 public

参见 IGovernor.execute

_executeOperations(uint256, address[] targets, uint256[] values, bytes[] calldatas, bytes32) internal

内部执行机制。可以重写(无需超级调用)以修改执行方式(例如添加 vault/timelock)。

直接调用此函数将不会检查提案的当前状态,也不会将执行标志设置为 true 或发出 ProposalExecuted 事件。应使用 execute 执行提案。
cancel(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash) → uint256 public

参见 IGovernor.cancel

_cancel(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash) → uint256 internal

具有最小限制的内部取消机制。除了 Canceled、Expired 或 Executed 之外,提案可以在任何状态下取消。取消后,提案无法重新提交。

发出一个 IGovernor.ProposalCanceled 事件。

getVotes(address account, uint256 timepoint) → uint256 public

参见 IGovernor.getVotes

getVotesWithParams(address account, uint256 timepoint, bytes params) → uint256 public

参见 IGovernor.getVotesWithParams

castVote(uint256 proposalId, uint8 support) → uint256 public

参见 IGovernor.castVote

castVoteWithReason(uint256 proposalId, uint8 support, string reason) → uint256 public

参见 IGovernor.castVoteWithReason

castVoteWithReasonAndParams(uint256 proposalId, uint8 support, string reason, bytes params) → uint256 public

参见 IGovernor.castVoteWithReasonAndParams

castVoteBySig(uint256 proposalId, uint8 support, address voter, bytes signature) → uint256 public

参见 IGovernor.castVoteBySig

castVoteWithReasonAndParamsBySig(uint256 proposalId, uint8 support, address voter, string reason, bytes params, bytes signature) → uint256 public

参见 IGovernor.castVoteWithReasonAndParamsBySig

_castVote(uint256 proposalId, address account, uint8 support, string reason) → uint256 internal

内部投票机制:检查投票是否待处理,是否尚未投票,使用 IGovernor.getVotes 检索投票权重,并调用 _countVote 内部函数。使用_defaultParams()。

发出一个 IGovernor.VoteCast 事件。

_castVote(uint256 proposalId, address account, uint8 support, string reason, bytes params) → uint256 internal

内部投票机制:检查投票是否待处理,是否尚未投票,使用 IGovernor.getVotes 检索投票权重,并调用 _countVote 内部函数。

发出一个 IGovernor.VoteCast 事件。

relay(address target, uint256 value, bytes data) external

将事务或函数调用中继到任意目标。如果治理执行者是 governor 本身以外的某个合约,例如使用时间锁时,可以在治理提案中调用此函数,以恢复错误发送到 governor 合约的Token或 Ether。请注意,如果执行者只是 governor 本身,则使用 relay 是多余的。

_executor() → address internal

governor 通过其执行操作的地址。将被通过另一个合约(例如时间锁)执行操作的模块重载。

onERC721Received(address, address, uint256, bytes) → bytes4 public

参见 IERC721Receiver.onERC721Received。如果治理执行者不是 governor 本身(例如,与时间锁一起使用),则禁用接收Token。

onERC1155Received(address, address, uint256, uint256, bytes) → bytes4 public

参见 IERC1155Receiver.onERC1155Received。如果治理执行者不是 governor 本身(例如,与时间锁一起使用),则禁用接收Token。

onERC1155BatchReceived(address, address, uint256[], uint256[], bytes) → bytes4 public

参见 IERC1155Receiver.onERC1155BatchReceived。如果治理执行者不是 governor 本身(例如,与时间锁一起使用),则禁用接收Token。

_encodeStateBitmap(enum IGovernor.ProposalState proposalState) → bytes32 internal

ProposalState 编码为 bytes32 表示形式,其中每个启用的位对应于 ProposalState 枚举中的底层位置。例如:

0x000…​10000
^^\-\-\-\-\-\- …​
^\-\-\-\-\- Succeeded
^\-\-\-\- Defeated
^\-\-\- Canceled
^\-\- Active
^\- Pending
_validateStateBitmap(uint256 proposalId, bytes32 allowedStates) → enum IGovernor.ProposalState internal

检查提案的当前状态是否与 allowedStates 位图描述的要求相符。此位图应使用 _encodeStateBitmap 构建。

如果不满足要求,则会还原并显示 GovernorUnexpectedProposalState 错误。

_isValidDescriptionForProposer(address proposer, string description) → bool internal
_validateCancel(uint256 proposalId, address caller) → bool internal

检查 caller 是否可以取消具有给定 proposalId 的提案。

默认实现允许提案提议者在待处理状态期间取消提案。

clock() → uint48 public

用于标记检查点的时钟。可以重写以实现基于时间戳的检查点(和投票)。

CLOCK_MODE() → string public

时钟的描述

votingDelay() → uint256 public

提案创建和投票- hashProposal(targets, values, calldatas, descriptionHash)

Nonces

EIP712

Events

IGovernor

IERC5267

Errors

IGovernor

Nonces

##### `COUNTING_MODE() → string` public

查看 IGovernor.COUNTING_MODE.

##### `hasVoted(uint256 proposalId, address account) → bool` public

查看 IGovernor.hasVoted.

##### `proposalVotes(uint256 proposalId) → uint256 againstVotes, uint256 forVotes, uint256 abstainVotes` public

访问内部投票计数。

##### `_quorumReached(uint256 proposalId) → bool` internal

查看 Governor._quorumReached.

##### `_voteSucceeded(uint256 proposalId) → bool` internal

查看 Governor._voteSucceeded. 在此模块中,forVotes 必须严格大于 againstVotes。

##### `_countVote(uint256 proposalId, address account, uint8 support, uint256 totalWeight, bytes) → uint256` internal

查看 Governor._countVote. 在此模块中,支持遵循来自 Governor Bravo 的 VoteType 枚举。

GovernorCountingFractional

import "@openzeppelin/contracts/governance/extensions/GovernorCountingFractional.sol";

Governor 的扩展,用于 fractional voting。

GovernorCountingSimple 类似,此合约是 Governor 的投票计数模块,支持 3 个选项: 反对、赞成、弃权。此外,它还包括第四个选项:Fractional,允许选民在其他 3 个选项中拆分他们的投票权。

以 Fractional 支持投出的票必须附带一个 params 参数,该参数是三个打包的 uint128 值, 分别代表委托人分配给反对、赞成和弃权的权重。对于为其他 3 个选项投出的那些票,params 参数必须为空。

当委托人是一个实施自己投票规则的合约时,这尤其有用。这些委托合约 可以根据多个实体委托其投票权的偏好来投 fractional 票。

一些示例用例包括:

  • 从 DeFi 池持有的代币进行投票

  • 从 L2 中由桥持有的代币进行投票

  • 使用零知识证明从受保护的池中私下投票。

基于 ScopeLift 的 GovernorCountingFractional

自 v5.1 起可用。

函数

Governor

Nonces

EIP712

Events

IGovernor

IERC5267

Errors

IGovernor

abi.encodePacked(uint128(againstVotes), uint128(forVotes), uint128(abstainVotes))
考虑一下,小数表决将所投的票数(在每个类别中)限制为 128 位。<br>根据底层 token 有多少小数位,单个投票人可能需要将其投票分成<br>多个投票操作。对于高于约 30 个小数位的精度,大型 token 持有者可能需要<br>可能需要大量调用来投出所有选票。投票人可以选择在单个操作中投出所有<br>剩余的选票,使用传统的 "bravo" 投票。
GovernorExceedRemainingWeight(address voter, uint256 usedVotes, uint256 remainingWeight) error

一个小数投票参数使用的投票数超过了该用户可用的投票数。

uint8 VOTE_TYPE_FRACTIONAL internal constant

GovernorCountingOverridable

import "@openzeppelin/contracts/governance/extensions/GovernorCountingOverridable.sol";

Governor 的扩展,使 委托人 能够覆盖其 受托人 的投票。此模块需要一个 继承了 VotesExtended 的 token。

函数

GovernorVotes

Governor

Nonces

EIP712

Events

IGovernor

IERC5267

Errors

IGovernor

Nonces

COUNTING_MODE() → string public

参见IGovernor.COUNTING_MODE

hasVoted(uint256 proposalId, address account) → bool public

参见 IGovernor.hasVoted

调用 castVote (或类似函数) 会使用 委托 给投票人的投票权来投票。<br>相反,调用 castOverrideVote (或类似函数) 会使用账户本身的投票权,来自其资产<br>余额。投出 "override vote" 不算作投票,也不会通过此 getter 反映出来。 考虑<br>使用 hasVotedOverride 来检查某个账户是否已针对给定的提案 id 投出 "override vote"。
hasVotedOverride(uint256 proposalId, address account) → bool public

检查 account 是否已否决其 受托人 对提案的投票。

proposalVotes(uint256 proposalId) → uint256 againstVotes, uint256 forVotes, uint256 abstainVotes public

内部投票计数的访问器。

_quorumReached(uint256 proposalId) → bool internal

参见 Governor._quorumReached

_voteSucceeded(uint256 proposalId) → bool internal

参见 Governor._voteSucceeded。 在此模块中,forVotes 必须严格大于 againstVotes。

_countVote(uint256 proposalId, address account, uint8 support, uint256 totalWeight, bytes) → uint256 internal

参见 Governor._countVote。 在此模块中,支持遵循 VoteType 枚举(来自 Governor Bravo)。

Governor._castVote 调用,后者发出 IGovernor.VoteCast (或 IGovernor.VoteCastWithParams)<br>事件。
_countOverride(uint256 proposalId, address account, uint8 support) → uint256 internal

Governor._countVote 的变体,用于处理投票否决。

有关 castVotecastOverrideVote 之间的区别,请参见 hasVoted
_castOverride(uint256 proposalId, address account, uint8 support, string reason) → uint256 internal

Governor._castVote 的变体,用于处理投票否决。返回否决的权重。

castOverrideVote(uint256 proposalId, uint8 support, string reason) → uint256 public

用于投出否决票的公共函数。返回否决的权重。

castOverrideVoteBySig(uint256 proposalId, uint8 support, address voter, string reason, bytes signature) → uint256 public

用于使用投票人的签名投出否决票的公共函数。返回否决的权重。

OVERRIDE_BALLOT_TYPEHASH() → bytes32 public
VoteReduced(address indexed delegate, uint256 proposalId, uint8 support, uint256 weight) event

在原始 token 持有者投出否决票后,delegate 投出的票数减少了 weight

OverrideVoteCast(address indexed voter, uint256 proposalId, uint8 support, uint256 weight, string reason) event

proposalId 上的 委托 投票被 weight 否决

GovernorAlreadyOverriddenVote(address account) error

GovernorVotes

import "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol";

Governor 的扩展,用于从 ERC20Votes token 中提取投票权重,或者自 v4.5 起从 ERC721Votes token 中提取投票权重。

函数

Governor

Events

IGovernor

IERC5267

Errors

IGovernor

Nonces

##### constructor(contract IVotes tokenAddress) internal
##### token() → contract IERC5805 public

投票权来源的 token。

##### clock() → uint48 public

Clock (如 ERC-6372 中指定的) 设置为与 token 的 clock 匹配。如果 token 未实现 ERC-6372,则回退到区块号。

##### CLOCK_MODE() → string public

机器可读的 clock 描述,如 ERC-6372 中指定的。

##### _getVotes(address account, uint256 timepoint, bytes) → uint256 internal

GovernorVotesQuorumFraction

import "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol";

Governor 的扩展,用于从 ERC20Votes token 中提取投票权重,并将法定人数表示为占总供应量的一部分。

Functions

GovernorVotes

Governor

IGovernor

Nonces

EIP712

Events

IGovernor

IERC5267

Errors

IGovernor

Nonces

##### constructor(uint256 quorumNumeratorValue) internal

将法定人数初始化为 token 总供应量的一部分。

该分数指定为 numerator / denominator。默认情况下,分母为 100,因此法定人数指定为百分比:分子为 10 对应于法定人数为总供应量的 10%。分母可以通过覆盖 quorumDenominator 来自定义。

##### quorumNumerator() → uint256 public

返回当前的法定人数分子。请参阅 quorumDenominator

##### quorumNumerator(uint256 timepoint) → uint256 public

返回特定时间点的法定人数分子。请参阅 quorumDenominator

##### quorumDenominator() → uint256 public

返回法定人数分母。默认为 100,但可能会被覆盖。

##### quorum(uint256 timepoint) → uint256 public

返回时间点的法定人数,以投票数表示:supply * numerator / denominator

##### updateQuorumNumerator(uint256 newQuorumNumerator) external

更改法定人数分子。

发出 QuorumNumeratorUpdated 事件。

要求:

  • 必须通过治理提案调用。

  • 新分子必须小于或等于分母。

##### _updateQuorumNumerator(uint256 newQuorumNumerator) internal

更改法定人数分子。

发出 QuorumNumeratorUpdated 事件。

要求:

  • 新分子必须小于或等于分母。
##### _optimisticUpperLookupRecent(struct Checkpoints.Trace208 ckpts, uint256 timepoint) → uint256 internal

返回特定时间点的分子。

##### QuorumNumeratorUpdated(uint256 oldQuorumNumerator, uint256 newQuorumNumerator) event
##### GovernorInvalidQuorumFraction(uint256 quorumNumerator, uint256 quorumDenominator) error

设置的法定人数不是有效分数。

GovernorVotesSuperQuorumFraction

import "@openzeppelin/contracts/governance/extensions/GovernorVotesSuperQuorumFraction.sol";

GovernorVotesQuorumFraction 的扩展,具有表示为总供应量一部分的超级法定人数。满足超级法定人数(并且具有多数赞成票)的提案在提案截止日期之前进入“成功”状态。

Functions

GovernorSuperQuorum

GovernorVotesQuorumFraction

GovernorVotes

Governor

IGovernor

Nonces

EIP712

Events

GovernorVotesQuorumFraction

IGovernor

IERC5267

Errors

GovernorVotesQuorumFraction

IGovernor

Nonces

constructor(uint256 superQuorumNumeratorValue) internal

将超级仲裁初始化为 token 总供应量的一部分。

超级仲裁被指定为 token 总供应量的一部分,并且必须大于仲裁。

superQuorumNumerator() → uint256 public

返回当前的超级仲裁分子。

superQuorumNumerator(uint256 timepoint) → uint256 public

返回在特定 timepoint 的超级仲裁分子。

superQuorum(uint256 timepoint) → uint256 public

返回 timepoint 的超级仲裁,以票数表示:supply * numerator / denominator。 更多详细信息,请参见 GovernorSuperQuorum.superQuorum

updateSuperQuorumNumerator(uint256 newSuperQuorumNumerator) public

更改超级仲裁分子。

发出一个 SuperQuorumNumeratorUpdated 事件。

要求:

  • 必须通过治理提案调用。

  • 新的超级仲裁分子必须小于或等于分母。

  • 新的超级仲裁分子必须大于或等于仲裁分子。

_updateSuperQuorumNumerator(uint256 newSuperQuorumNumerator) internal

更改超级仲裁分子。

发出一个 SuperQuorumNumeratorUpdated 事件。

要求:

  • 新的超级仲裁分子必须小于或等于分母。

  • 新的超级仲裁分子必须大于或等于仲裁分子。

_updateQuorumNumerator(uint256 newQuorumNumerator) internal

覆盖 GovernorVotesQuorumFraction._updateQuorumNumerator 以确保超级仲裁分子大于或等于仲裁分子。

state(uint256 proposalId) → enum IGovernor.ProposalState public

Governor.state 函数的重写版本,用于检查提案是否已达到超级仲裁。

如果提案达到超级仲裁,但 _voteSucceeded 返回 false,例如,假设超级仲裁设置得足够低,以至于 FOR 和 AGAINST 票都超过了它,并且 AGAINST 票超过了 FOR 票,<br>该提案将继续保持活动状态,直到 _voteSucceeded 返回 true 或达到提案截止日期。<br>这意味着,如果超级仲裁设置得很低,投票也可能在足够的 AGAINST 投票者有机会投票之前过早成功。因此,建议设置足够高的超级仲裁以避免这些<br>类型的场景。
SuperQuorumNumeratorUpdated(uint256 oldSuperQuorumNumerator, uint256 newSuperQuorumNumerator) event
GovernorInvalidSuperQuorumFraction(uint256 superQuorumNumerator, uint256 denominator) error

设置的超级仲裁无效,因为它超过了仲裁分母。

GovernorInvalidSuperQuorumTooSmall(uint256 superQuorumNumerator, uint256 quorumNumerator) error

设置的超级仲裁无效,因为它小于或等于仲裁。

GovernorInvalidQuorumTooLarge(uint256 quorumNumerator, uint256 superQuorumNumerator) error

设置的仲裁无效,因为它超过了超级仲裁。

扩展

GovernorTimelockAccess

import "@openzeppelin/contracts/governance/extensions/GovernorTimelockAccess.sol";

该模块将 Governor 实例连接到 accessManager 实例, 允许 governor 使用普通的 queue 工作流调用被 manager 延迟限制的调用. 对于 manager 没有外部延迟的操作,会应用一个可选的基础延迟. 提案的执行将会被延迟,以满足其所有操作的需求延迟。

这个扩展允许 governor 持有和使用自己的资产和权限,不像 GovernorTimelockControlGovernorTimelockCompound,其中时间锁是一个单独的合约,必须是持有资产和 权限的合约。然而,受 manager 延迟限制的操作将通过 AccessManager.execute 函数执行.

安全注意事项

一些操作可能会在 AccessManager 中被管理员或一组监护人取消,这取决于 正在调用的受限函数。由于提案是原子的,监护人取消提案中的单个操作将导致所有提案都无法执行。考虑单独提出可取消的操作。

默认情况下,只要相关的 AccessManager 声称目标函数受其约束,函数调用将通过其路由。然而,管理员可以配置 manager 对 governor 想要直接调用的函数(例如,token 转移)进行声明,试图拒绝 governor 访问这些函数。为了缓解这种攻击媒介,governor 能够使用 setAccessManagerIgnored 忽略 AccessManager 声明的限制。虽然减轻了永久拒绝服务,但临时 DoS 在技术上仍有可能。默认情况下,所有 governor 自己的函数(例如,setBaseDelaySeconds)都忽略 AccessManager

AccessManager 不支持同时调度具有相同目标和 calldata 的多个操作。<br>参见 AccessManager.schedule 以获得解决方法。

函数

Governor

IGovernor

Nonces

EIP712

Events

IGovernor

IERC5267

Errors

IGovernor

_setBaseDelaySeconds(uint32 newBaseDelay) internal

更改 baseDelaySeconds 的值。没有访问控制的内部函数。

isAccessManagerIgnored(address target, bytes4 selector) → bool public

检查来自关联的 accessManager 的限制是否对目标函数忽略。当目标函数将被直接调用,而不管该函数的 AccessManager 设置如何时,返回 true。 请参阅上面的 setAccessManagerIgnored 和安全考虑事项。

setAccessManagerIgnored(address target, bytes4[] selectors, bool ignored) public

配置是否忽略来自关联的 accessManager 的限制,针对目标函数。 请参阅上面的安全考虑事项。

_setAccessManagerIgnored(address target, bytes4 selector, bool ignored) internal

setAccessManagerIgnored 的内部版本,没有访问限制。

proposalExecutionPlan(uint256 proposalId) → uint32 delay, bool[] indirect, bool[] withDelay public

公共访问器,用于检查执行计划,包括提案自排队后将被延迟的秒数,一个数组,指示哪些提案操作将通过关联的 accessManager 间接执行,另一个数组,指示哪些操作将在 queue 中调度。请注意,那些必须调度的操作可以被 AccessManager 守护者取消。

proposalNeedsQueuing(uint256 proposalId) → bool public

请参阅 IGovernor.proposalNeedsQueuing

propose(address[] targets, uint256[] values, bytes[] calldatas, string description) → uint256 public

请参阅 IGovernor.propose

_queueOperations(uint256 proposalId, address[] targets, uint256[], bytes[] calldatas, bytes32) → uint48 internal

用于对提案进行排队的机制,可能会在 AccessManager 中调度其某些操作。

执行延迟是根据在 propose 中检索的延迟信息选择的。如果自提案创建以来延迟已更新,则此值可能不正确。在这种情况下,需要重新创建提案。
_executeOperations(uint256 proposalId, address[] targets, uint256[] values, bytes[] calldatas, bytes32) internal

用于执行提案的机制,对于延迟的操作,可能会通过 AccessManager.execute 进行。

_cancel(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash) → uint256 internal

请参阅 Governor._cancel

BaseDelaySet(uint32 oldBaseDelaySeconds, uint32 newBaseDelaySeconds) event
AccessManagerIgnoredSet(address target, bytes4 selector, bool ignored) event
GovernorUnmetDelay(uint256 proposalId, uint256 neededTimestamp) error
GovernorMismatchedNonce(uint256 proposalId, uint256 expectedNonce, uint256 actualNonce) error
GovernorLockedIgnore() error

GovernorTimelockControl

import "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol";

Governor 的扩展,它将执行过程绑定到 TimelockController 的实例。这为所有成功的提案增加了一个延迟,该延迟由 TimelockController 强制执行(除了投票持续时间之外)。Governor 需要 proposer(理想情况下是 executor 和 canceller)角色,Governor 才能正常工作。

使用此模型意味着提案将由 TimelockController 操作,而不是由 Governor 操作。因此,资产和权限必须附加到 TimelockController。发送到 Governor 的任何资产将无法从提案访问,除非通过 Governor.relay 执行。

除了 governor 之外,将 TimelockController 设置为具有额外的 proposers 或 cancelers 非常危险,因为它授予他们以下能力:1) 以 timelock 的身份执行操作,从而可能执行预计只能通过投票才能访问的操作或访问资金,以及 2) 阻止已获得选民批准的治理提案,从而有效地执行拒绝服务攻击。

函数

Governor

IGovernor

Nonces

EIP712

Events

IGovernor

IERC5267

Errors

IGovernor

Nonces

constructor(contract TimelockController timelockAddress) internal

设置 timelock。

state(uint256 proposalId) → enum IGovernor.ProposalState public

Governor.state 函数的重写版本,它考虑了 timelock 报告的状态。

timelock() → address public

用于检查 timelock 地址的公共访问器

proposalNeedsQueuing(uint256) → bool public

请参阅 IGovernor.proposalNeedsQueuing

_queueOperations(uint256 proposalId, address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash) → uint48 internal

用于将提案排队到 timelock 的函数。

_executeOperations(uint256 proposalId, address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash) internal

Governor._executeOperations 函数的重写版本,它通过 timelock 运行已经排队的提案。

_cancel(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash) → uint256 internal

Governor._cancel 函数的重写版本,用于取消已经排队的 timelock 提案。

_executor() → address internal

governor 执行操作的地址。在这种情况下,是 timelock。

updateTimelock(contract TimelockController newTimelock) external

用于更新底层 timelock 实例的公共端点。限制为 timelock 本身,因此更新必须通过治理提案提出、安排和执行。

建议不要在存在其他已排队的治理提案时更改 timelock。
TimelockChange(address oldTimelock, address newTimelock) event

当用于提案执行的 timelock 控制器被修改时发出。

GovernorTimelockCompound

import "@openzeppelin/contracts/governance/extensions/GovernorTimelockCompound.sol";

Governor 的扩展,它将执行过程绑定到 Compound Timelock。这为所有成功的提案增加了一个延迟,该延迟由外部 timelock 强制执行(除了投票持续时间之外)。对于要执行的任何操作,Governor 需要是 timelock 的管理员。一个公共的、不受限制的 GovernorTimelockCompound.acceptAdmin 可用于接受 timelock 的所有权。

使用此模型意味着提案将由 TimelockController 操作,而不是由 Governor 操作。因此,资产和权限必须附加到 TimelockController。发送到 Governor 的任何资产将无法从提案访问,除非通过 Governor.relay 执行。

函数

Governor

IGovernor

Nonces

EIP712

Events

IGovernor

IERC5267

Errors

IGovernor

Nonces

constructor(contract ICompoundTimelock timelockAddress) internal

设置时间锁。

state(uint256 proposalId) → enum IGovernor.ProposalState public

Governor.state 函数的重写版本,增加了对 Expired 状态的支持。

timelock() → address public

用于检查时间锁地址的公共访问器

proposalNeedsQueuing(uint256) → bool public

参见 IGovernor.proposalNeedsQueuing

_queueOperations(uint256 proposalId, address[] targets, uint256[] values, bytes[] calldatas, bytes32) → uint48 internal

用于将提案加入时间锁队列的函数。

_executeOperations(uint256 proposalId, address[] targets, uint256[] values, bytes[] calldatas, bytes32) internal

Governor._executeOperations 函数的重写版本,用于通过时间锁运行已排队的提案。

_cancel(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash) → uint256 internal

Governor._cancel 函数的重写版本,用于取消已排队的时间锁提案(如果已排队)。

_executor() → address internal

Governor 执行操作的地址。 在本例中,为时间锁。

__acceptAdmin() public

接受对时间锁的管理权限。

updateTimelock(contract ICompoundTimelock newTimelock) external

用于更新底层时间锁实例的公共端点。 仅限于时间锁本身,因此更新必须通过治理提案提出、安排和执行。

出于安全原因,必须在设置新的时间锁之前将时间锁移交给另一个管理员。 两个操作(移交时间锁)并执行更新可以分批放在一个提案中。

请注意,如果时间锁管理员已在之前的操作中被移交出去,如果时间锁的管理员已被接受并且操作在治理范围之外执行,我们将拒绝通过时间锁进行的更新。

不建议在有其他已排队的治理提案时更改时间锁。
TimelockChange(address oldTimelock, address newTimelock) event

当用于提案执行的时间锁控制器被修改时发出。

GovernorSettings

import "@openzeppelin/contracts/governance/extensions/GovernorSettings.sol";

Governor 的扩展,用于通过治理更新设置。

函数

Governor

IGovernor

Nonces

EIP712

Events

IGovernor

IERC5267

Errors

IGovernor

Nonces

constructor(uint48 initialVotingDelay, uint32 initialVotingPeriod, uint256 initialProposalThreshold) internal

初始化治理参数。

votingDelay() → uint256 public

参见 IGovernor.votingDelay

votingPeriod() → uint256 public

参见 IGovernor.votingPeriod

proposalThreshold() → uint256 public

参见 Governor.proposalThreshold

setVotingDelay(uint48 newVotingDelay) public

更新投票延迟。此操作只能通过治理提案执行。

发出 VotingDelaySet 事件。

setVotingPeriod(uint32 newVotingPeriod) public

更新投票期。此操作只能通过治理提案执行。

发出 VotingPeriodSet 事件。

setProposalThreshold(uint256 newProposalThreshold) public

更新提案阈值。此操作只能通过治理提案执行。

发出 ProposalThresholdSet 事件。

_setVotingDelay(uint48 newVotingDelay) internal

投票延迟的内部设置器。

发出 VotingDelaySet 事件。

_setVotingPeriod(uint32 newVotingPeriod) internal

投票期的内部设置器。

发出 VotingPeriodSet 事件。

_setProposalThreshold(uint256 newProposalThreshold) internal

提案阈值的内部设置器。

发出 ProposalThresholdSet 事件。

VotingDelaySet(uint256 oldVotingDelay, uint256 newVotingDelay) event
VotingPeriodSet(uint256 oldVotingPeriod, uint256 newVotingPeriod) event
ProposalThresholdSet(uint256 oldProposalThreshold, uint256 newProposalThreshold) event

GovernorPreventLateQuorum

import "@openzeppelin/contracts/governance/extensions/GovernorPreventLateQuorum.sol";

一个模块,确保在达到法定人数后有最短的投票期。这可以防止大型投票者通过确保始终有时间让其他投票者做出反应并尝试反对该决定,从而在最后一刻左右投票并触发法定人数。

如果投票导致达到法定人数,则可以延长提案的投票期,使其不会在至少经过指定时间(“投票延期”参数)之前结束。此参数可以通过治理提案设置。

函数

IGovernor

Nonces

EIP712

Events

IGovernor

IERC5267

Errors

IGovernor

Nonces

constructor(uint48 initialVoteExtension) internal

初始化投票扩展参数:自提案达到法定人数到其投票期结束之间需要经过的时间(以区块数或秒为单位,具体取决于 governor 时钟模式)。 如果必要,投票期将延长到提案创建期间设置的时间之外。

proposalDeadline(uint256 proposalId) → uint256 public

返回提案截止日期,如果提案在其投票期内较晚达到法定人数,则截止日期可能已超出提案创建时设置的截止日期。 请参阅 Governor.proposalDeadline

_tallyUpdated(uint256 proposalId) internal

投票统计已更新,并检测它是否导致达到法定人数,从而可能延长投票期。

可能会发出 ProposalExtended 事件。

lateQuorumVoteExtension() → uint48 public

返回投票扩展参数的当前值:从提案达到法定人数到其投票期结束所需经过的区块数。

setLateQuorumVoteExtension(uint48 newVoteExtension) public

更改 lateQuorumVoteExtension。 此操作只能由治理执行者执行,通常通过治理提案执行。

发出 LateQuorumVoteExtensionSet 事件。

_setLateQuorumVoteExtension(uint48 newVoteExtension) internal

更改 lateQuorumVoteExtension。 这是一个内部函数,如果需要另一种访问控制机制,可以在公共函数(如 setLateQuorumVoteExtension)中公开该函数。

发出 LateQuorumVoteExtensionSet 事件。

ProposalExtended(uint256 indexed proposalId, uint64 extendedDeadline) event

当提案截止日期因在其投票期内较晚达到法定人数而被推迟时发出。

LateQuorumVoteExtensionSet(uint64 oldVoteExtension, uint64 newVoteExtension) event

lateQuorumVoteExtension 参数被更改时发出。

GovernorStorage

import "@openzeppelin/contracts/governance/extensions/GovernorStorage.sol";

Governor 的扩展,实现了提案详情的存储。此模块还提供了提案可枚举性的原语。

此模块的用例包括:

  • 无需依赖事件索引即可浏览提案状态的 UI。
  • 仅使用 proposalId 作为 Governor.queueGovernor.execute 函数中的参数,用于 L2 链,在这些链中,与 calldata 相比,存储成本较低。

函数

Governor

IGovernor

Nonces

EIP712

Events

IGovernor

IERC5267

Errors

IGovernor

Nonces

_propose(address[] targets, uint256[] values, bytes[] calldatas, string description,- [_checkGovernance()`](https://docs.openzeppelin.com/contracts/5.x/api/governance#Governor-_checkGovernance--)

IGovernor

Nonces

EIP712

Events

IGovernor

IERC5267

Errors

IGovernor

Nonces

proposalGuardian() → address public

Getter,返回 proposal guardian 的地址。

setProposalGuardian(address newProposalGuardian) public

更新 proposal guardian 的地址。这个操作只能通过治理提案来执行。

发出一个 ProposalGuardianSet 事件。

_setProposalGuardian(address newProposalGuardian) internal

proposal guardian 的内部 setter。

发出一个 ProposalGuardianSet 事件。

_validateCancel(uint256 proposalId, address caller) → bool internal

覆盖 Governor._validateCancel 以实现扩展的取消逻辑。

ProposalGuardianSet(address oldProposalGuardian, address newProposalGuardian) event

GovernorSuperQuorum

import "@openzeppelin/contracts/governance/extensions/GovernorSuperQuorum.sol";

Governor 的扩展,具有超级法定人数。满足超级法定人数(并且具有多数赞成票)的提案在提案截止日期之前进入 Succeeded 状态。想要使用此扩展的计数模块必须实现proposalVotes

函数

Governor

IGovernor

Nonces

EIP712

Events

IGovernor

IERC5267

Errors

IGovernor

Nonces

superQuorum(uint256 timepoint) → uint256 public

提案达到超级法定人数所需的最小投票- getVotes(account)

Nonces

EIP712

Events

IVotes

IERC5267

Errors

IVotes

Nonces

clock() → uint48 public

用于标记检查点的时钟。可以被覆盖以实现基于时间戳的检查点(和投票),在这种情况下,CLOCK_MODE也应该被覆盖以匹配。

CLOCK_MODE() → string public

如 ERC-6372 中规定的时钟的机器可读描述。

_validateTimepoint(uint256 timepoint) → uint48 internal

验证时间点是否在过去,并将其作为 uint48 返回。

getVotes(address account) → uint256 public

返回 account 当前拥有的票数。

getPastVotes(address account, uint256 timepoint) → uint256 public

返回 account 在过去特定时刻拥有的票数。如果 clock() 被配置为使用区块号,这将返回相应区块结束时的值。

要求:

  • timepoint 必须在过去。如果使用区块号操作,则该区块必须已被挖掘。
getPastTotalSupply(uint256 timepoint) → uint256 public

返回过去特定时刻可用的总票数。如果 clock() 被配置为使用区块号,这将返回相应区块结束时的值。

该值是所有可用票数的总和,不一定是所有已授权票数的总和。<br>尚未授权的票数仍然是总供应量的一部分,即使它们不会参与投票。<br>

要求:

  • timepoint 必须在过去。如果使用区块号操作,则该区块必须已被挖掘。
_getTotalSupply() → uint256 internal

返回当前的总票数。

delegates(address account) → address public

返回 account 选择的委托人。

delegate(address delegatee) public

将投票权从发送者委托给 delegatee

delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) public

将投票权从签名者委托给 delegatee

_delegate(address account, address delegatee) internal

将所有 account 的投票单位委托给 delegatee

发出事件 IVotes.DelegateChangedIVotes.DelegateVotesChanged

_transferVotingUnits(address from, address to, uint256 amount) internal

转移、铸造或销毁投票单位。要注册铸造,from 应该为零。要注册销毁,to 应该为零。投票单位的总供应量将通过铸造和销毁进行调整。

_moveDelegateVotes(address from, address to, uint256 amount) internal

将委托的投票权从一个委托人转移到另一个委托人。

_numCheckpoints(address account) → uint32 internal

获取 account 的检查点数量。

_checkpoints(address account, uint32 pos) → struct Checkpoints.Checkpoint208 internal

获取 account 的第 pos 个检查点。

_getVotingUnits(address) → uint256 internal

必须返回账户持有的投票单位。

ERC6372InconsistentClock() error

时钟被错误地修改了。

ERC5805FutureLookup(uint256 timepoint, uint48 clock) error

无法查找未来的投票。

VotesExtended

import "@openzeppelin/contracts/governance/utils/VotesExtended.sol";

Votes 的扩展,增加了对委托和余额的检查点。

虽然此合约扩展了 Votes,但 Votes 的有效使用可能与<br>VotesExtended 不兼容,除非进行额外的考虑。_transferVotingUnits 的此实现必须<br>在投票权重移动注册加粗后运行,以便它反映在 _getVotingUnits 上。

换句话说,VotesExtended 必须以一种在资产转移注册加粗且余额更新后调用 _transferVotingUnits 的方式集成:

contract VotingToken is Token, VotesExtended {
  function transfer(address from, address to, uint256 tokenId) public override {
    super.transfer(from, to, tokenId); // &lt;- 首先执行转移 ...
    _transferVotingUnits(from, to, 1); // &lt;- ... 然后调用 _transferVotingUnits。
  }

  function _getVotingUnits(address account) internal view override returns (uint256) {
     return balanceOf(account);
  }
}

ERC20VotesERC721Votes 遵循此模式,因此可以安全地与 VotesExtended 一起使用。

Functions

Votes

Nonces

EIP712

Events

IVotes

IERC5267

Errors

Votes

IVotes

Nonces

getPastDelegate(address account, uint256 timepoint) → address public

返回在过去特定时刻 account 的委托人。如果 clock() 被配置为使用区块号,这将返回相应区块结束时的值。

要求:

  • timepoint 必须在过去。如果使用区块号操作,则该区块必须已被挖掘。
getPastBalanceOf(address account, uint256 timepoint) → uint256 public

返回在过去特定时刻 accountbalanceOf。如果 clock() 被配置为使用区块号,这将返回相应区块结束时的值。

要求:

  • timepoint 必须在过去。如果使用区块号操作,则该区块必须已被挖掘。
_delegate(address account, address delegatee) internal

将所有 account 的投票单位委托给 delegatee

发出事件 IVotes.DelegateChangedIVotes.DelegateVotesChanged

_transferVotingUnits(address from, address to, uint256 amount) internal

转移、铸造或销毁投票单位。要注册铸造,from 应该为零。要注册销毁,to 应该为零。投票单位的总供应量将通过铸造和销毁进行调整。

Timelock

在治理系统中,TimelockController 合约负责在提案及其执行之间引入延迟。它可以与 Governor 一起使用,也可以不一起使用。

TimelockController

import "@openzeppelin/contracts/governance/TimelockController.sol";

合约模块,充当时间锁定的控制器。当设置为 Ownable 智能合约的所有者时,它会对所有 onlyOwner 维护操作强制执行时间锁。这使得受控合约的用户有时间在应用潜在危险的维护操作之前退出。

默认情况下,此合约是自我管理的,这意味着管理任务必须经过时间锁流程。提议者(resp 执行者)角色负责提议(resp 执行)操作。一个常见的用例是将此 TimelockController 定位为智能合约的所有者,并将多重签名或 DAO 作为唯一的提议者。

Modifiers

Functions

ERC1155Holder

ERC721Holder

AccessControl

Events

IAccessControl

Errors

IAccessControl

Internal Variables

onlyRoleOrOpenRole(bytes32 role) modifier

修饰符,使一个函数只能由某个角色调用。除了检查发送者的角色之外,address(0) 的角色也被考虑在内。将角色授予 address(0) 等同于为每个人启用此角色。

constructor(uint256 minDelay, address[] proposers, address[] executors, address admin) public

使用以下参数初始化合约:

  • minDelay:操作的初始最小延迟(以秒为单位)

  • proposers:将被授予提议者和取消者角色的帐户

  • executors:将被授予执行者角色的帐户

  • admin:将被授予管理员角色的可选帐户;使用零地址禁用

可选的管理员可以帮助在部署后进行角色的初始配置,而无需受到延迟的影响,但是此角色应随后被放弃,以支持<br>通过时间锁定的提案进行管理。此合约的先前版本会自动将此管理员分配给部署者,并且也应将其放弃。
receive() external

合约可能会接收/持有 ETH 作为维护过程的一部分。

supportsInterface(bytes4 interfaceId) → bool public

参见 IERC165.supportsInterface

isOperation(bytes32 id) → bool public

返回 ID 是否对应于已注册的操作。这包括等待、就绪和完成的操作。

isOperationPending(bytes32 id) → bool public

返回操作是否正在挂起。请注意,“挂起”操作也可能是“就绪”的。

isOperationReady(bytes32 id) → bool public

返回操作是否已准备好执行。请注意,“就绪”操作也正在“挂起”。

isOperationDone(bytes32 id) → bool public

返回操作是否已完成。

getTimestamp(bytes32 id) → uint256 public

返回操作准备就绪的时间戳(未设置的操作为 0,完成的操作为 1)。

getOperationState(bytes32 id) → enum TimelockController.OperationState public

返回操作状态。

getMinDelay() → uint256 public

返回操作变为有效所需的最小延迟(以秒为单位)。

此值可以通过执行调用 updateDelay 的操作来更改。

hashOperation(address target, uint256 value, bytes data, bytes32 predecessor, bytes32 salt) → bytes32 public

返回包含单个事务的操作的标识符。

hashOperationBatch(address[] targets, uint256[] values, bytes[] payloads, bytes32 predecessor, bytes32 salt) → bytes32 public

返回包含一批事务的操作的标识符。

schedule(address target, uint256 value, bytes data, bytes32 predecessor, bytes32 salt, uint256 delay) public

计划包含单个事务的操作。

如果盐不为零,则发出 CallSalt,并发出 [CallScheduled](https://docs.##### TimelockUnexpectedOperationState(bytes32 operationId, bytes32 expectedStates) 错误

操作的当前状态不符合要求。 expectedStates 是一个位图,从右到左,为每个 OperationState 枚举位置启用位。

参见 _encodeStateBitmap

TimelockUnexecutedPredecessor(bytes32 predecessorId) 错误

某个操作的前置操作尚未完成。

TimelockUnauthorizedCaller(address caller) 错误

调用者账户未被授权。

uint256 _DONE_TIMESTAMP 内部常量
术语
  • Operation (操作): 一项事务(或一组事务),是时间锁的主题。它必须由提议者安排,并由执行者执行。时间锁强制在提议和执行之间设置最短延迟。如果操作包含多个事务(批量模式),它们将以原子方式执行。操作由其内容的哈希标识。

  • Operation status (操作状态):

  • Unset (未设置): 不属于时间锁机制的操作。

  • Waiting (等待中): 已安排的操作,在计时器到期之前。

  • Ready (就绪): 已安排的操作,在计时器到期之后。

  • Pending (待定): 处于等待中或就绪状态的操作。

  • Done (已完成): 已执行的操作。

  • Predecessor (前置操作): 操作之间的(可选)依赖关系。一个操作可以依赖于另一个操作(其前置操作),从而强制执行这两个操作的执行顺序。

  • Role (角色):

  • Admin (管理员): 负责授予提议者和执行者角色的地址(智能合约或 EOA)。

  • Proposer (提议者): 负责安排(和取消)操作的地址(智能合约或 EOA)。

  • Executor (执行者): 负责在时间锁到期后执行操作的地址(智能合约或 EOA)。可以将此角色授予零地址,以允许任何人执行操作。

Operation structure (操作结构)

TimelockController 执行的操作可以包含一个或多个后续调用。根据是否需要以原子方式执行多个调用,可以使用简单操作或批量操作。

两种操作都包含:

  • Target (目标),时间锁应操作的智能合约的地址。

  • Value (值),以 wei 为单位,应与事务一起发送。大多数时候,这将是 0。以太币可以在执行事务之前存入,也可以在执行事务时一同传递。

  • Data (数据),包含编码的函数选择器和调用的参数。这可以使用多种工具生成。例如,可以使用 web3js 将授予 ACCOUNT 对角色 ROLE 的维护操作编码如下:

const data = timelock.contract.methods.grantRole(ROLE, ACCOUNT).encodeABI()
  • Predecessor (前置操作),指定操作之间的依赖关系。此依赖关系是可选的。如果操作没有任何依赖关系,请使用 bytes32(0)

  • Salt (盐),用于消除两个其他方面相同的操作的歧义。这可以是任何随机值。

在批量操作的情况下,targetvaluedata 被指定为数组,这些数组的长度必须相同。

Operation lifecycle (操作生命周期)

时间锁定的操作由唯一的 ID(它们的哈希)标识,并遵循特定的生命周期:

UnsetPendingPending + ReadyDone

  • 通过调用 schedule(或 scheduleBatch),提议者将操作从 Unset 状态移动到 Pending 状态。这将启动一个计时器,该计时器必须长于最短延迟。计时器在通过 getTimestamp 方法访问的时间戳到期。

  • 计时器到期后,操作将自动进入 Ready 状态。此时,可以执行该操作。

  • 通过调用 execute(或 executeBatch),执行者触发操作的底层事务,并将其移动到 Done 状态。如果操作具有前置操作,则该前置操作必须处于 Done 状态,此转换才能成功。

  • cancel 允许提议者取消任何 Pending 操作。这会将操作重置为 Unset 状态。因此,提议者可以重新安排已取消的操作。在这种情况下,重新安排操作时,计时器将重新启动。

可以使用以下函数查询操作状态:

Roles (角色)
Admin (管理员)

管理员负责管理提议者和执行者。为了使时间锁实现自治,此角色应仅授予时间锁本身。部署后,除了时间锁本身之外,还可以将管理员角色授予任何地址。在进一步配置和测试后,此可选管理员应放弃其角色,以便所有进一步的维护操作都必须通过时间锁过程。

Proposer (提议者)

提议者负责安排(和取消)操作。这是一个关键角色,应授予治理实体。这可以是 EOA、多重签名或 DAO。

Proposer fight (提议者之争): 拥有多个提议者,虽然可以在某个提议者不可用时提供冗余,但可能很危险。由于提议者对所有操作都有发言权,因此他们可以取消他们不同意的操作,包括将他们从提议者中删除的操作。

此角色由 PROPOSER_ROLE 值标识:0xb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1

Executor (执行者)

执行者负责在时间锁到期后执行提议者安排的操作。逻辑上讲,作为提议者的多重签名或 DAO 也应该是执行者,以保证已安排的操作最终会被执行。但是,拥有额外的执行者可以降低成本(执行事务不需要提议它的多重签名或 DAO 的验证),同时确保负责执行的人员无法触发未经提议者安排的操作。或者,可以允许任何地址在时间锁到期后通过将执行者角色授予零地址来执行提议。

此角色由 EXECUTOR_ROLE 值标识:0xd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63

一个没有至少一个提议者和一个执行者的活动合约将被锁定。在部署者放弃其对时间锁合约本身的行政权利之前,请确保这些角色由可靠的实体填充。有关角色管理的更多信息,请参见 AccessControl 文档。

← Finance

Interfaces →

  • 原文链接: docs.openzeppelin.com/co...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
OpenZeppelin
OpenZeppelin
江湖只有他的大名,没有他的介绍。