mcpField
V
vebetterdao-navigators

vebetterdao-navigators

github.com/vechain开发1548 次安装4 周前更新
代码仓库

关于 vebetterdao-navigators

vebetterdao-navigators 为开发 VeBetterDAO 投票与奖励合约的人整理 Navigator 功能领域知识,涵盖委托投票、奖励乘数、费用和 Relayer 行为。

主要功能

  1. 01分配与治理奖励乘数
  2. 02Navigator 注册与公民委托
  3. 03基于快照的委托投票
  4. 04Relayer 投票与跳过处理
  5. 05奖励费用与费用托管

适用场景

  1. 01实现 Navigator 合约和投票流程
  2. 02核对委托规则与投票权
  3. 03检查奖励乘数和费用行为

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/vechain/vechain-ai-skills --skill vebetterdao-navigators

安装后在 Claude Code 中输入/vebetterdao-navigators确认已加载。

详细介绍

VeBetterDAO 导航者功能

导航者功能的领域知识:奖励乘数和导航者委托系统。两个阶段在同一版本中一并发布。

阶段 1:奖励乘数

通过 FreshnessUtils 库应用于 RoundVotesCountingUtils.countVote()——仅修改奖励权重,不修改链上投票权。

行为乘数
本轮(每周)有更新x3 (30000 bp)
最近 2 轮(每两周)内有更新x2 (20000 bp)
>= 3 轮未更新x1 (10000 bp)
  • “更新” = 更改所投票的应用集合(添加/移除/替换)。在相同应用之间更改权重不算
  • 通过对已投票应用 ID 进行 XOR 指纹计算得出(与顺序无关,O(n),节省 gas)
  • 首次投票的用户始终获得 x3(通过 lastFingerprint == bytes32(0) 检测)
  • 可通过 VoterRewards.setFreshnessMultipliers(tier1, tier2, tier3) 由治理配置
  • 数值以 Checkpoints.Trace208 的形式存储在 VoterRewards 中(在轮次开始时快照)
  • 由导航者代为委托投票的公民继承导航者的新鲜度(投票时使用导航者的偏好更新公民指纹)
治理意向乘数(提案投票)

在调用 registerVote() 前应用于 GovernorVotesLogic。在注册时按提案计算——每个提案相互独立。

投票类型乘数
赞成/反对x1 (10000 bp)
弃权x0.30 (3000 bp)
  • 可通过 VoterRewards.setIntentMultipliers(forAgainst, abstain) 由治理配置
  • 由导航者代为委托投票的公民继承导航者的决策乘数
乘数适用范围
  • 新鲜度仅缩放分配奖励的奖励权重(在 RoundVotesCountingUtils.countVote() 中)
  • 意向仅缩放治理奖励的奖励权重(在 GovernorVotesLogic 中、调用 registerVote 前)
  • GM 不会与新鲜度/意向叠加。 当 GM 奖励池已注资(v5+ 实时配置)时,GM 会在 cycleToVoterToGMWeight 中累积各投票者独立的权重,并从 GM 奖励池领取——它不会乘以分配/治理奖励权重。VoterRewards.registerVote() 中旧版的 weight * GM 路径仅在 gmPoolAmount == 0 时运行
  • 比例:基点(10000 = 1x)
安全升级

VoterRewards.initializeV7 为每个乘数创建两个检查点:

  1. 在轮次开始时间点设为 → 10000(中性),使当前轮次不受影响
  2. 在当前区块设为 → 实际配置值(下一轮生效)

阶段 2:导航者系统

核心概念
  • 导航者:质押 B3TR 以代表委托公民投票的用户
  • 公民:将特定数量的 VOT3 委托给导航者的用户
  • 角色互斥——导航者不能成为另一位导航者的公民
  • 公民保留 VOT3 的完整所有权,但已委托部分会被锁定
注册
  • 无需许可——在 NavigatorRegistry 中至少质押 50,000 B3TR
  • 最高质押额:流通中 VOT3 的 1%(仅在存入时强制执行,现有质押不受影响)
  • 10:1 委托比例:质押额必须 >= 已委托 VOT3 总量的 10%。若减少质押会导致违反此比例,则禁止减少
  • 用于个人资料的链上元数据 URI(与 X2EarnApps 使用相同模式)
  • 链上报告每轮可选,但至少每 2 轮必须提交一次,通过 submitReport(metadataURI) 提交
  • 导航者不能启用自动投票(角色互斥)
  • 导航者不能向其他导航者委托(角色互斥)
委托
  • Citizens 委托特定数量的 VOT3(明确选择,而非全部余额),最低为 1 VOT3
  • VOT3 保留在 citizen 的钱包中,但已委托的部分会被锁定(无法转账或转换为 B3TR)
  • balanceOf() 返回 全部 VOT3 余额(包括已委托部分)。使用 unlockedBalance() 获取可转账数量
  • VOT3 _update() 强制执行:balance - delegatedAmount >= transferAmount
  • VOT3 通过 INavigatorRegistry.getDelegatedAmount(from) 从 NavigatorRegistry 读取委托数量——无需授予角色,VOT3 上也没有映射;VOT3 仅存储注册表地址
  • 每位 citizen 只能委托给一位 navigator
  • 在轮次开始时创建快照——轮次中途的变更将在下一轮生效
  • 允许部分取消委托(在下一轮生效)
  • 委托无需进行 personhood 检查。在投票时(快照时)验证 personhood;非 person 的 citizens 将被跳过
  • 已委托的 Citizens 无法手动投票——必须先退出委托
  • 委托时会禁用自动投票(NavigatorRegistry 调用 XAllocationVoting.disableAutoVotingFor)
  • 未委托的 VOT3 处于闲置状态(不产生收益)
  • 如果委托会超出 navigator 的容量(10:1 比例),则会拒绝委托
委托函数
函数用途事件
delegate(navigator, amount)仅限首次委托。自动清除已失效 navigator 的过期委托。DelegationCreated
increaseDelegation(amount)向现有委托增加更多 VOT3DelegationIncreased
reduceDelegation(amount)部分或全部减少委托(全部减少 = 移除委托)DelegationDecreased 或 DelegationRemoved
undelegate()完全移除委托DelegationRemoved
全局 Citizen 数量

NavigatorRegistry 会全局追踪已委托的 citizens:

  • Checkpoints.Trace208 totalDelegatedCitizens——委托时递增,取消委托时递减
  • mapping(address => uint256) navigatorCitizenCount——按 navigator 统计的数量
  • getTotalDelegatedCitizensAtTimepoint(timepoint)——供 XAllocationVoting.startNewRound 用于计算 governanceUsers
  • 在 announceExit() / deactivateNavigator() 时:navigatorCitizenCount 清零,且 totalDelegatedCitizens 立即递减
投票机制
Allocation Voting(XAllocationVoting)

两个独立函数(不合并):

  • castVoteOnBehalfOf(voter, roundId)——现有的自动投票流程(不变)
  • castNavigatorVote(citizen, roundId)——navigator 委托的 citizens:
    • 在快照时验证 personhood——非 person 的 citizens 会被跳过(不会回滚),与 castVoteOnBehalfOf 的行为一致
    • 投票权重 = 轮次快照时的委托数量(使用检查点记录,而非全部余额)
    • Navigator 的应用偏好和百分比(自定义权重分配,以基点表示,总和必须为 10000;最多 15 个应用)
    • 每位 citizen = 单独一笔交易
    • 包含内置的跳过或投票逻辑(参见下文的 Relayer 集成)
    • 为调用者在 RelayerRewardsPool 中注册 RelayerAction.VOTE

Navigator 设置偏好即为其本人投票(个人 VOT3 余额 + 抵押的 B3TR 转换为 VOT3)

治理提案投票(B3TRGovernor)

castNavigatorVote(proposalId, citizen)——独立函数:

  1. 在提案快照时,citizen 必须已委托给某个 navigator
  2. Navigator 必须已设置决定(1=反对,2=赞成,3=弃权)
  3. 投票权重 = 提案快照时的委托数量(使用检查点记录)
  4. 应用意向乘数以计算奖励
  5. 在 RelayerRewardsPool 中注册 RelayerAction.VOTE
  6. 包含内置的跳过或投票逻辑(参见下文的 Relayer 集成)
getVotes 反映委托

两个治理合约上的 getVotes(account, timepoint):

  • 如果公民在 timepoint 时有有效的导航者:仅返回委托金额(这是该公民的投票权)
  • 如果没有导航者:返回完整的 VOT3.getPastVotes(在 XAllocationVoting 中还会加上 getDepositVotingPower)
  • 当 navigatorRegistry == address(0) 时返回完整余额(向后兼容)
  • getQuadraticVotingPower 内部会调用 getVotes,因此委托会传递为 sqrt(委托金额) * 1e9
  • 仅用于查询:如果公民在快照时有导航者,实际调用 castVote 会回退并报错 DelegatedToNavigator。导航者投票时会直接使用 getDelegatedAmountAtTimepoint
中继器集成

计入中继器预期操作的公民:

  • 在轮次开始时,XAllocationVoting.startNewRound 会计算:
    • allocationUsers = autoVotingUsers + totalDelegatedCitizens
    • governanceUsers = totalDelegatedCitizens(仅公民——中继器不会代表自动投票用户投治理票)
  • 通过 B3TRGovernor.getActiveProposals() 获取有效的治理提案
  • 将所有数据传递给 RelayerRewardsPool.setTotalActionsForRoundWithGovernance(roundId, allocationUsers, governanceUsers, activeProposalIds)
  • 每轮预期操作数:allocationUsers * 2(投票 + 领取)+ governanceUsers * activeProposals(治理投票)

跳过或投票流程:

castNavigatorVote(分配投票和治理投票)将投票和跳过操作合并到单个函数中:

  1. 快照时导航者已失效 → 回退并报错 NotDelegatedToNavigator(该公民从未委托)
  2. 快照时该公民不是人员 → 立即跳过,并减少预期操作数(NavigatorVoteSkipped / NavigatorGovernanceVoteSkipped)
  3. 导航者目前已失效(在快照后退出/停用)→ 立即跳过,并减少预期操作数
  4. 导航者有效 + 已设置偏好/决策 → 正常投票
  5. 导航者有效 + 未设置偏好/决策 + 已到跳过时段 → 跳过,并减少预期操作数
  6. 导航者有效 + 未设置偏好/决策 + 尚未到跳过时段 → 回退(中继器稍后重试)

跳过时段 = 距离轮次/提案截止时间 2 小时(约 720 个区块)。常量:CITIZEN_SKIP_WINDOW_BLOCKS(分配投票)、GOVERNANCE_SKIP_WINDOW_BLOCKS(治理投票)。

按用户跟踪跳过操作(RelayerRewardsPool V3):

  • reduceUserAllocationVote(roundId, user) — 减少特定用户的一项分配投票操作
  • reduceUserGovernanceVote(roundId, user, proposalId) — 减少每位用户针对每项提案的一项治理投票操作
  • 当用户的所有投票操作(分配投票 + 所有治理提案)都被跳过时,会自动减少领取操作
  • 防止重复跳过:如果同一用户/轮次/提案的操作已减少,则回退

有效提案缓存:

  • 创建提案时填充 B3TRGovernor.proposalsForRound 映射
  • getActiveProposals() 从当前轮次的提案中筛选处于 Active 状态的提案
  • 在轮次开始时缓存到 RelayerRewardsPool.activeProposalsForRound

偏好设置过晚违规:

  • 导航者必须至少在轮次截止前 preferenceCutoffPeriod 个区块(约 24 小时)设置偏好
  • 允许稍后设置,但会将该轮次标记为轻微违规

委托时禁用自动投票:

  • NavigatorRegistry.delegate() 会调用 XAllocationVoting.disableAutoVotingFor(citizen)(特权调用)
  • 取消委托后,用户必须手动重新启用自动投票

首选中继器:

  • 公民通过 relayerRewardsPool.setPreferredRelayer(relayer) 手动设置 preferredRelayer
  • 在早期访问期间,只有首选中继器(如果已设置且已注册)才能代表该公民操作
  • 委托时不会自动设置——公民必须手动设置

公民的费用扣除顺序(领取时):

  1. 导航者费用:先从总奖励中扣除(进入 NavigatorRegistry 费用托管账户)
  2. 中继器费用:从剩余金额中扣除(进入 RelayerRewardsPool)
  3. 公民获得剩余部分
  • 中继器费用适用于自动投票用户和公民
  • 两者都会登记 CLAIM 操作

奖励

奖励仅按快照时的委托金额按比例发放(而非全部余额)。适用公民自身的 GM 等级。

费用扣除顺序:

1. Navigator fee = gross reward * navigatorFeePercentage / 10000 (goes to NavigatorRegistry escrow)
2. Relayer fee = relayerRewardsPool.calculateRelayerFee(gross - navigatorFee) (goes to RelayerRewardsPool)
3. Citizen receives the rest
  • 中继者费用适用于自动投票者和导航者公民
  • 导航者费用仅适用于公民
  • 在领取奖励时通过 VoterRewards.claimReward() 扣除费用
  • 投票时,公民的时效性指纹会更新为导航者的应用偏好(继承时效性)
  • 公民继承导航者的治理意图乘数

费用托管

在 NavigatorRegistry 中:mapping(navigator => mapping(round => amount))

  • 每轮费用在 4 轮后可领取(滚动解锁)
  • 重大惩罚会收缴所有未领取的锁定费用

惩罚

轻微惩罚(自动执行,当前剩余质押的 5%——复利计算)

任何人都可以通过公开函数举报。罚没资金转入金库。

六种违规类型:

  1. 错过分配投票——拥有公民,却未设置某一轮的偏好(需要有委托)
  2. 错过治理提案投票——拥有公民,却未在提案投票期间设置决定(需要有委托)
  3. 分配偏好过期——至少 3 轮未更新(与时效性乘数使用相同阈值)(需要有委托)
  4. 错过报告——连续 2 轮未提交报告(需要有委托)
  5. 偏好设置超时——在轮次截止时间前的 preferenceCutoffPeriod(约 24 小时)之后才设置分配偏好(需要有委托)
  6. 质押低于最低要求——轮次开始时和结束时的质押均低于 minStake(无论是否有委托均适用)

违规标志(NavigatorSlashingUtils 中的位标志):

  • FLAG_MISSED_ALLOCATION = 1 << 0(1)
  • FLAG_LATE_PREFERENCES = 1 << 1(2)
  • FLAG_STALE_PREFERENCES = 1 << 2(4)
  • FLAG_MISSED_REPORT = 1 << 3(8)
  • FLAG_MISSED_GOVERNANCE = 1 << 4(16)
  • FLAG_BELOW_MIN_STAKE = 1 << 5(32)

举报机制:

  • 轻微违规按轮次举报,而非按违规类型举报
  • 轮次结束后,任何人都可以调用 reportRoundInfractions(navigator, roundId, proposalIds)
  • 合约会在链上评估该轮次的所有六种违规类型
  • 仅当导航者在该轮次快照时有委托,才会检查违规类型 1-5
  • 违规类型 6(质押低于最低要求)会无论是否有委托都进行检查——导航者必须始终保持质押高于最低要求
  • 质押低于最低要求的检查采用两个检查点:stakeAtRoundStart < minStake AND stakeAtRoundEnd < minStake。这样,导航者在其质押因惩罚而降低后,有整整一轮的时间进行补足。
  • 如果存在任何违规,该轮次只会施加一次轻微惩罚
  • 如果轮次仍在进行中,举报会回滚并报错 RoundStillActive

如果质押低于最低要求:导航者仍保持活跃状态,但不能接受新的委托;如果到轮次结束时仍未补足,将受到惩罚。

质押低于最低要求的时间示例(minStake = 50K):

轮次开始质押事件结束质押belowMinStake?
R350K因错过职责被罚没 5% → 47.5K47.5K否(开始时达到最低要求)
R447.5K导航者在轮次中途补足 3K50.5K否(开始时低于要求,结束前已恢复)
R550.5K—50.5K否(高于最低要求)

如果导航者未恢复,则情况如下:

轮次开始质押事件结束质押belowMinStake?
R350K被罚没 5% → 47.5K47.5K否(开始时达到最低要求)
R447.5K未采取行动47.5K是(开始和结束时均低于要求)
R545.125K再次受到惩罚42.87K是(持续累积)
重大惩罚(治理流程,最高可罚没 100% 的质押 + 锁定费用 + 移除)

适用情形:操纵、贿赂、买票、未披露报酬。 流程:5 名导航者锁定质押以触发流程 → 4 轮内公布调查结果 → 进行治理投票。

停用

  • 通过治理提案(任何人都可以提出),并在链上执行
  • 提案包含罚没金额(质押额 + 锁定费用的 0–100%)
  • 下一轮生效(当前轮正常结束)
  • 无法重新激活——必须重新注册

退出

  1. announceExit() — 发出事件,通知期为 1 轮(可由治理配置)
  2. Navigator 必须在通知期内继续投票
  3. 延迟失效:宣布退出后,所有公民委托在视图层面立即作废
    • isDelegated() 返回 false,getDelegatedAmount() 返回 0
    • VOT3 转账锁自动解除(公民无需采取任何操作)
    • castNavigatorVote 失败并返回 NotDelegatedToNavigator
    • 不再接受新公民委托(NavigatorCannotAcceptDelegations)
  4. 公民可以直接重新委托给新的 Navigator,无需先调用 undelegate()(过期委托会自动清除)
  5. 退出通知期结束后(达到停用检查点),即可调用 withdrawStake()——质押额立即返还。锁定费用仍按照各自的 4 轮计划,通过 claimFee(roundId) 领取
  6. 重新加入 = 重新注册
  7. 没有 finalizeExit()——退出通过检查点时间自动生效
Navigator 退出/停用时的公民体验

公民无需采取任何操作——VOT3 通过延迟失效自动解锁:

  • getDelegatedAmount(citizen) 检查 Navigator 是否已失效 → 返回 0
  • VOT3._update() 读取 getDelegatedAmount → 发现返回值为 0 → 允许转账
  • 公民可以直接调用 delegate(newNavigator, amount)——旧的过期检查点会自动清除
  • 保留历史委托数据用于奖励计算(不影响 getDelegatedAmountAtTimepoint)
索引器:隐式移除委托

Navigator 退出或停用时,不会发出 DelegationRemoved 事件。索引器必须将 ExitAnnounced / NavigatorDeactivated 事件视为移除该 Navigator 的所有公民委托。

质押和投票权

Navigator 质押 B3TR,底层会将其转换为 VOT3。质押金额由 NavigatorRegistry 以 VOT3 形式持有,并计入 Navigator 的个人投票权(通过 stakedAmount Trace208 创建检查点)。NavigatorRegistry 在初始化时会在 VOT3 上进行自我委托,以确保总投票供应量准确。

质押的 VOT3 仅计入投票权——不能用于支持提案,也不能降低权力。它不会直接产生奖励。

角色投票权来源不计入的内容
Navigator(自行投票)个人 VOT3 余额 + 质押的 B3TR(以 VOT3 形式)公民委托的 VOT3
公民(由 Navigator 代投)快照时其委托的 VOT3 数量未委托的剩余 VOT3

委托的 VOT3 始终留在公民的钱包中。Navigator 决定投票方向;每位公民的委托金额作为单独的一票投出。

**B3TR↔VOT3 转换流程:**调用 register()/addStake() 时:B3TR 转入合约 → 通过 VOT3.convertToVOT3() 转换为 VOT3。调用 reduceStake()/withdrawStake()/罚没时:VOT3 通过 VOT3.convertToB3TR() 转回 B3TR → 转出。

**经济机制:**质押的 B3TR 为 Navigator 提供投票权。Navigator 还必须吸引委托才能赚取费用。例如:质押 50K B3TR(= 50K VOT3 投票权)→ 最多获得 500K VOT3 委托 → Navigator 从这 500K VOT3 产生的奖励中赚取 20% 的费用。

合约级保护措施

保护措施合约错误
阻止自我委托NavigatorDelegationUtilsSelfDelegationNotAllowed
委托者不能注册为导航者NavigatorStakingUtilsDelegatorCannotRegister
公民不能手动投票(分配)XAllocationVotingDelegatedToNavigator
公民不能手动投票(治理)GovernorVotesLogicDelegatedToNavigator
导航者不能启用自动投票XAllocationVotingNavigatorCannotEnableAutoVoting
公民不能启用自动投票XAllocationVotingDelegatedToNavigator
仅限 VoterRewards 存入费用NavigatorRegistryUnauthorizedCaller
退出/停用时延迟失效NavigatorDelegationUtils_isNavigatorDead()

关键合约

新增
  • NavigatorRegistry — UUPS 可升级门面,包含 6 个库:NavigatorStakingUtils、NavigatorDelegationUtils、NavigatorVotingUtils、NavigatorFeeUtils、NavigatorSlashingUtils、NavigatorLifecycleUtils
已修改
  • VOT3.sol(V2)— 从 NavigatorRegistry 读取委托锁,不重复存储
  • XAllocationVoting.sol(V9)— 面向公民和治理的 castNavigatorVote、disableAutoVotingFor、startNewRound
  • B3TRGovernor.sol(V10)— castNavigatorVote、getActiveProposals、proposalsForRound、relayerRewardsPool
  • VoterRewards.sol(V7)— 倍数检查点、导航者费用扣除、意向倍数
  • RelayerRewardsPool.sol(V3)— 按用户跟踪跳过情况、setTotalActionsForRoundWithGovernance、activeProposalsForRound
依赖项(只读)
  • VOT3.sol — 用于最大质押上限的流通供应量
  • VeBetterPassport — 身份验证检查(对已委托的公民在快照时验证;跳过非自然人)
  • RelayerRewardsPool — 中继者注册检查、preferredRelayer、按用户跟踪跳过情况
  • B3TRGovernor — 在轮次开始时查询活跃提案

代码库参考

导航者合约
  • /packages/contracts/contracts/navigator/NavigatorRegistry.sol — 主门面
  • /packages/contracts/contracts/navigator/libraries/NavigatorStorageTypes.sol — 单一 ERC-7201 命名空间
  • /packages/contracts/contracts/navigator/libraries/NavigatorStakingUtils.sol
  • /packages/contracts/contracts/navigator/libraries/NavigatorDelegationUtils.sol
  • /packages/contracts/contracts/navigator/libraries/NavigatorVotingUtils.sol
  • /packages/contracts/contracts/navigator/libraries/NavigatorFeeUtils.sol
  • /packages/contracts/contracts/navigator/libraries/NavigatorSlashingUtils.sol
  • /packages/contracts/contracts/navigator/libraries/NavigatorLifecycleUtils.sol
  • /packages/contracts/contracts/interfaces/INavigatorRegistry.sol
已修改的合约
  • /packages/contracts/contracts/x-allocation-voting-governance/XAllocationVoting.sol
  • /packages/contracts/contracts/x-allocation-voting-governance/libraries/VotesUtils.sol
  • /packages/contracts/contracts/governance/B3TRGovernor.sol
  • /packages/contracts/contracts/governance/libraries/GovernorVotesLogic.sol
  • /packages/contracts/contracts/governance/libraries/GovernorStorageTypes.sol
  • /packages/contracts/contracts/governance/libraries/GovernorConfigurator.sol
  • /packages/contracts/contracts/VoterRewards.sol
  • /packages/contracts/contracts/VOT3.sol
  • /packages/contracts/contracts/RelayerRewardsPool.sol

v1 中未包含

  1. 导航者可配置的费用率(固定为 20%)

评论

支持 Markdown