mcpField
A
auto-voting-relayers

auto-voting-relayers

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

关于 auto-voting-relayers

auto-voting-relayers skill 为 VeBetterDAO 的合约、relayer 节点、仪表板和文档提供领域知识,涵盖自动投票与 Navigator 委托投票。它说明投票、奖励领取、费用扣除和 relayer 奖励池的运作流程。

主要功能

  1. 01说明自动投票与偏好设置
  2. 02涵盖 Navigator 委托投票
  3. 03介绍 relayer 注册及奖励分配
  4. 04详述合约职责与投票流程
  5. 05说明奖励费用扣除方式

适用场景

  1. 01开发或维护 VeBetterDAO 自动投票组件
  2. 02理解 Navigator 公民投票流程
  3. 03排查 relayer 操作与奖励领取
  4. 04查阅合约函数及各轮预期操作

安装

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

$npx skills add https://github.com/vechain/vechain-ai-skills --skill auto-voting-relayers

安装后在 Claude Code 中输入/auto-voting-relayers确认已加载。

详细介绍

VeBetterDAO 自动投票与中继系统

自动投票与中继生态系统的完整领域知识。本技能为处理系统的任何组件提供背景信息:智能合约、中继节点、中继仪表板或文档。

系统概览

VeBetterDAO 的自动投票系统允许用户自动完成每周的 X Allocation 投票。用户只需选择一次喜爱的应用,并开启自动投票;中继(链下服务)便会处理后续事项:投票、领取奖励,全程免 Gas。中继从奖励池中赚取手续费。代币始终留在用户的钱包中。

借助 Navigators 功能,中继还会为委托给 Navigator 的公民提供服务,代表他们参与分配轮次投票和治理提案投票。计算预期操作总数时,也会将这些公民与自动投票用户一并计入。

架构

Users (toggle auto-voting, set preferences)
Citizens (delegate VOT3 to a navigator)
    |
    v
Smart Contracts (on-chain logic)
    - XAllocationVoting (v9): auto-voting state, vote execution, castNavigatorVote
    - B3TRGovernor (v10): governance castNavigatorVote, getActiveProposals
    - VoterRewards (v7): reward claiming, fee deduction (relayer + navigator fees)
    - RelayerRewardsPool (v3): relayer registration, reward distribution, per-user skip tracking
    - NavigatorRegistry: delegation state, preferences, governance decisions
    |
    v
Relayer Nodes (off-chain execution)
    - relayer-node/ (standalone CLI, no monorepo dependency)
    - Monitor rounds, batch vote/claim, loop every 5 min
    - Serve both auto-voting users and navigator citizens
    |
    v
Relayer Dashboard (monitoring/analytics)
    - apps/relayer-dashboard/ (static Next.js, GitHub Pages)
    - Round analytics, relayer stats, ROI tracking

工作原理(非技术版)

用户(自动投票)
  1. 持有至少 1 个 VOT3,完成至少 3 项可持续行动,并通过 VeBetterPassport 验证
  2. 最多选择 15 个应用,并开启自动投票
  3. 下一轮开始生效(不适用于当前轮次)
  4. 每周:中继代表你投票,并将奖励领取到你的钱包
  5. 手续费:奖励的 10%(每周最多 100 B3TR),用于支付所有 Gas 费用
  6. 自动投票处于启用状态期间:不可手动投票或领取奖励
  7. 手动领取备用方案:如果中继尚未处理,可在轮次结束 5 天后使用
公民(Navigator 委托)
  1. 将指定数量的 VOT3 委托给 Navigator
  2. 委托后会自动关闭自动投票
  3. 中继使用 Navigator 的应用偏好为分配轮次投票
  4. 中继根据 Navigator 的决定(赞成/反对/弃权)为治理提案投票
  5. 中继领取奖励——先扣除 Navigator 手续费,再扣除中继手续费
  6. 剩余奖励将发放至公民的钱包
自动关闭触发条件(自动投票)
  • VOT3 低于 1 个
  • 所有选中的应用都不再符合资格
  • 未达到可持续行动门槛
  • 被应用所有者检测为机器人
中继
  1. 在链上调用 RelayerRewardsPool 的 registerRelayer() 进行注册(任何人均可注册)
  2. 使用钱包运行 relayer-node(MNEMONIC 或 RELAYER_PRIVATE_KEY)
  3. 节点会自动发现自动投票用户和 Navigator 委托公民
  4. 获得加权积分:投票 = 3 分,领取奖励 = 1 分(自动投票和公民投票均适用)
  5. 为公民投治理提案也可获得投票权重(每次 3 分)
  6. 完成(或跳过)所有预期操作后,领取奖励池中的按比例分成
应用作为中继

应用可以注册成为中继,请求用户将其设为偏好应用,并运行节点。这样应用无需向 veDelegate 支付投票费用,反而可以赚取中继手续费。重要提示:应用应将自己添加到偏好列表中,而不是替换其他应用。

与 veDelegate 的对比

功能veDelegateVeBetterDAO 自动投票
X Allocation 投票是是
治理投票是(始终为“弃权”)是(公民投票:采用 Navigator 的决定)
复投(B3TR->VOT3)自动手动
代币托管离开钱包留在钱包中
中心化程度单一实体多个中继
应用成本应用向 veDelegate 付费应用赚取手续费

veDelegate:docs.vedelegate.vet / github.com/vechain-energy/vedelegate-for-dapps

智能合约详情

XAllocationVoting.sol (v9)

v8 新增自动投票,v9 新增 Navigator 投票。现在采用外部库架构。

存储(位于 AutoVotingLogic / XAllocationVotingStorageTypes 中):

  • _autoVotingEnabled:按用户记录的检查点状态(更改在下一轮生效)
  • _userVotingPreferences:每位用户的应用 ID 数组(最多 15 个,经过验证且无重复)
  • _totalAutoVotingUsers:记录检查点的总数
  • navigatorRegistry:INavigatorRegistry 引用(V9)

关键函数:

toggleAutoVoting(address user)                         // Enable/disable
setUserVotingPreferences(bytes32[] memory appIds)      // Set apps (1-15)
castVoteOnBehalfOf(address voter, uint256 roundId)     // Relayer executes auto-vote
castNavigatorVote(address citizen, uint256 roundId)    // Relayer executes citizen vote (vote-or-skip)
disableAutoVotingFor(address user)                     // Privileged, called by NavigatorRegistry on delegation
getUserVotingPreferences(address)                      // View preferences
isUserAutoVotingEnabled(address)                       // Current status
isUserAutoVotingEnabledForRound(address, uint256)      // Status at round snapshot
getTotalAutoVotingUsersAtRoundStart()                  // Count at last emission
getTotalAutoVotingUsersAtTimepoint(uint48)             // Historical count

投票执行(castVoteOnBehalfOf — 自动投票用户):

  1. 验证提前访问资格(窗口期内的已注册中继者)
  2. 获取用户偏好设置,筛选符合条件的应用
  3. 将投票权平均分配给符合条件的应用
  4. 通过内部 _countVote() 投票
  5. 在 RelayerRewardsPool 中登记 VOTE 操作(3 个权重积分)

Navigator 投票执行(castNavigatorVote — 公民):

跳过或投票决策流程(合并到函数中,没有单独的跳过调用):

  1. 快照时 Navigator 已失效 → 回退并报错 NotDelegatedToNavigator
  2. Navigator 现在已失效(快照后退出/停用)→ 通过 pool.reduceUserAllocationVote 跳过,发出 NavigatorVoteSkipped
  3. Navigator 有效 + 已设置偏好 → 使用 Navigator 自定义百分比(基点,总和必须为 10000)正常投票,并登记 RelayerAction.VOTE
  4. Navigator 有效 + 未设置偏好 + 已到跳过窗口期 → 跳过,发出 NavigatorVoteSkipped
  5. Navigator 有效 + 未设置偏好 + 未到跳过窗口期 → 回退并报错 SkipWindowNotReached

跳过窗口期:XAllocationVoting.citizenSkipWindowBlocks() — 可通过存储配置(V9 迁移),默认约 720 个区块(距本轮截止时间约 2 小时)。通过 getter 从链上读取;不要硬编码——治理可以通过 setCitizenSkipWindowBlocks 更新该值,且不同网络的值可能不同。

startNewRound() — 设置预期操作:

计算本轮的预期操作:

  • allocationUsers = autoVotingUsers + totalDelegatedCitizens
  • governanceUsers = totalDelegatedCitizens(仅公民——中继者不会代表自动投票用户进行治理投票)
  • 获取 governor.getActiveProposals()
  • 调用 pool.setTotalActionsForRoundWithGovernance(roundId, allocationUsers, governanceUsers, activeProposals)
B3TRGovernor.sol (v10)

v10 新增 Navigator 治理投票和中继者集成。

castNavigatorVote(proposalId, citizen) — 公民治理投票:

与 XAllocationVoting 的跳过或投票模式相同:

  1. 快照时 Navigator 已失效 → 回退并报错 NotDelegatedToNavigator
  2. Navigator 现在已失效 → 通过 pool.reduceUserGovernanceVote 跳过,发出 NavigatorGovernanceVoteSkipped
  3. Navigator 有效 + 已设置决策 → 正常投票,并在 RelayerRewardsPool 中登记 RelayerAction.VOTE
  4. Navigator 有效 + 未设置决策 + 已到跳过窗口期 → 跳过,发出 NavigatorGovernanceVoteSkipped
  5. Navigator 有效 + 未设置决策 + 未到跳过窗口期 → 回退并报错 GovernanceSkipWindowNotReached

跳过窗口期:B3TRGovernor.governanceSkipWindowBlocks() — 可通过存储配置(V10 迁移),默认约 720 个区块(距提案截止时间约 2 小时)。通过 getter 从链上读取;不要硬编码——治理可以通过 setGovernanceSkipWindowBlocks 更新该值,且不同网络的值可能不同。

映射 Navigator 决策:1=反对,2=赞成,3=弃权 → governor 支持值 0、1、2。 奖励采用意图乘数。

getActiveProposals() — 返回当前活跃的提案 ID(从 proposalsForRound 映射中过滤,该映射在创建提案时填充)。供 XAllocationVoting.startNewRound 用于计算治理预期操作。

VoterRewards.sol (v7)

V6 添加了中继者费用集成。V7 添加了导航员费用扣除和奖励乘数。

V7 存储新增项: navigatorRegistry

claimReward(uint256 cycle, address voter) 中的费用流程:

  1. 检查用户在轮次开始时是否启用了自动投票或委托(已记录检查点)
  2. 计算原始奖励(投票奖励 + GM 奖励)
  3. 如果是公民(已委托):先从总奖励中扣除导航员费用 → 存入 NavigatorRegistry 费用托管账户
  4. 如果启用了自动投票或已委托:从剩余金额中扣除中继者费用 → RelayerRewardsPool.deposit(fee, cycle)
  5. registerRelayerAction(msg.sender, voter, cycle, CLAIM) — 为调用者记入 1 个权重点
  6. 将净奖励转入投票者钱包

费用公式:

Navigator fee = gross * navigatorFeePercentage / 10000 (citizens only, goes to NavigatorRegistry escrow)
Relayer fee = min((gross - navigatorFee) * relayerFeePercentage / 100, feeCap) (auto-voters AND citizens)

重要: 调用 claimReward() 的 msg.sender 就是获得 CLAIM 操作记账的中继者。

提前访问: 在此窗口期间,如果调用者是投票者本人或不是已注册的中继者,则调用会回退。自动投票用户和公民均适用。

RelayerRewardsPool.sol (v3)

管理注册、操作跟踪、奖励分配和逐用户跳过跟踪。

核心存储:

totalRewards[roundId]                    // Pool amount (funded by fees)
relayerWeightedActions[roundId][relayer] // Per-relayer weighted work
totalWeightedActions[roundId]            // Expected weighted total
completedWeightedActions[roundId]        // Completed weighted total
registeredRelayers[address]              // Registration mapping
relayerAddresses[]                       // All registered addresses
voteWeight = 3                           // Points per vote action
claimWeight = 1                          // Points per claim action
earlyAccessBlocks = 432,000              // ~5 days on VeChain
relayerFeePercentage = 10               // 10%
feeCap = 100 ether                       // 100 B3TR

V3 存储新增项:

activeProposalsForRound[roundId]                      // Cached governance proposal IDs
userAllocationVoteReduced[roundId][user]               // Per-user allocation skip flag
userGovernanceVoteReduced[roundId][user][proposalId]   // Per-user/proposal governance skip flag
userClaimReduced[roundId][user]                        // Per-user claim auto-reduction flag

奖励公式:

relayerShare = (relayerWeightedActions / completedWeightedActions) * totalRewards

可领取条件: isRewardClaimable(roundId) 要求:

  • 轮次已结束(emissions.isCycleEnded(roundId))
  • 所有工作均已完成(completedWeightedActions >= totalWeightedActions)
  • 逐用户跳过会自动减少 totalWeightedActions,因此被跳过的公民不会阻碍奖励领取

注册(任何人均可注册):

  • registerRelayer() — 自行注册
  • unregisterRelayer(address) — 可由管理员或中继者本人调用

预期操作设置:

  • setTotalActionsForRound(roundId, userCount) — 旧接口,调用 setTotalActionsForRoundWithGovernance,并将 governanceUsers 设为 0
  • setTotalActionsForRoundWithGovernance(roundId, allocationUsers, governanceUsers, activeProposalIds) — V3:设置预期操作数。总数 = allocationUsers * 2(投票 + 领取)+ governanceUsers * activeProposals(治理投票)。缓存 activeProposalIds

操作数减少:

  • reduceExpectedActionsForRound(roundId, userCount) — 批量减少不符合资格的自动投票用户对应的操作数
  • reduceUserAllocationVote(roundId, user) — 逐用户跳过分配投票。如果该用户的所有投票都被跳过,则自动减少领取操作数
  • reduceUserGovernanceVote(roundId, user, proposalId) — 逐用户、逐提案跳过治理投票。采用相同的自动减少逻辑
  • 防止重复跳过:如果同一用户、轮次或提案的操作数已减少,则调用会回退

操作登记:

  • registerRelayerAction(relayer, voter, roundId, action) — 记录投票或领取工作
  • deposit(amount, roundId) — 将费用扣款存入资金池

提前访问:

  • 投票窗口:roundSnapshot + earlyAccessBlocks
  • 领取窗口:roundDeadline + earlyAccessBlocks
  • 窗口期间:仅已注册的中继者可操作,用户不能自行操作
  • 窗口结束后:任何人均可操作

每轮中继者生命周期

Round N: Users enable auto-voting / citizens delegate to navigators (checkpointed)
Round N+1:
  1. startNewRound() - snapshot locks status
     - allocationUsers = autoVotingUsers + totalDelegatedCitizens
     - governanceUsers = totalDelegatedCitizens
     - fetches activeProposals from B3TRGovernor
     - calls setTotalActionsForRoundWithGovernance(roundId, allocationUsers, governanceUsers, activeProposals)

  2. ALLOCATION VOTING:
     a. Relayers call castVoteOnBehalfOf(voter, roundId) for auto-voting users
        - Ineligible users: reduceExpectedActionsForRound()
        - Each successful vote: +3 weighted points
     b. Relayers call castNavigatorVote(citizen, roundId) for citizens
        - Navigator dead/no-prefs + skip window reached: skip (reduceUserAllocationVote)
        - Navigator alive + prefs set: vote, +3 weighted points

  3. GOVERNANCE VOTING (concurrent with allocation):
     For each active proposal:
       Relayers call B3TRGovernor.castNavigatorVote(proposalId, citizen) for each citizen
       - Navigator dead/no-decision + skip window reached: skip (reduceUserGovernanceVote)
       - Navigator alive + decision set: vote, +3 weighted points

  4. Round ends (deadline block)

  5. CLAIMS:
     Relayers call VoterRewards.claimReward(cycle, user) for auto-voters and citizens
     - Navigator fee deducted first (citizens only), then relayer fee
     - Each successful claim: +1 weighted point
     - If all votes for a citizen were skipped, claim is auto-reduced (no claim needed)

  6. All expected actions completed (or reduced via skips) -> pool unlocks
  7. Relayers call RelayerRewardsPool.claimRewards(roundId)

导航员公民集成

中继者服务于委托给导航员的公民,以及启用了自动投票的用户。这是在现有自动投票逻辑基础上的新增功能。

与自动投票的主要区别
方面自动投票用户Navigator 公民
投票函数(分配)castVoteOnBehalfOf(voter, roundId)castNavigatorVote(citizen, roundId)
投票函数(治理)不适用B3TRGovernor.castNavigatorVote(proposalId, citizen)
发现方式AutoVotingToggled 事件DelegationCreated/Removed 事件
偏好设置用户自己的应用列表(均分)Navigator 的 AllocationPreferencesSet(自定义百分比)
治理不适用Navigator 的 GovernanceDecisionSet
投票权快照时的全部 VOT3 余额快照时委托的数量(已记录检查点)
身份验证是否
是否计入预期操作?是(仅分配)是(分配 + 治理)
跳过机制reduceExpectedActionsForRound(批量)按用户跳过,并设有跳过窗口
领取函数claimReward(cycle, voter)相同——claimReward(cycle, citizen)
领取时的费用仅中继者费用先扣 Navigator 费用,再扣中继者费用
计入预期操作的公民

公民会计入预期操作。每轮开始时:

  • allocationUsers = autoVotingUsers + totalDelegatedCitizens(用于分配投票 + 领取)
  • governanceUsers = totalDelegatedCitizens(用于治理投票——仅公民,不包括自动投票用户)
  • governanceUsers 单独计算,因为中继者不会替自动投票用户投治理票

跳过窗口(可按网络通过存储配置,默认为截止时间前约 720 个区块 / 约 2 小时——从 XAllocationVoting.citizenSkipWindowBlocks() / B3TRGovernor.governanceSkipWindowBlocks() 读取)和按用户跟踪跳过状态可避免死锁:如果 Navigator 未设置偏好,中继者可在跳过窗口开启后跳过该公民的投票,按比例减少预期操作。

跳过或投票流程(适用于分配和治理)

castNavigatorVote 在同一个函数中处理投票和跳过:

  1. 快照时 Navigator 已失效 → 回滚(快照时该公民未委托)
  2. Navigator 目前已失效(自快照后退出 / 停用)→ 立即跳过,并减少预期操作
  3. Navigator 仍有效,且已设置偏好 / 决策 → 正常投票
  4. Navigator 仍有效,尚未设置偏好 / 决策,且已到达跳过窗口 → 跳过
  5. Navigator 仍有效,尚未设置偏好 / 决策,且尚未到达跳过窗口 → 回滚 SkipWindowNotReached / GovernanceSkipWindowNotReached(中继者稍后重试)
按用户跟踪跳过状态

跳过某位公民的投票时:

  • 分配:reduceUserAllocationVote(roundId, citizen) — 减少预期操作
  • 治理:reduceUserGovernanceVote(roundId, citizen, proposalId) — 按提案分别减少
  • 某位公民的所有投票(分配 + 所有治理提案)都被跳过后,领取操作会自动减少
  • 每次跳过均按用户、轮次和提案分别记录,以防重复减少
治理投票登记

B3TRGovernor.castNavigatorVote 会针对每次治理投票,在 RelayerRewardsPool 中登记 RelayerAction.VOTE。中继者每次治理投票可获得与分配投票相同的 3 个权重积分。

公民费用扣除顺序
  1. Navigator 费用:从奖励总额中扣除(转入 NavigatorRegistry 费用托管账户)
  2. 中继者费用:从剩余金额中扣除(百分比和上限与自动投票相同,转入 RelayerRewardsPool)
  3. 公民获得剩余金额
委托时禁用自动投票

用户委托给 Navigator 时,其自动投票会通过 XAllocationVoting.disableAutoVotingFor(citizen) 自动禁用,以防止重复计数和投票路径冲突。取消委托后,用户必须手动重新启用自动投票。

首选中继者
  • 公民通过 relayerRewardsPool.setPreferredRelayer(relayer) 手动设置 preferredRelayer
  • 在早期访问期间,如果已设置首选中继者且该中继者已注册,则只有该中继者可以代表公民操作
  • 委托时不会自动设置——公民必须手动设置
  • 公民可随时更改或清除首选中继者

中继节点 (relayer-node/)

独立的 CLI 工具。无单仓库依赖。

依赖项: @vechain/sdk-core、@vechain/sdk-network、@vechain/vebetterdao-contracts

relayer-node/src/
  index.ts      # Entry, env parsing, main loop, SIGINT
  config.ts     # Mainnet + testnet-staging addresses
  contracts.ts  # 26 view functions + event pagination
  relayer.ts    # Batch vote/claim with isolation/retry
  display.ts    # Terminal UI (box drawing + chalk)
  types.ts      # Shared interfaces

环境变量: MNEMONIC / RELAYER_PRIVATE_KEY、RELAYER_NETWORK、RUN_ONCE、DRY_RUN

周期: 从事件中发现用户 -> 筛选已投票用户 -> 批量调用 castVoteOnBehalfOf + castNavigatorVote -> 批量调用治理 castNavigatorVote -> 批量调用 claimReward -> 每 5 分钟循环一次

中继仪表板 (apps/relayer-dashboard/)

静态 Next.js 14(输出:“export”)、Chakra UI v3、VeChain Kit、Recharts。托管于 GitHub Pages 的 /b3tr 路径下。

数据: 静态 report.json(每小时由 GH Action 临时生成)+ 通过 useCallClause 读取链上数据

页面(基于状态的导航,非文件路由):

  • 首页:StatsCards(2x2)、RoundsChart、RoundsList、信息卡片
  • 我的中继器:ConnectedWallet 视图
  • 信息:BecomeRelayer + AppsAsRelayers
  • 轮次详情:/round?roundId=X - 双栏布局,包含摘要/操作/财务信息

钩子:

  • contracts.ts - 来自 @repo/config 的 ABI + 地址
  • useCurrentRoundId - XAllocationVoting.currentRoundId()
  • useTotalAutoVotingUsers - getTotalAutoVotingUsersAtTimepoint()
  • useRegisteredRelayers - getRegisteredRelayers()
  • useRoundRewardStatus - isRewardClaimable() + getTotalRewards()
  • useReportData - 获取 /data/report.json
  • useB3trToVthoRate - 预言机汇率

命令: yarn relayer:dev:staging、yarn relayer:dev:mainnet、yarn relayer:build:staging、yarn relayer:build:mainnet

Gas 成本分析

操作GasVTHO等值 B3TR
投票(5-8 个应用)~441K~4.41~0.075
领取~208K~2.08~0.035
每位用户/每轮总计~6.49~0.11

平均用户:约 10.8k-22.6k VOT3,每轮可获得约 90-190 B3TR。 按 10% 的费用计算:每位用户约有 9-19 B3TR 进入奖励池。中继器成本:0.11 B3TR。利润:每位用户约 8.9-18.9 B3TR。

外部资源

评论

支持 Markdown