地址
函数与选择器
常量
状态修改函数
addValidator
创建一个关联委托者账户的验证者,并返回结果validatorId。
函数选择器
payload- 由以下字段组成,以大端字节序打包在一起(等价于 Solidity 中的abi.encodePacked()):bytes secpPubkey(用于共识的唯一 SECP 公钥)bytes blsPubkey(用于共识的唯一 BLS 公钥)address authAddress(用于验证者委托者账户的地址。该地址对验证者的质押金额拥有提现权限)uint256 amount(验证者自我质押的金额。必须等于msg.value)uint256 commission(向委托者收取的佣金,乘以 1e18,例如10% = 1e17)
signedSecpMessage- 对 payload 的 SECP 签名signedBlsMessage- 对 payload 的 BLS 签名
secpPubkey、blsPubkey、authAddress、amount 和 commission,然后验证 signedSecpMessage 和 signedBlsMessage 对应于由相应 SECP 和 BLS 私钥签名的 payload。
- 验证者必须同时提供唯一的 BLS 密钥和唯一的 SECP 密钥。任何包含重复公钥的提交都会回滚。
- 两个签名(
signedSecpMessage和signedBlsMessage)都必须有效,且都必须是对payload的签名。 - 多个验证者可以共享同一个
authAddress。 msg.value必须大于或等于MIN_AUTH_ADDRESS_STAKE,否则调用将回滚。- 如果
msg.value还大于或等于ACTIVE_VALIDATOR_STAKE,则该验证者将在未来激活:- 如果
addValidator在边界区块之前调用,则在纪元n+1; - 否则将在纪元
n+2激活。
- 如果
Pseudocode
Pseudocode
delegate
如果委托者账户不存在则创建,并增加委托者的余额。 函数选择器validatorId- 委托者希望委托的验证者的 IDmsg.value- 要委托的金额
- 委托者账户由
msg.sender决定。 validatorId必须对应一个有效的验证者。msg.value必须 >=DUST_THRESHOLD。- 如果此次委托使验证者的总质押超过
ACTIVE_VALIDATOR_STAKE,并且该验证者尚不在execution_valset中,则会被添加进去。 - 委托者的质押变为活跃
- 若请求在边界区块之前,则在纪元
n+1生效 - 否则在纪元
n+2生效
- 若请求在边界区块之前,则在纪元
Pseudocode
Pseudocode
undelegate
从委托者账户扣除amount 并将其移入一个提现请求对象,在 WITHDRAWAL_DELAY 个纪元的挂起状态之后,资金即可通过 withdraw 函数领取。
函数选择器
validatorId- 发送者此前已委托的验证者的 ID,我们要从该验证者移除委托amount- 要解除委托的金额,以 Monad wei 计withdrawId- 0 到 255(含)之间的整数,作为委托者提现的标识符。对于每个 (validator, delegator) 元组,最多可有 256 个未完成的提现请求
- 委托者账户由
msg.sender决定。 validatorId必须对应一个发送者此前已委托过的有效验证者- 委托者必须拥有 >= amount 的质押。
- 如果提现导致
Val(validatorId).stake()降至ACTIVE_VALIDATOR_STAKE以下,则该验证者将被安排从 valset 中移除。 - 如果验证者的
authAddress解除足够多的自身质押,使其降至MIN_AUTH_ADDRESS_STAKE以下,则该验证者将被安排从 valset 中移除。 - 如果存在具有相同
withdrawId的待处理提现,该函数会回滚。调用withdraw后withdrawId可复用。 - 委托者只能在质押已激活后才能移除该质押。这是委托者结构体中的 stake 字段。待生效的委托在激活前不能被移除。
- 委托者的质押在 valset 中变为非活跃
- 若请求在边界区块之前,则在纪元
n+1生效 - 否则在纪元
n+2生效
- 若请求在边界区块之前,则在纪元
- 委托者的质押变为可提现,因此不再受罚没约束
- 若请求在边界区块之前,则在纪元
n + 1 + WITHDRAWAL_DELAY - 否则在纪元
n + 2 + WITHDRAWAL_DELAY
- 若请求在边界区块之前,则在纪元

质押可提现性相对于 undelegate 命令的时间线
Pseudocode
Pseudocode
withdraw
完成一次解除委托操作(以调用undelegate 函数开始),将金额发送给 msg.sender,前提是已经过足够的纪元。
函数选择器
validatorId- 发送者此前已委托的验证者的 ID,我们之前对该验证者发出了undelegate命令withdrawId- 委托者此前创建的提现的标识符;即之前提供给undelegate的相同 id。对于每个 (validator, delegator) 元组,最多可有 256 个未完成的提现请求。
- 委托者为
msg.sender。提现由msg.sender、validatorId和withdrawId标识 - 一旦解除委托完成且提现延迟已过,即可执行提现操作:
- 若解除委托请求在边界区块之前,则在纪元
n + 1 + WITHDRAWAL_DELAY - 否则在纪元
n + 2 + WITHDRAWAL_DELAY
- 若解除委托请求在边界区块之前,则在纪元
Pseudocode
Pseudocode
compound
将委托者已累积的奖励转换为额外的质押。 函数选择器validatorId- 发送者此前已委托的验证者的 ID,我们要为其复投奖励
- 用于复投的账户由
msg.sender决定。如果委托者账户不存在,则调用回滚 validatorId必须对应一个发送者此前已委托过的有效验证者- 委托者的奖励在 valset 中变为活跃
- 若请求在边界区块之前,则在纪元
n+1生效 - 否则在纪元
n+2生效.
- 若请求在边界区块之前,则在纪元
Pseudocode
Pseudocode
claimRewards
允许委托者领取奖励而非 复投 它们。 函数选择器validatorId- 发送者此前已委托的验证者的 ID,我们要为其领取奖励
validatorId必须对应一个发送者此前已委托过的有效验证者- 如果该
(validatorId, msg.sender)元组对应的委托者账户不存在,则调用回滚 - 委托者累积的奖励会转入其委托账户
Pseudocode
Pseudocode
changeCommission
允许验证者的authAddress 修改该验证者的佣金。
函数选择器
validatorId- 希望更改佣金率的验证者的 IDcommission- 从区块奖励中收取的佣金率,以 1e18 为单位表示(例如 10% = 1e17)
msg.sender必须是相应验证者 Id 的authAddress。- 佣金不能设置为大于
MAX_COMMISSION(当前为 100%)。 - 佣金变更在以下纪元生效:
- 如果请求不在纪元延迟轮次内,则在纪元
n+1。 - 如果请求在纪元延迟轮次内,则在纪元
n+2。
- 如果请求不在纪元延迟轮次内,则在纪元
Pseudocode
Pseudocode
externalReward
允许任何人向特定验证者的质押者发送额外的 MON,通常由验证者自己调用以将额外的小费分享给其委托者。 函数选择器validatorId- 验证者的 IDmsg.value- 要添加到未领取奖励中的 MON
- 只能对当前在共识验证者集中的验证者调用;否则交易将回滚。
msg.value必须介于 1 MON 与 1,000,000 MON 之间;否则交易将回滚。- 此处不会从中扣除佣金并转入验证者的
auth_address。如果您希望扣除一部分,应在发送前先扣除。
Pseudocode
Pseudocode
视图函数
由于质押预编译合约只允许
CALL,所有视图函数都被赋予默认的 nonpayable 状态可变性。getValidator
返回验证者跨执行、共识和快照上下文的完整状态视图。ValExecution(执行视图)- 质押和佣金(共识视图)
- 质押和佣金(快照视图)
validatorId- 验证者的 ID
getDelegator
返回指定验证者对应的委托者DelInfo,提供委托者的质押、累积奖励和待生效质押变更的视图。
函数选择器
validatorId- 验证者的 IDdelegator- address of the delegator about whose stake we are inquiring
getWithdrawalRequest
返回(validatorId, delegator, withdrawId) 元组对应的待处理 WithdrawalRequest。
函数选择器
get*ValidatorSet
分别返回共识、快照和执行验证者 ID。 函数选择器startIndex- 由于所查找的列表可能非常长,因此这些函数都是分页的,返回所需列表的一个固定长度子集。传入startIndex指示从列表的哪个位置开始。
PAGINATED_RESULTS_SIZE = 100).
行为
getExecutionValidatorSet() 返回所有符合入选质押标准的完整活跃验证者集合。getSnapshotValidatorSet() 返回被选定为下一纪元领导者的验证者子集。getConsensusValidatorSet() 返回当前纪元中作为领导者的验证者子集。
每次调用从 startIndex 开始最多获取 PAGINATED_RESULTS_SIZE 个验证者 ID,并返回元组 (bool done, uint32 nextIndex, uint256[] valids)。
bool isDone 表示是否已到达列表末尾。uint32 nextIndex 是数组中的最后一个槽位。
getDelegations
返回给定委托者地址已委托的验证者 ID 的分页列表。 函数选择器delegator- 我们要查询其委托的地址startValId
startValId 开始最多获取 PAGINATED_RESULTS_SIZE 个验证者 ID,并返回元组 (bool isDone, uint64 nextValId, uint64[] valIds),包含来自输入 delegator 地址的委托。
bool isdone 表示是否已到达列表末尾。uint64 nextValId 是 valIds 中最后一个元素之后的 ID。将其用作下一次调用的 startValId。
如果 delegator 委托的验证者 ID 数超过 PAGINATED_RESULTS_SIZE,则需要多次调用(在 isDone 为 false 时继续)。
要获取完整集合,首次调用请使用 startValId = 0。
getDelegators
返回给定验证者的委托者地址分页列表。 函数选择器validatorId- 我们要了解其委托者的验证者的 IDstartDelegator
startDelegator 开始最多获取 PAGINATED_RESULTS_SIZE 个委托者地址,并返回元组 (bool isDone, address nextDelegator, address[] delegators),包含对输入 validatorId 的委托。
bool isDone 表示已到达列表末尾。nextDelegator 是 delegators 中最后一个元素之后的地址。将其用作下一次调用的 startDelegator。
要获取完整集合,应使用 startDelegator = 0 调用该函数。
某个验证者的委托者数量可能非常庞大,因此建议通过 events 框架维护一份更新的列表,而不是周期性地调用这个昂贵的查找。
getEpoch
返回当前纪元以及在纪元中的时序(边界区块之前或之后)。 函数选择器inEpochDelayPeriod 为 false,则尚未到达边界区块,此时的写操作应在 epoch + 1 生效。如果 inEpochDelayPeriod 为 true,则网络已过边界区块,此时的写操作应在 epoch + 2 生效
getProposerValId
返回当前区块提议者的验证者 ID,对应于区块作者的 SECP 值。 函数选择器Syscalls
目前有三个 syscall。用户不能直接调用它们。它们只能通过特殊的系统交易触发。syscallOnEpochChange
在纪元延迟轮次结束时触发,以敲定累加器值并更新纪元状态。 函数选择器epoch- 正要进入的新共识纪元
- 如果验证者在上一纪元收到了更改质押的请求,并参与了上一纪元的共识验证者集,则保存相应的累加器值
- 如果任何验证者在上一纪元处于活跃状态但在当前纪元变为非活跃,也保存其当前的累加器值
- 在状态中设置当前纪元
Pseudocode
Pseudocode
syscallReward
为每个区块奖励出块的验证者及其委托者已配置的区块奖励。 函数选择器blockAuthor—— 出块验证者的地址。
- 如果验证者的佣金不为零,则会将一部分奖励分配给验证者的
authAddress。 - 剩余的奖励可供验证者的委托者领取。
- 假设某验证者的个人质押占其验证者总委托的 20%。
- 佣金设置为总奖励的 10%。
Pseudocode
Pseudocode
syscallSnapshot
对当前执行层验证者集进行排序,选出质押最多的前N 名验证者作为即将到来的共识验证者集,将更新后的集合存入状态,并清除之前的共识集。
函数选择器
Pseudocode
Pseudocode
事件
质押预编译合约会发出出现在交易回执中的标准事件。这些事件为验证者和委托者的操作提供带索引的信息。ValidatorRewarded
当通过syscallReward 分配区块奖励,或通过 externalReward 向验证者的质押者发送额外 MON 时发出。
ValidatorCreated
当通过addValidator 添加验证者时发出。
ValidatorStatusChanged
在addValidator、delegate、undelegate 或 compound 期间,当验证者的标志发生变化时发出。
Delegate
当委托金额增加时发出,即在addValidator、delegate 或 compound 期间。
Undelegate
当委托者调用undelegate 时发出。
Withdraw
当委托者成功执行withdraw 时发出。
ClaimRewards
当委托者通过claimRewards 领取奖励时发出。
CommissionChanged
当验证者通过changeCommission 更改佣金时发出。
EpochChanged
当纪元通过syscallOnEpochChange 改变时发出。
预编译合约内部
验证者结构体
委托者结构体
状态变量
映射
Solidity 质押接口
点击代码块右上角的按钮可复制到剪贴板。质押 ABI JSON
点击代码块右上角的按钮可复制到剪贴板。常见问题
是否存在 removeValidator 函数?
是否存在 removeValidator 函数?
没有直接的
removeValidator 函数。相反,如果某验证者的 auth_account 通过 undelegate 移除了足够多的质押,该验证者会在未来某个纪元从共识集合中被移除。这将发生在纪元 n+1 或纪元 n+2,取决于 undelegate 是否发生在纪元延迟轮次内。即使未处于活跃状态,验证者的信息也会始终保留。验证者 ID 是永久的,因为其他委托者可能仍在委托,并需要引用该 val_id 进行解除委托/提现。验证者如何更改自己的 commission?
验证者如何更改自己的 commission?
验证者可通过调用
changeCommission 更改其 commission。哪些函数可以查看验证者 ID 列表?
哪些函数可以查看验证者 ID 列表?
参见 valset getters。
哪些函数可以查看验证者的状态?
哪些函数可以查看验证者的状态?
参见
getValidator。哪些函数可以查看委托者对某个特定验证者的委托情况?
哪些函数可以查看委托者对某个特定验证者的委托情况?
参见
getDelegator。对于该委托者对该验证者的待处理提现,请参见 getWithdrawalRequest。它更像合约还是预编译?
它更像合约还是预编译?
尽管使用了 Solidity 选择器和 ABI,它是一个预编译合约。访问 处的代码会返回空代码。它的账户总是以 warm 方式访问,使用无效参数的调用会消耗全部 gas。例外:如果某账户尝试使用 EIP-7702 将委托设置为质押预编译合约,则对其所有的调用都会回滚。

