治理

这个 crate 包括链上治理的原语。

Governor

这个模块化的 Governor 组件系统允许部署易于定制的链上投票协议。

有关如何实现 Governor 的演练,请查看 Governor 页面。

IGovernor

use openzeppelin_governance::governor::interface::IGovernor;

governor 合约的接口。

0x1100a1f8546595b5bd75a6cd8fcc5b015370655e66f275963321c5cd0357ac9

函数

name() → felt252 external

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

version() → felt252 external

governor 实例的版本(用于构建 SNIP-12 域分隔符)。

COUNTING_MODE() → ByteArray external

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

有两个标准键:supportquorum

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

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

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

如果计数模块使用了编码的 params,则应在 params 下包含此信息 键,并使用描述行为的唯一名称。例如:

  • params=fractional 可能指的是一种方案,其中投票以分数形式在 赞成/反对/弃权之间分配。

  • params=erc721 可能指的是一种方案,其中特定的 NFT 被委托进行投票。

该字符串可以被标准的 URLSearchParams JavaScript 类解码。

hash_proposal(calls: Span<Call>, description_hash: felt252) → felt252 external

用于从提案细节(重新)构建提案 id 的哈希函数。

state(proposal_id: felt252) → ProposalState external

返回提案的状态(给定其 id)。

proposal_threshold() → u256 external

选民成为提案人所需的票数。

proposal_snapshot(proposal_id: felt252) → u64 external

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

proposal_deadline(proposal_id: felt252) → u64 external

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

proposal_proposer(proposal_id: felt252) → ContractAddress external

创建提案的帐户。

proposal_eta(proposal_id: felt252) → u64 external

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

proposal_needs_queuing(proposal_id: felt252) → bool external

提案是否需要在执行前排队。这表明提案是否需要经过时间锁。

voting_delay() → u64 external

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

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

voting_period() → u64 external

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

voting_delay 可能会延迟投票的开始。在设置投票持续时间时,必须考虑这一点 与投票延迟相比。
此值在提交提案时存储,以便对该值的可能更改 不会影响已提交的提案。

quorum(timepoint: u64) → u256 external

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

timepoint 参数对应于用于计算投票的快照。这允许 法定人数根据该时间点的值(例如令牌的总供应量)进行调整。

get_votes(account: ContractAddress, timepoint: u64) → u256 external

返回 account 在特定 timepoint 的投票权。

这可以通过多种方式实现,例如通过从一个(或多个)ERC20Votes 令牌读取委托余额。

get_votes_with_params(account: ContractAddress, timepoint: u64, params: Span<felt252>) → u256 external

返回 account 在特定 timepoint 的投票权(给定额外的编码参数)。

has_voted(proposal_id: felt252, account: ContractAddress) → bool external

返回 account 是否已对提案进行投票。

propose(calls: Span<Call>, description: ByteArray) → felt252 external

创建一个新提案。投票在 voting_delay 指定的延迟后开始,持续时间为 voting_period 指定的时间。

Governor 和目标的状态可能在提案创建和执行之间发生变化。 这可能是目标合约上第三方操作或其 governor 提案的结果。 例如,此合约的余额可能会更新,或者其访问控制权限可能会被 修改,可能会损害提案成功执行的能力(例如,governor 没有足够的价值来覆盖具有多个转移的提案)。

返回提案的 id。

queue(calls: Span<Call>, description_hash: felt252) → felt252 external

对提案进行排队。某些 governor 要求在执行之前执行此步骤。 如果排队不是必需的,则此函数可能会回退。

对提案进行排需要达到法定人数,投票才能成功,并且必须达到 截止日期。

返回提案的 id。

execute(calls: span<Call>, description_hash: felt252) → felt252 external

执行成功的提案。这需要达到法定人数,投票才能 成功,并且必须达到截止日期。根据 governor 的不同,也可能需要 提案已排队并且经过了一些延迟。

有些模块可以修改执行的要求,例如通过添加 额外的时间锁(参见 timelock_controller)。

返回提案的 id。

cancel(calls: Span<Call>, description_hash: felt252) → felt252 external

取消提案。提案可以由提案人取消,但只能在 Pending 状态下取消,即在投票开始之前取消。

返回提案的 id。

cast_vote(proposal_id: felt252, support: u8) → u256 external

对提案进行投票。

返回投票的权重。

cast_vote_with_reason(proposal_id: felt252, support: u8, reason: ByteArray) → u256 external

对提案进行投票,并提供 reason

返回投票的权重。

cast_vote_with_reason_and_params(proposal_id: felt252, support: u8, reason: ByteArray, params: Span<felt252>) → u256 external

对提案进行投票,并提供理由和其他编码参数。

返回投票的权重。

cast_vote_by_sig(proposal_id: felt252, support: u8, voter: ContractAddress, signature: Span<felt252>) → u256 external

使用选民的签名对提案进行投票。

返回投票的权重。

cast_vote_with_reason_and_params_by_sig(proposal_id: felt252, support: u8, voter: ContractAddress, reason: ByteArray, params: Span<felt252>, signature: Span<felt252>) → u256 external

使用 voter 的签名对提案进行投票,并提供理由和其他编码参数。

返回投票的权重。

nonces(voter: ContractAddress) → felt252 external

返回地址的下一个未使用的 nonce。

relay(call: Call) external

将交易或函数调用传递到任意目标。

如果 governance 执行器是 governor 本身以外的某个合约,例如 当使用时间锁时,可以在 governance 提案中调用此函数以恢复 错误地发送到 governor 合约的令牌。

如果执行器只是 governor 本身,则使用 relay 是多余的。

事件

ProposalCreated(proposal_id: felt252, proposer: ContractAddress, calls: Span<Call>, signatures: Span<Span<felt252>>, vote_start: u64, vote_end: u64, description: ByteArray) event

在创建提案时发出。

ProposalQueued(proposal_id: felt252, eta_seconds: u64) event

在提案排队时发出。

ProposalExecuted(proposal_id: felt252) event

在执行提案时发出。

ProposalCanceled(proposal_id: felt252) event

在取消提案时发出。

VoteCast(voter: ContractAddress, proposal_id: felt252, support: u8, weight: u256, reason: ByteArray) event

在投票时发出。

VoteCastWithParams(voter: ContractAddress, proposal_id: felt252, support: u8, weight: u256, reason: ByteArray, params: Span<felt252>) event

在进行带参数的投票时发出。

GovernorComponent

use openzeppelin_governance::governor::GovernorComponent;

治理系统的核心。

下面介绍的扩展 trait 使 GovernorComponent 成为一个模块化和可配置的系统。可嵌入的 和内部实现取决于这些 trait。它们可以在合约本地实现,也可以通过提供的库 组件扩展
实施 SRC5Component 是本组件需要实现的要求。

扩展 trait 函数

voting_delay(self: @ContractState) → u64 extension

必须返回提案创建时间和投票开始时间之间的延迟(以时间点数表示)。可以 增加此值,以便在提案开始投票之前,用户有时间购买投票权或委托投票权。

voting_period(self: @ContractState) → u64 extension

必须返回投票开始和投票结束之间的延迟(以时间点数表示)。

proposal_threshold(self: @ContractState) → u256 extension

必须返回帐户创建提案必须具有的最小票数。

quorum(self: @ContractState, timepoint: u64) → u256 extension

必须返回提案成功所需的最低票数。

counting_mode(self: @ContractState) → ByteArray extension

必须返回对 cast_vote 的可能 support 值以及计算这些投票的方式的描述, 旨在被 UI 消耗,以显示正确的投票选项并解释结果。 有关更多详细信息,请参见 COUNTING_MODE

count_vote(ref self: ContractState, proposal_id: felt252, account: ContractAddress, support: u8, total_weight: u256, params: Span<felt252>) → u256 extension

必须使用给定的 support、投票 weight 和投票 paramsaccount 注册 proposal_id 的投票。

支持是通用的,可以根据使用的投票系统表示各种内容。

has_voted(self: @ContractState, proposal_id: felt252, account: ContractAddress) → bool extension

必须返回帐户是否已对提案进行投票。

quorum_reached(self: @ContractState, proposal_id: felt252) → bool extension

必须返回是否已达到提案的最低法定人数。

vote_succeeded(self: @ContractState, proposal_id: felt252) → bool extension

必须返回提案是否已成功。

clock(self: @ContractState) → u64 extension

返回由 governor 的操作模式确定的当前时间点,旨在用于时间敏感的逻辑- Pending:提案尚不存在。 - Active:提案处于活跃状态。 - Canceled:提案已被取消。 - Defeated:提案未通过。 - Succeeded:提案已通过。 - Queued:提案已进入队列。 - Executed:提案已执行。

executor(self: @ContractState) → ContractAddress internal

必须返回 governor 执行操作的地址。 应该用于指定模块是否通过另一个合约(例如时间锁)执行操作。

必须是 governor 本身,或者是将 governor 作为唯一提议者、取消者和执行者的 TimelockController 的实例。
当 executor 不是 governor 本身(即时间锁)时,它可以调用受 assert_only_governance 保护的函数,并且还可能代表 governor 执行交易。因此,此模块被设计为与作为唯一潜在外部 executor 的 TimelockController 一起工作。

execute_operations(ref self: ContractState, proposal_id: felt252, calls: Span<Call>) internal

执行机制。 可用于修改操作的执行方式(例如添加 vault/timelock)。

queue_operations(ref self: ContractState, proposal_id: felt252, calls: Span<Call>) internal

排队机制。 可用于修改排队执行的方式 (例如添加 vault/timelock)。

要求:

  • 必须返回一个时间戳,描述预期的执行 ETA。 如果返回的 值为 0,则核心将认为排队未成功,并且公共 queue 函数将回退。

proposal_needs_queuing(self: @ContractState) → bool internal

必须返回提案在执行前是否需要排队。 这通常表示提案是否需要通过时间锁。

cancel_operations(ref self: ContractState, proposal_id: felt252, calls: Span<Call>) internal

取消机制。 可用于修改取消执行的方式 (例如添加 vault/timelock)。

可嵌入的函数

name() → felt252 external

Governor 实例的名称(用于构建 SNIP-12 域分隔符)。

version() → felt252 external

Governor 实例的版本(用于构建 SNIP-12 域分隔符)。

COUNTING_MODE() → ByteArray external

cast_vote 的可能的 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 被委托进行投票。

该字符串可以被标准的 URLSearchParams JavaScript 类解码。

hash_proposal(calls: Span<Call>, description_hash: felt252) → felt252 external

用于从提案详细信息中(重新)构建提案 id 的散列函数。

state(proposal_id: felt252) → ProposalState external

返回给定 id 的提案的状态。

proposal_threshold() → u256 external

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

proposal_snapshot(proposal_id: felt252) → u64 external

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

proposal_deadline(proposal_id: felt252) → u64 external

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

proposal_proposer(proposal_id: felt252) → ContractAddress external

创建提案的帐户。

proposal_eta(proposal_id: felt252) → u64 external

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

proposal_needs_queuing(proposal_id: felt252) → bool external

提案在执行前是否需要排队。 这表示提案是否需要通过时间锁。

voting_delay() → u64 external

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

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

voting_period() → u64 external

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

voting_delay 可以延迟投票的开始。 在设置投票持续时间时,必须 考虑投票延迟。
此值在提交提案时存储,以便对 该值的可能更改不会影响已提交的提案。

quorum(timepoint: u64) → u256 external

提案成功所需的最小票数。

timepoint 参数对应于用于计算投票的快照。 这 允许法定人数根据时间点(例如令牌的总供应量)进行缩放。

get_votes(account: ContractAddress, timepoint: u64) → u256 external

返回 account 在特定 timepoint 的投票权。

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

get_votes_with_params(account: ContractAddress, timepoint: u64, params: Span<felt252>) → u256 external

返回具有附加编码参数的帐户在特定时间点的投票权。

has_voted(proposal_id: felt252, account: ContractAddress) → bool external

返回一个帐户是否已对提案投票。

propose(calls: Span<Call>, description: ByteArray) → felt252 external

创建一个新提案。 投票在 voting_delay 指定的延迟后开始,并 持续 voting_period 指定的持续时间。 返回提案的 id。

此函数具有选择加入抢跑保护,如 is_valid_description_for_proposer 中所述。

在提案创建之间, Governor 和目标的状态可能会发生变化 及其执行。 这可能是目标 合约上的第三方行为或其他 governor 提案的结果。 例如,此合约的余额 可能会更新,或者其访问控制权限可能会被修改,这可能会损害 提案成功执行的能力(例如,governor 没有足够的价值 来支付具有多个转移的提案)。

要求:

  • 提议者必须有权提交提案。

  • 如果 proposal_threshold 大于零,则提议者必须有足够的票数来提交提案。

  • 提案不得已存在。

发出 ProposalCreated 事件。

queue(calls: Span<Call>, description_hash: felt252) → felt252 external

将提案排队。 一些 governor 要求在执行可以 发生之前执行此步骤。 如果不需要排队,则此函数可能会回退。 对提案进行排队需要达到法定人数,投票成功,并且 达到截止时间。

返回提案的 id。

要求:

  • 提案必须处于 Succeeded 状态。

  • 队列操作必须返回非零 ETA。

发出 ProposalQueued 事件。

execute(calls: span<Call>, description_hash: felt252) → felt252 external

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

一些模块可以修改执行的要求,例如添加 额外的时间锁(参见 timelock_controller)。

返回提案的 id。

要求:

  • 提案必须处于 SucceededQueued 状态。

发出 ProposalExecuted 事件。

cancel(calls: Span<Call>, description_hash: felt252) → felt252 external

取消提案。 提案可以由提议者取消,但只能在其 Pending 状态下,即在投票开始之前。

返回提案的 id。

要求:

  • 提案必须处于 Pending 状态。

  • 调用者必须是提案的提议者。

发出 ProposalCanceled 事件。

cast_vote(proposal_id: felt252, support: u8) → u256 external

进行投票。

要求:

  • 提案必须处于活动状态。

发出 VoteCast 事件。

cast_vote_with_reason(proposal_id: felt252, support: u8, reason: ByteArray) → u256 external

使用 reason 进行投票。

要求:

  • 提案必须处于活动状态。

发出 VoteCast 事件。

cast_vote_with_reason_and_params(proposal_id: felt252, support: u8, reason: ByteArray, params: Span<felt252>) → u256 external

使用 reason 和附加的序列化 params 进行投票。

要求:

  • 提案必须处于活动状态。

发出以下事件之一:

cast_vote_by_sig(proposal_id: felt252, support: u8, voter: ContractAddress, signature: Span<felt252>) → u256 external

使用 voter 的签名进行投票。

要求:

  • 提案必须处于活动状态。

  • 签名消息中的 nonce 必须与帐户的当前 nonce 匹配。

  • voter 必须实现 SRC6::is_valid_signature

  • signature 对于消息散列必须有效。

发出 VoteCast 事件。

cast_vote_with_reason_and_params_by_sig(proposal_id: felt252, support: u8, voter: ContractAddress, reason: ByteArray, params: Span<felt252>, signature: Span<felt252>) → u256 external

使用 voter 的签名,使用 reason 和附加的序列化 params 进行投票。

要求:

  • 提案必须处于活动状态。

  • 签名消息中的 nonce 必须与帐户的当前 nonce 匹配。

  • voter 必须实现 SRC6::is_valid_signature

  • signature 对于消息散列必须有效。

发出以下事件之一:

nonces(voter: ContractAddress) → felt252 external

返回地址的下一个未使用的 nonce。

relay(call: Call) external

将交易或函数调用中继到任意目标。

在 governance 执行器是 governor 本身以外的某个合约的情况下,例如 在使用时间锁时,可以在 governance 提案中调用此函数以恢复 错误发送到 governor 合约的令牌。

如果 executor 只是 governor 本身,则使用 relay 是多余的。

内部函数

initializer(ref self: ContractState) internal

通过注册支持的接口 id 来初始化合约。

get_proposal(self: @ContractState, proposal_id: felt252) → ProposalCore internal

返回给定 id 的提案对象。

is_valid_description_for_proposer(self: @ContractState, proposer: ContractAddress, description: ByteArray) → bool internal

检查提议者是否有权提交具有给定描述的提案。

如果提案描述以 #proposer=0x??? 结尾,其中 0x??? 是 以十六进制字符串(不区分大小写)编写的地址,则此提案的提交将 仅授权给所述地址。

这用于抢跑保护。 通过在他们 提案的末尾添加此模式,可以确保没有其他地址可以提交相同的提案。 攻击者 将不得不删除或更改该部分,这将导致不同的 提案 id。

在 Starknet 中,Sequencer 确保交易的顺序,但抢跑 仍然可以通过节点实现,并且未来可能会通过 sequencer 去中心化实现。

如果描述与此模式不匹配,则不受限制,任何人都可以提交 它。 这包括:

  • 如果 0x??? 部分不是有效的十六进制字符串。

  • 如果 0x??? 部分是有效的十六进制字符串,但不包含正好 64 个十六进制数字。

  • 如果它以预期的后缀结尾,后跟换行符或其他空格。

  • 如果它以一些其他类似的后缀结尾,例如 #other=abc

  • 如果它不以任何此类后缀结尾。

_hash_proposal(self: @ContractState, calls: Span<Call>, description_hash: felt252) → felt252 internal

从给定参数计算的提案 id。

提案 id 计算为 Pedersen 哈希值:

  • 被提议的调用数组

  • 描述哈希

_proposal_snapshot(self: @ContractState, proposal_id: felt252) → u64 internal

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

_proposal_deadline(self: @ContractState, proposal_id: felt252) → u64 internal

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

_proposal_proposer(self: @ContractState, proposal_id: felt252) → ContractAddress internal

创建提案的帐户。

_proposal_eta(self: @ContractState, proposal_id: felt252) → u64 internal

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

assert_only_governance(self: @ContractState) internal

断言调用者是 governance 执行器。

当 executor 不是 governor 本身(即时间锁)时,它可以调用 受此修饰符限制的函数,并且还可能代表 governor 执行 交易。 因此,此模块被设计为与 TimelockController 作为唯一的潜在外部 executor 一起工作。 时间锁 必须将 governor 作为唯一的提议者、取消者和执行者。

validate_state(self: @ContractState, proposal_id: felt252, state: ProposalState) internal

验证提案是否处于预期状态。 否则会发生 panic。

use_nonce(ref self: ContractState) → felt252 internal

使用一个 nonce,返回当前值,并递增 nonce。

_get_votes(self: @ContractState, account: ContractAddress, timepoint: u64, params: Span<felt252>) → u256 internal

GovernorVotesTrait::get_votes 的内部包装器。

_proposal_threshold(self: @ContractState) → u256 internal

GovernorProposeTrait::proposal_threshold 的内部包装器。

_state(self: @ContractState, proposal_id: felt252) → ProposalState internal

返回给定 id 的提案的状态。

要求:

  • 提案必须存在。

_propose(ref self: ContractState, calls: Span<Call>, description_hash: felt252) → felt252 internal

内部提议机制。 返回提案 id。

要求:

  • 提案不得已存在。

发出 ProposalCreated 事件。

_cancel(ref self: ContractState, proposal_id: felt252) internal

具有最小限制的内部取消机制。

提案可以在除 Canceled 或 Executed 之外的任何状态下取消。

取消后,无法重新提交提案。

_count_vote(ref self: ContractState, proposal_id: felt252, account: ContractAddress, support: u8, weight: u256, params: Span<felt252>) internal

GovernorCountingTrait::count_vote 的内部包装器。

_cast_vote(ref self: ContractState, proposal_id: felt252, account: ContractAddress, support: u8, reason: ByteArray, params: Span<felt252>) → u256 internal

内部投票机制。

检查投票是否待定以及是否尚未进行投票。 此函数使用 get_votes 检索投票权重,然后调用 _count_vote 内部函数。

发出以下事件之一:

事件

ProposalCreated(proposal_id: felt252, proposer: ContractAddress, calls: Span<Call>, signatures: Span<Span<felt252>>, vote_start: u64, vote_end: u64, description: ByteArray) event

创建提案时发出。

ProposalQueued(proposal_id: felt252, eta_seconds: u64) event

提案排队时发出。

ProposalExecuted(proposal_id: felt252) event

提案执行时发出。

ProposalCanceled(proposal_id: felt252) event

提案取消时发出。

VoteCast(voter: ContractAddress, proposal_id: felt252, support: u8, weight: u256, reason: ByteArray) event

投票时发出。

VoteCastWithParams(voter: ContractAddress, proposal_id: felt252, support: u8, weight: u256, reason: ByteArray, params: Span<felt252>) event

使用参数投票时发出。

Governor 扩展

Governor 组件可以(并且必须)通过实现 扩展 traits 来扩展,以添加所需的功能。 这可以通过直接在您的合约上实现这些 traits 来实现,或者通过使用库提供的一组现成的扩展来实现, 这些扩展如下所示。

GovernorCoreExecutionComponent

use openzeppelin_governance::governor::extensions::GovernorCoreExecutionComponent;

GovernorComponent 的扩展,提供直接通过 Governor 本身的执行机制。 对于时间锁定的执行机制,请参见 GovernorTimelockExecutionComponent

扩展 traits 函数

state(self: @ContractState, proposal_id: felt252) → ProposalState internal

返回给定 id 的提案状态。

要求:

  • 提案必须存在。

executor(self: @ContractState) → ContractAddress internal

返回 executor 地址。

在这种情况下,它返回 governor 合约地址,因为执行是直接通过它执行的。

execute_operations(ref self: ContractState, proposal_id: felt252, calls: Span<Call>, description_hash: felt252) internal

直接通过 governor 合约执行提案的操作。

queue_operations(ref self: ContractState, proposal_id: felt252, calls: Span<Call>, description_hash: felt252) → u64 internal

在此实现中,不需要排队,因此它返回 0。

proposal_needs_queuing(self: @ContractState, proposal_id: felt252) → bool internal

在此实现中,它始终返回 false。

cancel_operations(ref self: ContractState, proposal_id: felt252, description_hash: felt252) internal

取消提案的操作。

GovernorCountingSimpleComponent

use openzeppelin_governance::governor::extensions::GovernorCountingSimpleComponent;

GovernorComponent 的扩展,用于具有三个选项的简单投票计数。

扩展 traits 函数

counting_mode(self: @ContractState) → ByteArray internal

返回 "support=bravo&quorum=for,abstain"

  • support=bravo 表示支持遵循 Governor Bravo 格式,其中投票者可以投票赞成、反对或弃权

  • quorum=for,abstain 表示赞成票和弃权票都计入法定人数

count_vote(ref self: ContractState, proposal_id: felt252, account: ContractAddress, support: u8, total_weight: u256, params: Span<felt252>) → u256 internal

记录提案的投票。

支持值遵循 VoteType 枚举(0=反对、1=赞成、2=弃权)。

返回被计数的权重。

has_voted(self: @ContractState, proposal_id: felt252, account: ContractAddress) → bool internal

返回一个帐户是否已对提案投票。

quorum_reached(self: @ContractState, proposal_id: felt252) → bool internal

返回提案是否已达到法定人数。

在此实现中,赞成票和弃权票都计入法定人数。

vote_succeeded(self: @ContractState, proposal_id: felt252) → bool internal

返回提案是否已成功。

在此实现中,赞成票必须严格大于反对票。

GovernorSettingsComponent

use openzeppelin_governance::governor::extensions::GovernorSettingsComponent;

GovernorComponent 的扩展,用于可以通过 governance 更新的设置。

==== 扩展 traits 函数

==== voting_delay(self: @ContractState) → u64 internal

返回一个提案被创建到投票开始之间的延迟。

==== voting_period(self: @ContractState) → u64 internal

返回投票可以进行的时间段。

==== proposal_threshold(self: @ContractState) → u256 internal

返回一个账户创建提案所需的最小投票数。

==== 可嵌入函数

==== set_voting_delay(ref self: ContractState, new_voting_delay: u64) external

设置投票延迟。

要求:

  • 调用者必须是 governance executor。

如果新的投票延迟与旧的相同,则此函数不会发出事件。

可能会发出一个 VotingDelayUpdated 事件。

==== set_voting_period(ref self: ContractState, new_voting_period: u64) external

设置投票周期。

如果新的投票周期与旧的周期相同,则此函数不会发出事件 旧的投票周期。

要求:

  • 调用者必须是 governance executor。

  • new_voting_period 必须大于 0。

可能会发出一个 VotingPeriodUpdated 事件。

==== set_proposal_threshold(ref self: ContractState, new_proposal_threshold: u256) external

设置提案阈值。

如果新的提案阈值与该阈值相同,则此函数不会发出事件 旧的阈值。

要求:

  • 调用者必须是 governance executor。

可能会发出一个 ProposalThresholdUpdated 事件。

==== 内部函数

==== initializer(ref self: ContractState, initial_voting_delay: u64, initial_voting_period: u64, initial_proposal_threshold: u256) internal

通过设置默认值来初始化组件。

要求:

  • new_voting_period 必须大于 0。

==== assert_only_governance(ref self: ContractState) internal

断言调用者是 governance executor。

==== _set_voting_delay(ref self: ContractState, new_voting_delay: u64) internal

用于更新投票延迟的内部函数。

如果新的投票延迟与该延迟相同,则此函数不会发出事件 旧的那个。

可能会发出一个 VotingDelayUpdated 事件。

==== _set_voting_period(ref self: ContractState, new_voting_period: u64) internal

用于更新投票周期的内部函数。

要求:

  • new_voting_period 必须大于 0。

如果新的投票周期与旧的周期相同,则此函数不会发出事件。

可能会发出一个 VotingPeriodUpdated 事件。

==== _set_proposal_threshold(ref self: ContractState, new_proposal_threshold: u256) internal

用于更新提案阈值的内部函数。

如果新的提案阈值与旧的阈值相同,则此函数不会发出事件。

可能会发出一个 ProposalThresholdUpdated 事件。

==== 事件

==== VotingDelayUpdated(old_voting_delay: u64, new_voting_delay: u64) event

当投票延迟更新时发出。

==== VotingPeriodUpdated(old_voting_period: u64, new_voting_period: u64) event

当投票周期更新时发出。

==== ProposalThresholdUpdated(old_proposal_threshold: u256, new_proposal_threshold: u256) event

当提案阈值更新时发出。

=== GovernorVotesComponent

use openzeppelin_governance::governor::extensions::GovernorVotesComponent;

GovernorComponent 的扩展,用于从具有 IVotes 的 token 中提取投票权重 扩展。

VotesTokenImpl

==== 扩展 traits 函数

==== clock(self: @ContractState) → u64 internal

返回由 governor 的操作模式确定的当前时间点,旨在用于对时间敏感的逻辑。 参见 ERC-6372#clock

要求:

  • 此函数必须始终是非递减的。

==== CLOCK_MODE(self: @ContractState) → ByteArray internal

返回对 governor 正在运行的时钟的描述。 参见 ERC-6372#CLOCK_MODE

要求:

  • 输出的格式必须像 URL 查询字符串,可以在标准 JavaScript 中解码。

==== get_votes(self: @ContractState, account: ContractAddress, timepoint: u64, params: Span<felt252>) → u256 internal

使用 votes token 返回 account 在特定 timepoint 的投票权。

==== 可嵌入函数

==== token(self: @ContractState) → ContractAddress external

返回投票权来源的 votes token。

==== 内部函数

==== initializer(ref self: ContractState, votes_token: ContractAddress) internal

通过设置 votes token 来初始化组件。

要求:

  • votes_token 不能为零。

=== GovernorVotesQuorumFractionComponent

use openzeppelin_governance::governor::extensions::GovernorVotesQuorumFractionComponent;

GovernorComponent 的扩展,用于从具有 IVotes 扩展的 token 中提取投票权重,以及以总供应量的一部分表示的法定人数。

GovernorQuorum

==== 扩展 traits 函数

==== quorum(self: @ContractState, timepoint: u64) → u256 internal

它被计算为过去给定 timepoint 的 votes token 总供应量的百分比。

==== clock(self: @ContractState) → u64 internal

返回由 governor 的操作模式确定的当前时间点,旨在用于对时间敏感的逻辑。 参见 ERC-6372#clock

要求:

  • 此函数必须始终是非递减的。

==== CLOCK_MODE(self: @ContractState) → ByteArray internal

返回对 governor 正在运行的时钟的描述。 参见 ERC-6372#CLOCK_MODE

要求:

  • 输出的格式必须像 URL 查询字符串,可以在标准 JavaScript 中解码。

==== get_votes(self: @ContractState, account: ContractAddress, timepoint: u64, params: Span<felt252>) → u256 internal

使用 votes token 返回 account 在特定 timepoint 的投票权。

==== 可嵌入函数

==== token(self: @ContractState) → ContractAddress external

返回用于提取投票权的 votes token 的地址。

==== current_quorum_numerator(self: @ContractState) → u256 external

返回当前的 quorum numerator 值。

==== quorum_numerator(self: @ContractState, timepoint: u64) → u256 external

返回过去特定 timepoint 的 quorum numerator 值。

==== quorum_denominator(self: @ContractState) → u256 external

返回 quorum denominator 值。

==== 内部函数

==== initializer(self: @ComponentState<TContractState>, votes_token: ContractAddress, quorum_numerator: u256) internal

通过设置 votes token 和初始 quorum numerator 值来初始化组件。

要求:

  • votes_token 不能为零。

  • quorum_numerator 必须小于 quorum_denominator

发出一个 QuorumNumeratorUpdated 事件。

==== update_quorum_numerator(self: @ComponentState<TContractState>, new_quorum_numerator: u256) internal

更新 quorum numerator。

如果新的 quorum numerator 与旧的相同,则此函数不会发出事件。

要求:

  • new_quorum_numerator 必须小于 quorum_denominator

可能会发出一个 QuorumNumeratorUpdated 事件。

==== 事件

==== QuorumNumeratorUpdated(old_quorum_numerator: u256, new_quorum_numerator: u256) event

当 quorum numerator 更新时发出。

=== GovernorTimelockExecutionComponent

use openzeppelin_governance::governor::extensions::GovernorTimelockExecutionComponent;

GovernorComponent 的扩展,它将执行过程绑定到实现 TimelockControllerComponent 的合约实例。这增加了由 timelock 强制执行的延迟, 对于所有成功的提案(除了投票持续时间)。

Governor 需要 PROPOSER、EXECUTOR 和 CANCELLER 角色 才能正常工作。

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

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

==== 扩展 traits 函数

==== state(self: @ContractState, proposal_id: felt252) → ProposalState internal

返回给定 id 的提案状态。

要求:

  • 提案必须存在。

==== executor(self: @ContractState) → ContractAddress internal

返回 executor 地址。

在此模块中,executor 是 timelock controller。

==== execute_operations(ref self: ContractState, proposal_id: felt252, calls: Span<Call>, description_hash: felt252) internal

通过 timelock 运行已排队的提案。

==== queue_operations(ref self: ContractState, proposal_id: felt252, calls: Span<Call>, description_hash: felt252) → u64 internal

将提案排队到 timelock。

返回已排队提案执行的 eta。

==== proposal_needs_queuing(self: @ContractState, proposal_id: felt252) → bool internal

在此实现中,它始终返回 true。

==== cancel_operations(ref self: ContractState, proposal_id: felt252, description_hash: felt252) internal

如果已经排队,则取消 timelock 的提案。

==== 可嵌入函数

==== timelock(self: @ContractState) → ContractAddress external

返回 timelock controller 地址。

==== get_timelock_id(self: @ContractState) → felt252 external

返回给定提案 id 的 timelock 提案 id。

==== update_timelock(ref self: ContractState, new_timelock: ContractAddress) external

更新关联的 timelock。

要求:

  • 调用者必须是 governance。

发出一个 TimelockUpdated 事件。

==== 内部函数

==== initializer(ref self: ContractState, timelock: ContractAddress) internal

初始化 timelock controller。

要求:

  • timelock 不能为零地址。

==== assert_only_governance(self: @ContractState) internal

确保调用者是 executor(在本例中为 timelock controller)。

==== timelock_salt(self: @ContractState, description_hash: felt252) → felt252 internal

TimelockController 操作 salt 计算为 governor 地址和 description_hash 的 XOR。

它使用 governor 地址本身进行计算,以避免跨 governor 实例使用相同的 timelock 发生冲突。

==== get_timelock_dispatcher(self: @ContractState) → ITimelockDispatcher internal

返回用于与 timelock controller 交互的 dispatcher。

==== _update_timelock(ref self: ContractState, new_timelock: ContractAddress) internal

用于更新 timelock controller 地址的内部函数。

发出一个 TimelockUpdated 事件。

==== 事件

==== TimelockUpdated(old_timelock: ContractAddress, new_timelock: ContractAddress) event

当 timelock controller 更新时发出。

== Multisig

Multisig 模块通过要求多个签名者批准和执行交易来增强安全性并实现去中心化。功能包括可配置的法定人数、签名者管理和自我管理,确保关键操作的集体决策和透明度。

=== IMultisig

use openzeppelin_governance::multisig::interface::IMultisig;

Multisig 合约的接口。

==== 函数

==== get_quorum() → u32 external

返回当前的法定人数值。法定人数是批准交易所需的最小确认数。

==== is_signer(signer: ContractAddress) → bool external

返回给定的 signer 是否已在注册。只有注册的签名者才能提交、确认或执行交易。

==== get_signers() → Span<ContractAddress> external

返回所有当前签名者的列表。

==== is_confirmed(id: TransactionID) → bool external

返回是否已确认具有给定 id 的交易。

==== is_confirmed_by(id: TransactionID, signer: ContractAddress) → bool external

返回具有给定 id 的交易是否已由指定的 signer 确认。

==== is_executed(id: TransactionID) → bool external

返回是否已执行具有给定 id 的交易。

==== get_submitted_block(id: TransactionID) → u64 external

返回提交具有给定 id 的交易时所在的区块号。

==== get_transaction_state(id: TransactionID) → TransactionState external

返回具有给定 id 的交易的当前状态。

==== get_transaction_confirmations(id: TransactionID) → u32 external

返回来自已注册的签名者、对具有指定 id 的交易的确认数。

==== hash_transaction(to: ContractAddress, selector: felt252, calldata: Span<felt252>, salt: felt252) → TransactionID external

返回包含单个调用的交易的计算标识符。

==== `hash_transaction_batch++(calls: Span<Call>, salt: felt如果仲裁人数发生变化,则发出 QuorumUpdated 事件。

==== replace_signer(signer_to_remove: ContractAddress, signer_to_add: ContractAddress) external

用新的签名者替换现有的签名者。

要求:

  • 调用者必须是合约本身。

  • signer_to_remove 必须是现有的签名者。

  • signer_to_add 不能是现有的签名者。

为被移除的签名者发出 SignerRemoved 事件。

为新的签名者发出 SignerAdded 事件。

==== change_quorum(new_quorum: u32) external

如果 new_quorum 与当前仲裁人数不同,则将仲裁人数更新为 new_quorum

要求:

  • 调用者必须是合约本身。

  • new_quorum 必须为非零值。

  • new_quorum 必须小于或等于签名者的总数。

如果仲裁人数发生变化,则发出 QuorumUpdated 事件。

==== submit_transaction(to: ContractAddress, selector: felt252, calldata: Span<felt252>, salt: felt252) → TransactionID external

提交一个新的交易以供确认。

要求:

  • 调用者必须是已注册的签名者。

  • 这笔交易之前不能被提交过。

发出 TransactionSubmitted 事件。

如果 salt 不为零,则发出 CallSalt 事件。

==== submit_transaction_batch(calls: Span<Call>, salt: felt252) → TransactionID external

提交一个新的批量交易以供确认。

要求:

  • 调用者必须是已注册的签名者。

  • 这笔交易之前不能被提交过。

发出 TransactionSubmitted 事件。

如果 salt 不为零,则发出 CallSalt 事件。

==== confirm_transaction(id: TransactionID) external

确认具有给定 id 的交易。

要求:

  • 调用者必须是已注册的签名者。

  • 交易必须存在且未被执行。

  • 调用者之前不能确认过该交易。

发出 TransactionConfirmed 事件。

==== revoke_confirmation(id: TransactionID) external

撤销先前对具有给定 id 的交易的确认。

要求:

  • 交易必须存在且未被执行。

  • 调用者之前必须确认过该交易。

发出 ConfirmationRevoked 事件。

==== execute_transaction(to: ContractAddress, selector: felt252, calldata: Span<felt252>, salt: felt252) external

执行已确认的交易。

要求:

  • 调用者必须是已注册的签名者。

  • 交易必须被确认且尚未执行。

发出 TransactionExecuted 事件。

==== execute_transaction_batch(calls: Span<Call>, salt: felt252) external

执行已确认的批量交易。

要求:

  • 调用者必须是已注册的签名者。

  • 交易必须被确认且尚未执行。

发出 TransactionExecuted 事件。

==== 事件

==== SignerAdded(signer: ContractAddress) event

当添加新的 signer 时发出。

==== SignerRemoved(signer: ContractAddress) event

signer 被移除时发出。

==== QuorumUpdated(old_quorum: u32, new_quorum: u32) event

quorum 值更新时发出。

==== TransactionSubmitted(id: TransactionID, signer: ContractAddress) event

当新的交易由 signer 提交时发出。

==== TransactionConfirmed(id: TransactionID, signer: ContractAddress) event

当交易被 signer 确认时发出。

==== ConfirmationRevoked(id: TransactionID, signer: ContractAddress) event

signer 撤销其确认时发出。

==== TransactionExecuted(id: TransactionID) event

当交易被执行时发出。

==== CallSalt(id: felt252, salt: felt252) event

当提交带有非零 salt 的新交易时发出。

=== MultisigComponent

use openzeppelin_governance::multisig::MultisigComponent;

实现了 IMultisig 并为多重签名钱包提供功能的组件, 包括交易管理、仲裁处理和签名者操作。

==== 可嵌入的函数

==== get_quorum(self: @ContractState) → u32 external

返回当前的仲裁人数值。

==== is_signer(self: @ContractState, signer: ContractAddress) → bool external

检查给定的 signer 是否已注册。

==== get_signers(self: @ContractState) → Span<ContractAddress> external

返回所有当前签名者的列表。

==== is_confirmed(self: @ContractState, id: TransactionID) → bool external

返回具有给定 id 的交易是否已确认。 已确认的交易已收到所需的确认数量(仲裁人数)。

==== is_confirmed_by(self: @ContractState, id: TransactionID, signer: ContractAddress) → bool external

返回具有给定 id 的交易是否已由指定的 signer 确认。

==== is_executed(self: @ContractState, id: TransactionID) → bool external

返回具有给定 id 的交易是否已执行。

==== get_submitted_block(self: @ContractState, id: TransactionID) → u64 external

返回提交具有给定 id 的交易时的区块号。

==== get_transaction_state(self: @ContractState, id: TransactionID) → TransactionState external

返回具有给定 id 的交易的当前状态。

可能的状态为:

  • NotFound:交易不存在。

  • Pending:交易存在但尚未达到所需的确认数。

  • Confirmed:交易已达到所需的确认数但尚未执行。

  • Executed:交易已执行。

==== get_transaction_confirmations(self: @ContractState, id: TransactionID) → u32 external

返回来自已注册签名者的、用于指定 id 的交易的确认数。

==== hash_transaction(self: @ContractState, to: ContractAddress, selector: felt252, calldata: Span<felt252>, salt: felt252) external

返回包含单个调用的交易的计算标识符。

==== hash_transaction_batch(self: @ContractState, calls: Span<Call>, salt: felt252) external

返回包含一批调用的交易的计算标识符。

==== add_signers(ref self: ContractState, new_quorum: u32, signers_to_add: Span<ContractAddress>) external

添加新的签名者并更新仲裁人数。

要求:

  • 调用者必须是合约本身。

  • new_quorum 必须小于或等于添加后签名者的总数。

为每个添加的签名者发出 SignerAdded 事件。

如果仲裁人数发生变化,则发出 QuorumUpdated 事件。

==== remove_signers(ref self: ContractState, new_quorum: u32, signers_to_remove: Span<ContractAddress>) external

移除签名者并更新仲裁人数。

要求:

  • 调用者必须是合约本身。

  • new_quorum 必须小于或等于移除后签名者的总数。

为每个移除的签名者发出 SignerRemoved 事件。

如果仲裁人数发生变化,则发出 QuorumUpdated 事件。

==== replace_signer(ref self: ContractState, signer_to_remove: ContractAddress, signer_to_add: ContractAddress) external

用新的签名者替换现有的签名者。

要求:

  • 调用者必须是合约本身。

  • signer_to_remove 必须是现有的签名者。

  • signer_to_add 不能是现有的签名者。

为被移除的签名者发出 SignerRemoved 事件。

为新的签名者发出 SignerAdded 事件。

==== change_quorum(ref self: ContractState, new_quorum: u32) external

将仲裁人数值更新为 new_quorum

要求:

  • 调用者必须是合约本身。

  • new_quorum 必须为非零值。

  • new_quorum 必须小于或等于签名者的总数。

如果仲裁人数发生变化,则发出 QuorumUpdated 事件。

==== submit_transaction(ref self: ContractState, to: ContractAddress, selector: felt252, calldata: Span<felt252>, salt: felt252) external

提交一个新的交易以供确认。

要求:

  • 调用者必须是已注册的签名者。

  • 这笔交易之前不能被提交过。

发出 TransactionSubmitted 事件。

如果 salt 不为零,则发出 CallSalt 事件。

==== submit_transaction_batch(ref self: ContractState, calls: Span<Call>, salt: felt252) external

提交一个新的批量交易以供确认。

要求:

  • 调用者必须是已注册的签名者。

  • 这笔交易之前不能被提交过。

发出 TransactionSubmitted 事件。

如果 salt 不为零,则发出 CallSalt 事件。

==== confirm_transaction(ref self: ContractState, id: TransactionID) external

确认具有给定 id 的交易。

要求:

  • 调用者必须是已注册的签名者。

  • 交易必须存在且未被执行。

  • 调用者之前不能确认过该交易。

发出 TransactionConfirmed 事件。

==== revoke_confirmation(ref self: ContractState, id: TransactionID) external

撤销先前对具有给定 id 的交易的确认。

要求:

  • 交易必须存在且未被执行。

  • 调用者之前必须确认过该交易。

发出 ConfirmationRevoked 事件。

==== execute_transaction(ref self: ContractState, to: ContractAddress, selector: felt252, calldata: Span<felt252>, salt: felt252) external

执行已确认的交易。

要求:

  • 调用者必须是已注册的签名者。

  • 交易必须被确认且尚未执行。

发出 TransactionExecuted 事件。

==== execute_transaction_batch(ref self: ContractState, calls: Span<Call>, salt: felt252) external

执行已确认的批量交易。

要求:

  • 调用者必须是已注册的签名者。

  • 交易必须被确认且尚未执行。

发出 TransactionExecuted 事件。

==== 内部函数

==== initializer(ref self: ContractState, quorum: u32, signers: Span<ContractAddress>) internal

使用初始 quorumsigners 初始化 Multisig 组件。 必须在合约初始化期间调用此函数以设置初始状态。

要求:

  • quorum 必须为非零值,且小于或等于 signers 的数量。

为每个添加的签名者发出 SignerAdded 事件。

发出 QuorumUpdated 事件。

==== resolve_tx_state(self: @ContractState, id: TransactionID) → TransactionState internal

解析并返回具有给定 id 的交易的当前状态。

可能的状态为:

  • NotFound:交易不存在。

  • Pending:交易存在但尚未达到所需的确认数。

  • Confirmed:交易已达到所需的确认数但尚未执行。

  • Executed:交易已执行。

==== assert_one_of_signers(self: @ContractState, caller: ContractAddress) internal

断言 caller 是已注册的签名者之一。

要求:

  • caller 必须是已注册的签名者。

==== assert_tx_exists(self: @ContractState, id: TransactionID) internal

断言具有给定 id 的交易存在。

要求:

  • 具有给定 id 的交易必须已提交。

==== assert_only_self(self: @ContractState) internal

断言调用者是合约本身。

要求:

  • 调用者必须是合约自身的地址。

==== _add_signers(ref self: ContractState, new_quorum: u32, signers_to_add: Span<ContractAddress>) internal

添加新的签名者并更新仲裁人数。

要求:

  • 每个签名者地址都不能为零。

  • new_quorum 必须为非零值,且小于或等于添加后签名者的总数。

为每个新添加的签名者发出 SignerAdded 事件。

如果仲裁人数发生变化,则发出 QuorumUpdated 事件。

==== _remove_signers(ref self: ContractState, new_quorum: u32, signers_to_remove: Span<ContractAddress>) internal

移除现有的签名者并更新仲裁人数。

要求:

  • new_quorum 必须为非零值,且小于或等于移除后签名者的总数。

为每个移除的签名者发出 SignerRemoved 事件。

如果仲裁人数发生变化,则发出 QuorumUpdated 事件。

==== _replace_signer(ref self: ContractState, signer_to_remove: ContractAddress, signer_to_add: ContractAddress) internal

用新的签名者替换现有的签名者。

要求:

  • signer_to_remove 必须是现有的签名者。

  • signer_to_add 不能是现有的签名者。

  • signer_to_add 必须是非零地址。

为被移除的签名者发出 SignerRemoved 事件。

为新的签名者发出 SignerAdded 事件。

==== _change_quorum(ref self: ContractState, new_quorum: u32) internal

如果 new_quorum 与当前仲裁人数不同,则将仲裁人数值更新为 new_quorum

要求:

  • new_quorum 必须为非零值。

  • new_quorum 必须小于或等于签名者的总数。

如果仲裁人数发生变化,则发出 QuorumUpdated 事件。

==== 事件

==== SignerAdded(signer: ContractAddress) event

当添加新的 signer 时发出。

==== SignerRemoved(signer: ContractAddress) event

signer 被移除时发出。

==== QuorumUpdated(old_quorum: u32, new_quorum: u32) event

quorum 值更新时发出。

==== TransactionSubmitted(id: TransactionID, signer: ContractAddress) event

当新的交易由 signer 提交时发出。

==== TransactionConfirmed(id: TransactionID, signer: ContractAddress) event

当交易被 signer 确认时发出。

==== ConfirmationRevoked(id: TransactionID, signer: ContractAddress) event

signer 撤销其确认时发出。

==== TransactionExecuted(id: TransactionID) event

当交易被执行时发出。

==== CallSalt(id: felt252, salt: felt252) event

当提交带有非零 salt 的新交易时发出。

== 时间锁

在治理系统中,TimelockControllerComponent 负责在提案和执行之间引入延迟。

=== ITimelock

use openzeppelin_governance::timelock::interface::ITimelock;

时间锁合约的接口。

==== 函数

==== is_operation(id: felt252) → bool external

返回 id 是否对应于已注册的操作。 这包括 OperationStates: WaitingReadyDone

==== is_operation_pending(id: felt252) → bool external

返回 id OperationState 是否为待处理。 请注意,待处理的操作可能是 WaitingReady

==== is_operation_ready(id: felt252) → bool external

返回 id OperationState 是否为 Ready

==== is_operation_done(id: felt252) → bool external

返回 id OperationState 是否为 Done

==== get_timestamp(id: felt252) → u64 external

返回 id 变为 Ready 的时间戳。

注意:0 表示 OperationState 为 Unset1 表示 OperationState 为 Done

==== get_operation_state(id: felt252) → OperationState- 调用者必须具有 `PROPOSER_ROLE 角色。

触发 CallScheduled 事件。 如果 salt 非零,则触发 CallSalt 事件。

==== schedule_batch(calls: Span<Call>, predecessor: felt252, salt: felt252, delay: u64) external

安排一个包含一批事务的操作。

要求:

  • 调用者必须具有 PROPOSER_ROLE 角色。

为批处理中的每个事务触发一个 CallScheduled 事件。 如果 salt 非零,则触发 CallSalt 事件。

==== cancel(id: felt252) external

取消一个操作。已取消的操作将返回到 Unset OperationState。

要求:

  • 调用者必须具有 CANCELLER_ROLE 角色。

  • id 必须是待处理的操作。

触发一个 CallCancelled 事件。

==== execute(call: Call, predecessor: felt252, salt: felt252) external

执行一个(准备就绪)操作,其中包含单个 Call。

要求:

  • 调用者必须具有 EXECUTOR_ROLE

  • id 必须处于 Ready OperationState。

  • predecessor 必须是 0 或处于 Done OperationState。

触发一个 CallExecuted 事件。

此函数可以重入,但它不会带来风险,因为 [TimelockControllerComponent-_after_call] 检查提案是否待处理,因此在重入期间对操作的任何修改都应被捕获。

==== execute_batch(calls: Span<Call>, predecessor: felt252, salt: felt252) external

执行一个(准备就绪)操作,其中包含一批 Calls。

要求:

  • 调用者必须具有 EXECUTOR_ROLE

  • id 必须处于 Ready OperationState。

  • predecessor 必须是 0 或处于 Done OperationState。

为每个 Call 触发一个 CallExecuted 事件。

此函数可以重入,但它不会带来风险,因为 _after_call 检查提案是否待处理,因此在重入期间对操作的任何修改都应被捕获。

==== update_delay(new_delay: u64) external

更改未来操作的最小时间锁持续时间。

要求:

  • 调用者必须是时间锁本身。这只能通过调度来实现 并在稍后执行一个操作,其中时间锁是目标,数据 是对该函数的序列化调用。

触发一个 MinDelayChanged 事件。

==== 事件

==== CallScheduled(id: felt252, index: felt252, call: Call, predecessor: felt252, delay: u64) event

call 作为操作 id 的一部分被调度时触发。

==== CallExecuted(id: felt252, index: felt252, call: Call) event

call 作为操作 id 的一部分执行时触发。

==== CallSalt(id: felt252, salt: felt252) event

当使用非零 salt 调度新提案时触发。

==== CallCancelled(id: felt252) event

当操作 id 被取消时触发。

==== MinDelayChanged(old_duration: u64, new_duration: u64) event

当修改未来操作的最小延迟时触发。

=== TimelockControllerComponent

use openzeppelin_governance::timelock::TimelockControllerComponent;

实现 ITimelock 并使实现合约充当时间锁控制器的组件。

==== 可嵌入的函数

==== is_operation(self: @ContractState, id: felt252) → bool external

返回 id 是否对应于已注册的操作。 这包括 OperationStates:WaitingReadyDone

==== is_operation_pending(self: @ContractState, id: felt252) → bool external

返回 id OperationState 是否待处理。 请注意,待处理的操作可以是 WaitingReady

==== is_operation_ready(self: @ContractState, id: felt252) → bool external

返回 id OperationState 是否为 Ready

==== is_operation_done(self: @ContractState, id: felt252) → bool external

返回 id OperationState 是否为 Done

==== get_timestamp(self: @ContractState, id: felt252) → u64 external

返回 id 变为 Ready 的时间戳。

0 表示 OperationState 为 Unset1 表示 OperationState 为 Done

==== get_operation_state(self: @ContractState, id: felt252) → OperationState external

返回具有给定 id 的操作的当前状态。

可能的状态有:

  • Unset: 操作尚未安排或已取消。

  • Waiting: 操作已安排,并且正在等待安排的延迟。

  • Ready: 计时器已过期,该操作符合执行条件。

  • Done: 操作已执行。

==== get_min_delay(self: @ContractState) → u64 external

返回操作变为有效的最小延迟(以秒为单位)。 可以通过执行调用 update_delay 的操作来更改此值。

==== hash_operation(self: @ContractState, call: Call, predecessor: felt252, salt: felt252) external

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

==== hash_operation_batch(self: @ContractState, calls: Span<Call>, predecessor: felt252, salt: felt252) external

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

==== schedule(ref self: ContractState, call: Call, predecessor: felt252, salt: felt252, delay: u64) external

安排一个包含单个事务的操作。

要求:

  • 调用者必须具有 PROPOSER_ROLE 角色。

  • 提案不得已存在。

  • delay 必须大于或等于最小延迟。

触发 CallScheduled 事件。 如果 salt 非零,则触发 CallSalt 事件。

==== schedule_batch(ref self: ContractState, calls: Span<Call>, predecessor: felt252, salt: felt252, delay: u64) external

安排一个包含一批事务的操作。

要求:

  • 调用者必须具有 PROPOSER_ROLE 角色。

  • 提案不得已存在。

  • delay 必须大于或等于最小延迟。

为批处理中的每个事务触发一个 CallScheduled 事件。 如果 salt 非零,则触发 CallSalt 事件。

==== cancel(ref self: ContractState, id: felt252) external

取消一个操作。已取消的操作将返回到 Unset OperationState。

要求:

  • 调用者必须具有 CANCELLER_ROLE 角色。

  • id 必须是待处理的操作。

触发一个 CallCancelled 事件。

==== execute(ref self: ContractState, call: Call, predecessor: felt252, salt: felt252) external

执行一个(准备就绪)操作,其中包含单个 Call。

要求:

  • 调用者必须具有 EXECUTOR_ROLE

  • id 必须处于 Ready OperationState。

  • predecessor 必须是 0 或处于 Done OperationState。

触发一个 CallExecuted 事件。

此函数可以重入,但它不会带来风险,因为 [TimelockControllerComponent-_after_call] 检查提案是否待处理,因此在重入期间对操作的任何修改都应被捕获。

==== execute_batch(ref self: ContractState, calls: Span<Call>, predecessor: felt252, salt: felt252) external

执行一个(准备就绪)操作,其中包含一批 Calls。

要求:

  • 调用者必须具有 EXECUTOR_ROLE

  • id 必须处于 Ready OperationState。

  • predecessor 必须是 0 或处于 Done OperationState。

为每个 Call 触发一个 CallExecuted 事件。

此函数可以重入,但它不会带来风险,因为 _after_call 检查提案是否待处理,因此在重入期间对操作的任何修改都应被捕获。

==== update_delay(ref self: ContractState, new_delay: u64) external

更改未来操作的最小时间锁持续时间。

要求:

  • 调用者必须是时间锁本身。这只能通过调度来实现 并在稍后执行一个操作,其中时间锁是目标,数据 是对该函数的序列化调用。

触发一个 MinDelayChanged 事件。

==== 内部函数

==== initializer(ref self: ContractState, min_delay: u64, proposers: Span<ContractAddress>, executors: Span<ContractState>, admin: ContractAddress) internal

通过注册对 SRC5 和 AccessControl 的支持来初始化合约。

此函数还使用以下参数配置合约:

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

  • proposers:要授予提案者和取消者角色的帐户。

  • executors:要授予执行者角色的帐户。

  • admin:可选帐户,用于授予管理员角色;使用零地址禁用。

可选的管理员可以帮助在部署后进行角色的初始配置,而无需延迟,但应随后放弃此角色,以支持 通过时间锁提案进行管理。

proposers 中的每个帐户触发两个 IAccessControl::RoleGranted 事件,其中包含 PROPOSER_ROLECANCELLER_ROLE 角色。

executors 中的每个帐户触发一个 IAccessControl::RoleGranted 事件,其中包含 EXECUTOR_ROLE 角色。

可能会为 admin 触发一个带有 DEFAULT_ADMIN_ROLE 角色的 IAccessControl::RoleGranted 事件(如果 admin 是 非零)。

触发 MinDelayChanged 事件。

==== assert_only_role(self: @ContractState, role: felt252) internal

验证调用者是否具有给定的 role。 否则会panic。

==== assert_only_role_or_open_role(self: @ContractState, role: felt252) internal

验证调用者是否具有给定的 role。 如果 role 被授予零地址,则这被认为是开放角色,允许任何人成为调用者。

==== assert_only_self(self: @ContractState) internal

验证调用者是否是时间锁合约本身。 否则会panic。

==== _before_call(self: @ContractState, id: felt252, predecessor: felt252) internal

在执行操作的调用之前检查的私有函数。

要求:

  • id 必须处于 Ready OperationState。

  • predecessor 必须为零或处于 Done OperationState。

==== _after_call(self: @ContractState, id: felt252) internal

在执行操作的调用之后检查的私有函数 并将 id 的 OperationState 设置为 Done

要求:

  • id 必须处于 Ready OperationState。

==== _schedule(ref self: ContractState, id: felt252, delay: u64) internal

在给定的 delay 之后安排将变为有效的操作的私有函数。

==== _execute(ref self: ContractState, call: Call) internal

执行操作调用的私有函数。

==== 事件

==== CallScheduled(id: felt252, index: felt252, call: Call, predecessor: felt252, delay: u64) event

call 作为操作 id 的一部分被调度时触发。

==== CallExecuted(id: felt252, index: felt252, call: Call) event

call 作为操作 id 的一部分执行时触发。

==== CallSalt(id: felt252, salt: felt252) event

当使用非零 salt 调度新提案时触发。

==== CallCancelled(id: felt252) event

当操作 id 被取消时触发。

==== MinDelayChanged(old_duration: u64, new_duration: u64) event

当修改未来操作的最小延迟时触发。

== 投票

VotesComponent 提供了一个灵活的系统来跟踪和委托投票权。该系统允许用户将其投票权委托给其他地址,从而实现更积极地参与治理。

=== IVotes

use openzeppelin_governance::votes::interface::IVotes;

启用投票的合约的通用接口。

==== 函数

==== get_votes(account: ContractAddress) → u256 external

返回 account 当前拥有的票数。

==== get_past_votes(account: ContractAddress, timepoint: u64) → u256 external

返回 account 在过去的特定时刻拥有的票数。

==== get_past_total_supply(timepoint: u64) → u256 external

返回过去特定时刻可用的投票总数。

此值是所有可用投票的总和,不一定是所有已委派投票的总和。 尚未委派的投票仍然是总供应的一部分,即使它们不会参与投票。

==== delegates(account: ContractAddress) → ContractAddress external

返回 account 选择的代理。

==== delegate(delegatee: ContractAddress) external

将投票从发送者委托给 delegatee

==== delegate_by_sig(delegator: ContractAddress, delegatee: ContractAddress, nonce: felt252, expiry: u64, signature: Span<felt252>) external

通过 SNIP-12 消息签名验证将投票从 delegator 委托给 delegatee

==== clock() → u64 external

返回由合约的运行模式确定的当前时间点,旨在用于时间敏感的逻辑。 请参阅 ERC-6372#clock

要求:

  • 此函数必须始终是非递减的。

==== CLOCK_MODE() → u64 external

返回对合约运行的时钟的描述。 请参阅 ERC-6372#CLOCK_MODE

要求:

  • 输出的格式必须类似于 URL 查询字符串,可以在标准 JavaScript 中解码。

=== VotesComponent

use openzeppelin_governance::votes::VotesComponent;

实现 IVotes 接口并提供灵活的系统来跟踪和委托投票权的组件。

默认情况下,令牌余额不考虑投票权。这使得转移更便宜。缺点是它要求用户委托给自己才能激活检查点并跟踪他们的投票权。

使用此模块时,您的合约必须实现 VotingUnitsTrait。为方便起见,ERC20ERC721 令牌会自动执行此操作。

==== ERC20VotesImpl

==== get_voting_units(self: @ContractState, account: ContractAddress) → u256 internal

返回给定帐户的投票单位数。

此实现特定于 ERC20 令牌,其中余额 令牌直接表示投票单位的数量。

如果 ERC20 组件在最终合约中实现,则此实现将开箱即用。
此实现假定令牌以 1:1 的比例映射到投票单位。 当转移投票单位时(例如,通过使用钩子)对该公式的任何偏离 可能会危及内部投票核算。

==== ERC721VotesImpl

==== get_voting_units(self: @ContractState, account: ContractAddress) → u256 internal

返回给定帐户的投票单位数。

此实现特定于 ERC721 令牌,其中每个令牌 表示一个投票单位。该函数返回以下余额 指定帐户的 ERC721 令牌。

如果 ERC721 组件在最终合约中实现,则此实现将开箱即用。
此实现假定令牌以 1:1 的比例映射到投票单位。 当转移投票单位时(例如,通过使用钩子)对该公式的任何偏离 可能会危及内部投票核算。

==== 可嵌入的函数

==== `get_votes++(self: @ContractState[.contract-item]

==== delegate_by_sig(ref self: ContractState, delegator: ContractAddress, delegatee: ContractAddress, nonce: felt252, expiry: u64, signature: Span<felt252>) external

通过 SNIP-12 消息签名验证,将来自 delegator 的投票委托给 delegatee

要求:

  • expiry 不能是过去的时间。

  • nonce 必须与帐户的当前 nonce 匹配。

  • delegator 必须实现 SRC6::is_valid_signature

  • signature 应该对消息哈希有效。

发出 DelegateChanged 事件。

可能会发出一个或两个 DelegateVotesChanged 事件。

==== clock(self: @ContractState) → u64 external

返回由合约的运行模式确定的当前时间点,旨在用于时间敏感的逻辑。 参见 ERC-6372#clock

要求:

  • 此函数必须始终是非递减的。

==== CLOCK_MODE(self: @ContractState) → u64 external

返回对合约运行时间的描述。 参见 ERC-6372#CLOCK_MODE

要求:

  • 输出的格式必须类似于 URL 查询字符串,可以在标准 JavaScript 中解码。

==== 内部函数

==== get_total_supply(self: @ContractState) → u256 internal

返回当前投票总供应量。

==== move_delegate_votes(ref self: ContractState, from: ContractAddress, to: ContractAddress, amount: u256) internal

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

可能会发出一个或两个 DelegateVotesChanged 事件。

==== transfer_voting_units(ref self: ContractState, from: ContractAddress, to: ContractAddress, amount: u256) internal

转移、铸造或销毁投票单位。

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

如果投票单位基于底层可转让资产(如 token),则每次转移资产时都必须调用此函数,以使内部投票权核算保持同步。对于 ERC20 和 ERC721 token,这通常使用钩子来处理。

可能会发出一个或两个 DelegateVotesChanged 事件。

==== num_checkpoints(self: @ContractState, account: ContractAddress) → u64 internal

返回 account 的检查点数量。

==== checkpoints(self: @ContractState, account: ContractAddress, pos: u64) → Checkpoint internal

返回 account 的第 pos 个检查点。

==== _delegate(ref self: ContractState, account: ContractAddress, delegatee: ContractAddress) internal

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

发出 DelegateChanged 事件。

可能会发出一个或两个 DelegateVotesChanged 事件。

==== 事件

==== DelegateChanged(delegator: ContractAddress, from_delegate: ContractAddress, to_delegate: ContractAddress) event

当帐户更改其委托人时发出。

==== DelegateVotesChanged(delegate: ContractAddress, previous_votes: u256, new_votes: u256) event

当 token 转移或委托更改导致委托人的投票数量发生变化时发出。

=== VotingUnitsTrait

pub trait VotingUnitsTrait<TState> {
    fn get_voting_units(self: @TState, account: ContractAddress) -> u256;
}

一个 trait,当将 VotesComponent 集成到合约中时必须实现。它提供了一种机制来检索给定帐户在当前时间的投票单位数量。

==== 函数

==== get_voting_units(self: @TState, account: ContractAddress) → u256 external

返回给定帐户的投票单位数量。对于 ERC20,这通常是 token 余额。对于 ERC721,这通常是拥有的 token 数量。

虽然任何公式都可以用作投票单位的衡量标准,但如果投票单位通过遵循不同公式的任何外部流程进行转移,则合约的内部投票核算可能会受到影响。
例如,在实现 ERC20 的钩子时,转移的投票单位数量应与 get_voting_units 实现给出的公式相匹配。