| Contract | Address |
|---|---|
| RelayerRewardsPool | 0x34b56f892c9e977b9ba2e43ba64c27d368ab3c86 |
| XAllocationVoting | 0x89A00Bb0947a30FF95BEeF77a66AEdE3842Fe5B7 |
| VoterRewards | 0x838A33AF756a6366f93e201423E1425f67eC0Fa7 |
Manages relayer registration, action tracking, and reward distribution.
Anyone can register as a relayer by calling registerRelayer(). No admin approval needed.
registerRelayer() // Self-register as a relayer (open to anyone)
unregisterRelayer(address) // Admin only (POOL_ADMIN_ROLE)
isRegisteredRelayer(address) -> bool
getRegisteredRelayers() -> address[]relayerFeePercentage = 10 // 10% of user rewards
feeCap = 100 ether // Max 100 B3TR per user per round
voteWeight = 3 // Points per vote action
claimWeight = 1 // Points per claim action
earlyAccessBlocks = 432,000 // ~5 days on VeChain
relayerShare = (relayerWeightedActions / completedWeightedActions) * totalRewards
Rewards are claimable when:
- The round has ended
- All work is done (
completedWeightedActions >= totalWeightedActions)
// Registration
registerRelayer()
isRegisteredRelayer(address) -> bool
getRegisteredRelayers() -> address[]
// Reward claiming
claimRewards(uint256 roundId)
isRewardClaimable(uint256 roundId) -> bool
getTotalRewards(uint256 roundId) -> uint256
getRelayerWeightedActions(uint256 roundId, address relayer) -> uint256
// Internal (called by other contracts)
registerRelayerAction(address relayer, address voter, uint256 roundId, ActionType action)
deposit(uint256 amount, uint256 roundId)
setTotalActionsForRound(uint256 roundId, uint256 userCount)
reduceExpectedActionsForRound(uint256 roundId, uint256 userCount)Auto-voting was added in v8 via the AutoVotingLogicUpgradeable module.
toggleAutoVoting(address user) // Enable/disable auto-voting
setUserVotingPreferences(bytes32[] memory appIds) // Set apps (1-15, no duplicates)
getUserVotingPreferences(address) -> bytes32[] // View preferences
isUserAutoVotingEnabled(address) -> bool // Current statuscastVoteOnBehalfOf(address voter, uint256 roundId)This function:
- Validates early access (registered relayer during the 5-day window)
- Gets user preferences, filters eligible apps
- Splits voting power equally across eligible apps
- Casts the vote
- Registers a VOTE action on RelayerRewardsPool (3 weight points)
isUserAutoVotingEnabledForRound(address, uint256) -> bool
getTotalAutoVotingUsersAtRoundStart() -> uint256
getTotalAutoVotingUsersAtTimepoint(uint48) -> uint256Auto-voting status is checkpointed: changes take effect from the next round, not the current one.
Fee deduction happens in VoterRewards.claimReward():
- Check user had auto-voting enabled at round start (checkpointed)
- Calculate raw rewards (voting + GM reward)
- If auto-voting:
fee = min(totalReward * 10/100, 100 B3TR) - Fee approved + deposited to
RelayerRewardsPool.deposit(fee, cycle) - Register CLAIM action for
msg.sender(1 weight point) - Net reward transferred to voter wallet
msg.sender calling claimReward() IS the relayer credited for the CLAIM action.
During the early access period, only registered relayers can act. Users cannot self-vote or self-claim.
| Window | Duration | Start |
|---|---|---|
| Vote window | ~5 days | Round snapshot |
| Claim window | ~5 days | Round deadline |
After the early access period, anyone can act — this is the safety net ensuring users always receive their rewards.
Round N: User enables auto-voting + sets preferences (checkpointed)
Round N+1:
1. startNewRound() — snapshot locks auto-voting status
2. setTotalActionsForRound(roundId, userCount)
3. Relayers call castVoteOnBehalfOf() for each user
- Ineligible users: reduceExpectedActionsForRound()
- Each successful vote: +3 weighted points to relayer
4. Round ends (deadline block)
5. Relayers call VoterRewards.claimReward() for each user
- Fee deducted and deposited to pool
- Each successful claim: +1 weighted point to relayer
6. All actions complete → pool unlocked
7. Relayers call RelayerRewardsPool.claimRewards()