
Vebetterdao
- 87 installs
- 9 repo stars
- Updated June 11, 2026
- vechain/vechain-ai-skills
Helps with ai & agent building tasks.
About
vebetterdao is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- vebetterdao
- AI & Agent Building
- AI-coding skill
Vebetterdao by the numbers
- 87 all-time installs (skills.sh)
- +2 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #4,982 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/vechain/vechain-ai-skills --skill vebetterdaoAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 87 |
|---|---|
| repo stars | ★ 9 |
| Last updated | June 11, 2026 |
| Repository | vechain/vechain-ai-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
VeBetterDAO Skill
CRITICAL RULES
1. Read reference files FIRST. When the user's request involves any topic in the reference map below, read those files before doing anything else — before writing code, before making decisions. Briefly mention which files you are reading so the user can confirm the skill is active (e.g., "Reading VeBetterDAO reference..."). 2. Information priority for VeChain topics: (a) Reference files in this skill — always the primary source. (b) VeChain MCP tools — use @vechain/mcp-server for on-chain data, transaction building, and live network queries; use Kapa AI MCP for VeChain documentation lookups. (c) Web search — only as a last resort, and only for topics NOT covered in the reference files. 3. Prefer working directly in the main conversation for VeChain tasks. Plan mode and subagents do not inherit skill context and may fall back to web search instead of using reference files. 4. After compaction or context loss, re-read this SKILL.md to restore awareness of the reference map and operating procedure before continuing work.
Scope
Use this Skill for VeBetterDAO ecosystem development:
- X2Earn sustainability app development
- B3TR and VOT3 token integration
- Reward distribution (smart contract, hybrid, backend-only patterns)
- Sustainability proofs and impact codes
- App submission process to VeBetterDAO
- Governance: VeVote, proposals, voting, quadratic funding, allocation rounds
- Navigators: delegation, staking, freshness/intent multipliers, slashing
- B3MO Quests: quest creation, invitations, joining/leaving, claims, refunds, and indexer/frontend flows
Operating procedure
1. Clarify before implementing
When the user's request is ambiguous, ask before building. Key questions:
- Which reward distribution pattern? (smart contract / hybrid / backend-only)
- Mainnet or testnet deployment?
- Does the app already have VeBetterDAO integration?
2. Implement with VeChain-specific correctness
- Network: always explicit (
mainnet/testnet/solo) - Tokens: B3TR for rewards, VOT3 for governance voting
- Use correct contract addresses for the target network
3. Verify and deliver
A task is not complete until all applicable gates pass:
1. Code compiles — no build errors 2. Tests pass — existing tests still pass; new logic has test coverage 3. Risk notes documented — any token-transfer or governance implications are called out
Reference files
Read the matching files BEFORE doing anything else. See Critical Rules above.
- VeBetterDAO: references/vebetterdao.md — read for X2Earn, B3TR, sustainability, rewards, VeBetterDAO, impact codes, app submission.
- Governance: references/governance.md — read for VeVote, governance, voting, VOT3, proposal, steering committee, quadratic funding, allocation rounds.
- B3MO Quests: references/b3mo-quests.md — read for B3MO quests, quests, b3mo-quests, B3TRChallenges, SplitWin, MaxActions, quest invite, join quest, leave quest, claim prize, claim refund, quest indexer.
- Contracts: tokens & apps: references/contracts-tokens-apps.md — read for B3TR, VOT3, Emissions, XAllocationVoting, XAllocationPool, X2EarnRewardsPool, X2EarnApps, X2EarnCreator, DBAPool, endorsement, reward distribution.
- Contracts: governance & identity: references/contracts-governance-identity.md — read for B3TRGovernor, proposals, VoterRewards, GalaxyMember, Treasury, TimeLock, RelayerRewardsPool, GrantsManager, B3TRMultiSig, VeBetterPassport, signaling, entity linking, upgradeability.
- Navigators: references/navigators.md — navigator, navigators, delegation, staking, slashing, NavigatorRegistry, freshness multiplier, governance intent multiplier, navigator fee, citizen voting.
VeBetterDAO B3MO Quests
When to use
Use when the user asks about: B3MO quests, quests, /b3mo-quests, B3TRChallenges, SplitWin, MaxActions, quest invitations, joining/leaving/declining quests, claim/refund flows, quest indexer endpoints, or the B3MO quests frontend.
What are B3MO Quests?
B3MO Quests are peer-to-peer or sponsored competitions where users complete X2Earn app actions to win B3TR.
Naming rule: call the feature B3MO Quests or quests in prose and user-facing copy. challenge only appears where it is still the technical contract/API/code name, such as B3TRChallenges, getChallengeStatus, or /api/v1/b3tr/challenges.
Two core modes:
MaxActions: capped participant pool; top scorer(s) win the pool.SplitWin: sponsored-only, uncapped joins; first users reaching the threshold claim fixed prize slots.
Quest kind:
Stake: participants put up stake; winners/refunds depend on settlement.Sponsored: creator funds prize pool; users join without staking.
Visibility:
Public: discoverable and joinable while pending.Private: join via invitation.
Core Contract
- Contract:
B3TRChallenges - Interface:
IChallenges - Types library:
ChallengeTypes - Frontend config address commonly exposed as
challengesContractAddress - Frontend ABI usually comes from
B3TRChallenges__factory
Key statuses:
Pending: created, joinable/acceptable, not started.Active: started; participants can accumulate actions.Completed: settled; winners/refunds can claim depending on mode.Cancelled: creator cancelled before activation.Invalid: quest could not activate, usually because constraints were not met.
Important view functions:
getChallenge(id): full on-chain quest struct/view.getChallengeStatus(id): preferred computed status; reflects time-based transitions withoutsyncChallenge.getChallengeParticipants(id): joined users.getChallengeInvited(id): invited users.getChallengeDeclined(id): users who declined.getChallengeWinners(id): winners for settled or SplitWin claims.getChallengeSelectedApps(id): X2Earn apps whose actions count.getParticipantStatus(id, account):None,Invited,Declined,Joined.isInvitationEligible(id, account): whether an account can accept/re-accept.isSplitWinWinner(id, account): whether account already won a SplitWin slot.getParticipantActions(id, participant): live action count.maxParticipants(): default max for MaxActions.minBetAmount(): minimum stake in wei.
Important nuance: after ChallengeLeft, getParticipantStatus returns None, not a stored Left state. To detect users who left, consult the ChallengeLeft event or an indexer record derived from it.
Lifecycle Events
All lifecycle events use challengeId as the first indexed topic because this is the contract-level identifier.
ChallengeCreated: indexedcreatorandendRound; new quest and metadata.SplitWinConfigured: SplitWin config, emitted after creation.ChallengeInviteAdded: indexedinvitee; private invitation.ChallengeJoined: indexedparticipant; user joined.ChallengeLeft: indexedparticipant; user left before start.ChallengeDeclined: indexedparticipant; invitee declined.ChallengeCancelled: creator cancelled pending quest.ChallengeActivated: pending to active.ChallengeInvalidated: pending to invalid.ChallengeCompleted: active to completed, includes settlement data.ChallengePayoutClaimed: indexedaccount; MaxActions payout claimed.ChallengeRefundClaimed: indexedaccount; cancelled/invalid refund claimed.SplitWinPrizeClaimed: indexedwinner; SplitWin slot prize claimed.SplitWinCreatorRefunded: indexedcreator; creator reclaimed unclaimed SplitWin slots after end.
Settlement and Claim Rules
Settlement modes:
None: no settlement yet.TopWinners: best scorers claim prize.CreatorRefund: creator recovers pool.SplitWinCompleted: SplitWin completed after slots are claimed or reclaimed.
Frontend/domain flags commonly derived from raw state:
canJoin: pending, public, not joined, not creator, not at participant limit.canAccept: pending invite or eligible invitee, not at limit. Declined users may re-accept if still eligible.canComplete: MaxActions active quest pastendRound, creator or joined participant.canClaim: MaxActions completed quest where joined participant hasbestScore, or creator refund settlement applies.canClaimSplitWin: SplitWin active, joined, in time window, actions >= threshold, slots left.canClaimCreatorSplitWinRefund: SplitWin creator, current round afterendRound, slots left, creator refund not yet claimed.canRefund: cancelled or invalid quest; forStake, joined users refund; forSponsored, creator refunds.
Wei boundary: stakeAmount, totalPrize, and prizePerWinner are wei on-chain. Convert with formatEther at frontend boundaries. threshold and bestScore are action counts, not B3TR amounts.
Frontend / Indexer Pattern
Common route: /b3mo-quests.
Recommended data split:
- List sections use indexer endpoints for pagination and segmentation.
- Detail views can still use direct contract calls plus event scans when immediate post-transaction freshness matters.
- Contract multicall enriches indexer quest IDs with live computed status, participant status, invitation eligibility, winner state, action counts, and claim flags.
Typical indexer endpoints:
GET /api/v1/b3tr/challenges?status=...: public quests by status.GET /api/v1/b3tr/users/{wallet}/challenges?filter=...: wallet-scoped quest sections.
Typical wallet filters:
NeededAction: invites, claimable, finalizable, reclaimable.MyChallenges: user-created or participating current quests.OpenToJoin: joinable quests.OthersActive: active public/social discovery quests.History: terminal quests plus left/declined current quests.
After write transactions, invalidate all quest query keys and schedule delayed refetches to catch indexer/event lag.
UX and Copy Conventions
- User-facing copy should say B3MO Quest(s) or Quest(s).
- Avoid saying "challenge" in product copy, docs headings, and feature descriptions.
- Keep
challengeonly for existing contract/API/code identifiers. - Status labels should come from a shared helper, not handwritten string formatting.
- Action buttons should be driven by domain flags (
canJoin,canAccept,canClaim, etc.), not duplicated UI logic.
Implementation Rules
- Prefer
getChallengeStatus(id)over stored struct status for read paths. - Keep event-derived states when the contract does not store them directly, especially users who left and claim history.
- For invited users leaving a pending quest, leave + decline may need to be chained so the user does not remain invitation-eligible.
- Do not format action counts as token amounts.
- Preserve fast post-transaction UX with broad invalidation plus delayed refetches.
VeBetterDAO Contracts — Governance & Identity
When to use
Use when the user asks about: B3TRGovernor, proposals, VoterRewards, GalaxyMember, Treasury, TimeLock, RelayerRewardsPool, NavigatorRegistry, GrantsManager, B3TRMultiSig, VeBetterPassport, signaling, entity linking, delegation, contract upgradeability, or UUPS proxy pattern.
Full source: github.com/vechain/vebetterdao-contracts Auto-generated docs: vechain.github.io/vebetterdao-contracts
---
B3TRGovernor (V11)
Main governance contract. Community creates proposals, deposits VOT3, votes with quadratic voting, executes through TimeLock, and (V11) pays out an on-chain implementation cost after delivery is confirmed. V11 added the Community Execution Framework on top of V10's navigator governance voting and relayer integration.
| Function | Description |
|---|---|
propose(targets, values, calldatas, description, startRoundId, depositAmount, maxBudget) | Create proposal with deposit requirement, start round, and optional V11 B3TR implementation cost (maxBudget = 0 disables the community-execution flow) |
deposit(proposalId, amount) | Contribute VOT3 to activate proposal |
castVote(proposalId, support) | Vote: 0=against, 1=for, 2=abstain. Reverts with DelegatedToNavigator for delegated citizens |
castVoteWithReason(proposalId, support, reason) | Vote with reason string |
castNavigatorVote(proposalId, citizen) | Vote-or-skip for navigator-delegated citizens. Maps navigator decision (1=Against, 2=For, 3=Abstain) to governor support. Registers RelayerAction.VOTE in RelayerRewardsPool. Applies intent multiplier |
getActiveProposals() | Returns active proposal IDs (filtered from proposalsForRound mapping) |
queue(proposalId) | Prepare approved proposal for execution |
execute(proposalId) | Execute via TimeLock |
cancel(proposalId) | Cancel proposal |
withdraw(proposalId) | Recover deposits after voting |
markAsInDevelopment(proposalId, payee, description, implementationDiscussion, contributors[]) | V11. Register the V11 community-execution payee + metadata. Proposer or PROPOSAL_STATE_MANAGER_ROLE. One-shot. |
updateCommunityExecution(proposalId, payee, description, implementationDiscussion, contributors[]) | V11. Replace V11 fields while InDevelopment/Completed and unpaid. Proposer or PROPOSAL_STATE_MANAGER_ROLE. |
markAsCompleted(proposalId) | V11. Flip dev state to Completed. PROPOSAL_STATE_MANAGER_ROLE only. |
claimPayout(proposalId) | V11. Public, idempotent. Transfers full maxBudget from Treasury to registered payee. Requires Completed. |
resetDevelopmentState(proposalId) | V11. Admin escape hatch (PROPOSAL_STATE_MANAGER_ROLE). |
getQuadraticVotingPower(account, timepoint) | Quadratic voting power |
toggleQuadraticVoting(roundId) | Enable/disable per round |
setNavigatorRegistry(address) | Set NavigatorRegistry address |
setRelayerRewardsPool(address) | Set RelayerRewardsPool address |
V10 storage: INavigatorRegistry navigatorRegistry, IRelayerRewardsPool relayerRewardsPool, mapping(uint256 => uint256[]) proposalsForRound (populated at proposal creation).
V11 storage additions: proposalMaxBudget, proposalPayee, proposalDescription, proposalImplementationDiscussion, proposalContributors, proposalPayeesFinalized, proposalPaid, proposalDevelopmentState, maxContributorsPerProposal (currently 20, no runtime setter).
ProposalState enum (V11): adds InDevelopment and Completed after Executed.
V10 events: NavigatorGovernanceVoteCast, NavigatorGovernanceVoteSkipped.
V11 events: ProposalBudgetSet(proposalId, maxBudget), ProposalInDevelopment(proposalId), ProposalInDevelopmentDetails(proposalId, payee, description, implementationDiscussion), ProposalContributorsSet(proposalId, contributors), ProposalCompleted(proposalId), ProposalPayoutClaimed(proposalId, payee, amount), ProposalDevelopmentStateReset(proposalId).
V11 errors: InvalidPayeeAddress, MissingProposalBudget, TooManyContributors, PayeesAlreadyFinalized, PayoutAlreadyClaimed, NotReadyToClaim, UnauthorizedCommunityExecution.
V11 Treasury role: Governor must hold Treasury.GOVERNANCE_ROLE to forward claimPayout via Treasury.transferB3TR(payee, maxBudget) — granted as part of the V11 upgrade.
V10 `castNavigatorVote` skip-or-vote flow: 1. Navigator dead at snapshot → revert NotDelegatedToNavigator 2. Navigator dead NOW → skip via pool.reduceUserGovernanceVote, emit NavigatorGovernanceVoteSkipped 3. Navigator alive + decision set → vote normally 4. Navigator alive + no decision + skip window (720 blocks before deadline) → skip 5. Navigator alive + no decision + skip window not reached → revert GovernanceSkipWindowNotReached
Proposal types: STANDARD (0) and GRANT (1) with type-specific thresholds.
| Role | Can |
|---|---|
GOVERNOR_FUNCTIONS_SETTINGS_ROLE | Whitelist callable functions |
PROPOSAL_EXECUTOR_ROLE | Execute proposals |
PROPOSAL_STATE_MANAGER_ROLE | Track proposal development |
PAUSER_ROLE | Pause contract |
Integrates with VeBetterPassport for voter identity verification. Logic stored in external libraries (GovernorClockLogic, GovernorConfigurator, GovernorDepositLogic, GovernorFunctionRestrictionsLogic, GovernorProposalLogic, GovernorQuorumLogic, GovernorStateLogic, GovernorVotesLogic).
VoterRewards (V7)
Calculates and distributes rewards to voters based on voting power and Galaxy Member NFT levels. V7 added rewards multipliers (freshness + governance intent) and navigator fee deduction.
| Function | Description |
|---|---|
registerVote(voter, votingPower, roundId) | Records vote with quadratic-weight calculation |
claimReward(cycle, voter) | Claim cycle-specific rewards. Deducts navigator fee (citizens) then relayer fee (auto-voters + citizens) |
getReward(cycle, voter) | View base reward amount |
getGMReward(cycle, voter) | View GM bonus reward |
getRelayerFee(cycle, voter) | Relayer fee for auto-voting/citizen claims |
getNavigatorFee(cycle, voter) | Navigator fee for citizen claims (V7) |
getFreshnessMultipliers(timepoint) | Returns tier1, tier2, tier3 freshness multiplier values (V7) |
getIntentMultipliers(timepoint) | Returns forAgainst, abstain intent multiplier values (V7) |
setFreshnessMultipliers(tier1, tier2, tier3) | Governance setter for freshness tiers (V7) |
setIntentMultipliers(forAgainst, abstain) | Governance setter for intent values (V7) |
setLevelToMultiplier(level, multiplier) | Queue multiplier change for next cycle |
setLevelToMultiplierNow(level, multiplier) | Apply multiplier immediately |
toggleQuadraticRewarding(cycle) | Enable/disable quadratic rewarding |
V7 storage: 5 Checkpoints.Trace208 for multiplier values (freshnessMultiplierTier1/2/3, intentMultiplierForAgainst, intentMultiplierAbstain), INavigatorRegistry navigatorRegistry.
V7 fee flow: Navigator fee deducted first from gross reward (citizens only, → NavigatorRegistry escrow), then relayer fee from remainder (auto-voters + citizens, → RelayerRewardsPool). CLAIM action registered for both.
| Role | Can |
|---|---|
VOTE_REGISTRAR_ROLE | Register votes |
DEFAULT_ADMIN_ROLE | Set multipliers, scaling |
GOVERNANCE_ROLE | Set freshness/intent multipliers (V7) |
Separate GM rewards pool (v5+). Relayer fee integration (v6). Navigator fees + multipliers (v7).
GalaxyMember (NFT)
ERC-721 with level progression, node attachment, and voting rewards multiplier.
| Function | Description |
|---|---|
freeMint() | Mint level 1 if user participated in governance |
upgrade(tokenId) | Advance level by paying B3TR |
select(tokenId) | Select token for voting rewards multiplier |
selectFor(address, tokenId) | Admin selects for user |
attachNode(tokenId, nodeId) | Attach Stargate NFT for bonus level |
detachNode(tokenId, nodeId) | Remove attached node |
setMaxLevel(level) | Set maximum upgrade level |
setB3TRtoUpgradeToLevel(costs) | Define B3TR cost per level |
| Role | Can |
|---|---|
MINTER_ROLE | Minting |
PAUSER_ROLE | Pause/unpause |
NODES_MANAGER_ROLE | Node settings |
V6 replaced node management with Stargate NFT integration.
Treasury
Manages DAO assets. Receives emissions + unallocated funds.
| Function | Description |
|---|---|
transferB3TR(to, amount) | Transfer B3TR |
transferVOT3(to, amount) | Transfer VOT3 |
transferVET(to, amount) | Transfer VET |
transferVTHO(to, amount) | Transfer VTHO |
transferTokens(token, to, amount) | Generic ERC-20 transfer (with limits) |
transferNFT(collection, to, tokenId) | ERC-721 transfer |
convertB3TR(amount) | B3TR → VOT3 |
convertVOT3(amount) | VOT3 → B3TR |
setTransferLimitVET(limit) | Set VET transfer cap |
setTransferLimitToken(token, limit) | Set per-token transfer cap |
All transfers require GOVERNANCE_ROLE and contract must be unpaused.
Transfer limits (per operation, governance-updatable): 200,000 VET, 200,000 B3TR, 3,000,000 VTHO, 50,000 VOT3. Cannot transfer non-native or non ERC-721/ERC-20 tokens.
TimeLock
Executes governance actions from B3TRGovernor with a mandatory time delay. B3TRGovernor should be the sole proposer and executor.
RelayerRewardsPool (V3)
Manages rewards for relayers performing auto-voting and navigator citizen voting. V3 added per-user skip tracking and governance action support.
| Function | Description |
|---|---|
claimRewards(roundId, relayer) | Claim earned rewards |
deposit(amount, roundId) | Fund the pool |
registerRelayerAction(relayer, voter, roundId, action) | Log vote/claim action |
calculateRelayerFee(totalReward) | Compute fee deduction |
setTotalActionsForRound(roundId, userCount) | Legacy: sets expected for auto-voting only |
setTotalActionsForRoundWithGovernance(roundId, allocationUsers, governanceUsers, activeProposalIds) | V3: sets expected actions with separate governance users. Caches activeProposalIds |
reduceExpectedActionsForRound(roundId, userCount) | Bulk reduction for ineligible auto-voting users |
reduceUserAllocationVote(roundId, user) | V3: per-user allocation skip. Auto-reduces claim if all votes skipped |
reduceUserGovernanceVote(roundId, user, proposalId) | V3: per-user/proposal governance skip. Auto-reduces claim if all votes skipped |
setVoteWeight() / setClaimWeight() | Adjust action weights |
setRelayerFeePercentage() / setFeeCap() | Configure fee structure |
setEarlyAccessBlocks() | Define early access window |
registerRelayer(relayer) / unregisterRelayer(relayer) | Manage relayer access |
V3 storage: activeProposalsForRound[roundId], userAllocationVoteReduced[roundId][user], userGovernanceVoteReduced[roundId][user][proposalId], userClaimReduced[roundId][user].
| Role | Can |
|---|---|
POOL_ADMIN_ROLE | Pool administration, relayer management |
NavigatorRegistry (V1)
UUPS upgradeable contract managing navigator registration, citizen delegation, voting preferences, fees, slashing, and lifecycle. Facade with 6 external libraries. Staked B3TR is converted to VOT3 under the hood and counts as the navigator's voting power (checkpointed via Checkpoints.Trace208). NavigatorRegistry self-delegates on VOT3 during initialization.
| Function | Description |
|---|---|
register(amount, metadataURI) | Register as navigator by staking B3TR (min 50K, converted to VOT3) |
addStake(amount) / reduceStake(amount) | Manage B3TR stake (B3TR↔VOT3 conversion) |
withdrawStake(amount) | Withdraw after exit/deactivation (VOT3→B3TR) |
delegate(navigator, amount) | Delegate VOT3 to navigator |
increaseDelegation(amount) | Add more VOT3 |
reduceDelegation(amount) / undelegate() | Reduce or remove delegation |
setAllocationPreferences(roundId, appIds, percentages) | Set allocation vote preferences (basis points, sum to 10000) |
setGovernanceDecision(proposalId, decision) | Set governance vote (1=Against, 2=For, 3=Abstain) |
submitReport(metadataURI) | Submit on-chain report for current round |
announceExit() | Start exit with 1-round notice |
reportRoundInfractions(navigator, roundId, proposalIds) | Report minor infractions for completed round |
claimFee(roundId) | Claim navigator fee after 4-round lock |
depositNavigatorFee(navigator, roundId, amount) | Called by VoterRewards to deposit citizen fee |
deactivateNavigator(navigator, slashPct, slashFees) | Governance action: deactivate + optional slash |
getTotalDelegatedCitizensAtTimepoint(timepoint) | Historical total citizen count |
getDelegatedAmountAtTimepoint(citizen, timepoint) | Historical delegation amount |
getStakedAmountAtTimepoint(navigator, timepoint) | Historical staked amount (used by VotesUtils/GovernorVotesLogic for voting power) |
Storage: Checkpoints.Trace208 totalDelegatedCitizens, mapping(address => Checkpoints.Trace208) stakedAmount (checkpointed for snapshot voting power), mapping(address => uint256) navigatorCitizenCount, fee escrow per navigator per round.
Libraries: NavigatorStakingUtils, NavigatorDelegationUtils, NavigatorVotingUtils, NavigatorFeeUtils, NavigatorSlashingUtils, NavigatorLifecycleUtils.
| Role | Can |
|---|---|
DEFAULT_ADMIN_ROLE | Configuration |
GOVERNANCE_ROLE | Deactivation, parameter changes |
GrantsManager
Milestone-based grant distribution.
| Function | Description |
|---|---|
createMilestones(proposalId, milestones) | Create milestones with IPFS metadata |
approveMilestones(proposalId) | Validate milestone completion |
rejectMilestones(proposalId) | Deny milestones |
claimMilestone(proposalId, milestoneIndex) | Distribute funds for approved milestone |
grantState(proposalId) | Returns: rejected / in development / completed |
| Role | Can |
|---|---|
GRANTS_APPROVER_ROLE | Approve milestones |
GRANTS_REJECTOR_ROLE | Reject milestones |
GOVERNANCE_ROLE | Protocol governance |
B3TRMultiSig
Multi-signature wallet requiring multiple owner confirmations (max 50 owners).
| Function | Description |
|---|---|
submitTransaction(to, value, data) | Create pending transaction |
confirmTransaction(txId) | Owner approves |
executeTransaction(txId) | Execute when threshold met |
revokeConfirmation(txId) | Withdraw approval |
addOwner(owner) / removeOwner(owner) | Manage owners |
changeRequirement(count) | Adjust confirmation threshold |
VeBetterPassport
Sybil resistance contract. Determines if a wallet is a real person based on participation score, blacklisting, GM holdings, and entity linking. Used by XAllocationVoting and B3TRGovernor for voter eligibility.
Core identity checks:
| Function | Description |
|---|---|
isPerson(user) | Returns (bool person, string reason) — checks score, blacklist, GM level |
isPersonAtTimepoint(user, timepoint) | Same check at a specific block |
isCheckEnabled(checkType) | Whether a specific check is active |
isWhitelisted(user) / isBlacklisted(user) | Direct status |
isPassportWhitelisted(passport) / isPassportBlacklisted(passport) | Checks linked entities too |
Participation scoring:
| Function | Description |
|---|---|
registerAction(user, appId) | Register sustainable action (called by apps) |
registerActionForRound(user, appId, round) | Register for specific round |
userRoundScore(user, round) | Score in a specific round |
userTotalScore(user) | Lifetime score |
userRoundScoreApp(user, round, appId) | Per-app per-round score |
getCumulativeScoreWithDecay(user, lastRound) | Decayed cumulative score: f(t) = a * (1-r)^t |
thresholdPoPScore() | Required score to be considered a person |
appSecurity(appId) | App security level: LOW / MEDIUM / HIGH |
securityMultiplier(security) | Score multiplier per security level |
Entity linking (link multiple wallets to one passport):
| Function | Description |
|---|---|
linkEntityToPassport(passport) | Request linking (entity calls) |
acceptEntityLink(entity) | Passport accepts link |
removeEntityLink(entity) | Remove link (either side) |
getPassportForEntity(entity) | Resolve entity → passport |
getEntitiesLinkedToPassport(passport) | All linked entities |
isEntity(user) / isPassport(user) | Check role |
maxEntitiesPerPassport() | Configurable cap |
Delegation (delegate personhood to another address):
| Function | Description |
|---|---|
delegatePassport(delegatee) | Request delegation |
acceptDelegation(delegator) | Accept delegation |
revokeDelegation() | Revoke (either side) |
getDelegatee(delegator) / getDelegator(delegatee) | Resolve |
Signaling (flag suspicious users):
| Function | Description |
|---|---|
signalUser(user) | Signal a user (DEFAULT_ADMIN_ROLE) |
signalUserWithReason(user, reason) | Signal with reason (SIGNALER_ROLE) |
resetUserSignalsWithReason(user, reason) | Reset signals (RESET_SIGNALER_ROLE) |
assignSignalerToApp(appId, user) | Assign app-specific signaler |
signaledCounter(user) | Times user was signaled |
signalingThreshold() | Threshold for auto-blacklist |
| Role | Can |
|---|---|
SETTINGS_MANAGER_ROLE | Configure thresholds, decay, security |
WHITELISTER_ROLE | Whitelist/blacklist users |
ACTION_REGISTRAR_ROLE | Register actions |
ACTION_SCORE_MANAGER_ROLE | Manage scoring |
SIGNALER_ROLE | Signal users with reason |
RESET_SIGNALER_ROLE | Reset user signals |
ROLE_GRANTER | Grant roles |
B3TRProxy
EIP-1967 upgradeable proxy. Delegates all calls to the current implementation address. Read implementation via storage slot 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc.
---
Contract Upgradeability
All upgradeable contracts use UUPS proxy pattern with ERC-7201 storage layout.
| Contract | Upgradeable | Authorizer |
|---|---|---|
| B3TR | No | -- |
| B3TRProxy | No | -- |
| B3TRMultiSig | No | -- |
| B3TRGovernor | Yes | Governance OR DEFAULT_ADMIN |
| Emissions | Yes | UPGRADER_ROLE |
| GalaxyMember | Yes | UPGRADER_ROLE |
| TimeLock | Yes | UPGRADER_ROLE |
| Treasury | Yes | UPGRADER_ROLE |
| VOT3 | Yes | UPGRADER_ROLE |
| VoterRewards | Yes | UPGRADER_ROLE |
| X2EarnApps | Yes | UPGRADER_ROLE |
| X2EarnCreator | Yes | UPGRADER_ROLE |
| X2EarnRewardsPool | Yes | UPGRADER_ROLE |
| XAllocationPool | Yes | UPGRADER_ROLE |
| XAllocationVoting | Yes | UPGRADER_ROLE |
| GrantsManager | Yes | UPGRADER_ROLE |
| DBAPool | Yes | UPGRADER_ROLE |
| RelayerRewardsPool | Yes | UPGRADER_ROLE |
| VeBetterPassport | Yes | UPGRADER_ROLE |
| NavigatorRegistry | Yes | UPGRADER_ROLE |
B3TRGovernor and NavigatorRegistry store logic in external libraries. To upgrade library logic: deploy new library → deploy new implementation linking the library → upgradeToAndCall.
VeBetterDAO Contracts — Tokens & X2Earn Apps
When to use
Use when the user asks about: B3TR, VOT3, Emissions, XAllocationVoting, XAllocationPool, X2EarnRewardsPool, X2EarnApps, X2EarnCreator, DBAPool, token minting, voting rounds, app submission, endorsement, reward distribution, or impact tracking.
Full source: github.com/vechain/vebetterdao-contracts Auto-generated docs: vechain.github.io/vebetterdao-contracts
---
Contract Map
Emissions ──distribute()──> XAllocationPool + VoterRewards + Treasury + GalaxyMember
│ │
claim() │ registerVote()│ claimReward()
▼ │ ▼
X2EarnRewardsPool │ VoterRewards
│ │ │
distributeReward() │ claimReward()
▼ │ ▼
Users (B3TR) │ Voters (B3TR)
│
XAllocationVoting ◄── VOT3 holders vote
│
B3TRGovernor ──queue()──> TimeLock ──execute()──> TreasuryAll upgradeable contracts use UUPS proxy pattern with ERC-7201 storage layout.
---
B3TR (ERC-20 Token)
Capped ERC-20 token. 1B total supply over 12 years.
| Role | Can |
|---|---|
MINTER_ROLE | mint(address, amount) — respects supply cap |
| Admin | pause() / unpause() — halts all transfers |
Key function: tokenDetails() — returns name, symbol, decimals, totalSupply, cap in one call.
VOT3 (Governance Token, V2)
ERC-20 with voting power. Obtained by converting B3TR 1:1. V2 added NavigatorRegistry integration for delegation lock.
| Function | Description |
|---|---|
convertToVOT3(amount) | Swap B3TR → VOT3 |
convertToB3TR(amount) | Burn VOT3 → get B3TR back (only self-converted amount, not VOT3 received from others). Blocked for delegated amount |
delegate(delegatee) | Delegate voting power (auto-delegates on first receive) |
getQuadraticVotingPower(account) | Square root of token balance |
getPastQuadraticVotingPower(account, timepoint) | Historical voting power |
getNavigatorLockedAmount(address) | V2: reads delegation amount from NavigatorRegistry |
unlockedBalance(address) | V2: returns balance - navigatorLockedAmount (transferable amount) |
V2 delegation lock: _update() enforces balanceOf(from) - amount >= NavigatorRegistry.getDelegatedAmount(from). VOT3 stores only the registry address — no mapping, no role grant. balanceOf() returns full balance including delegated.
Roles: UPGRADER_ROLE, PAUSER_ROLE.
Emissions
Manages periodic B3TR distribution across XAllocations, Vote2Earn, Treasury, and GM pool with cycle-based decay.
| Function | Description |
|---|---|
distribute() | Distributes tokens for current cycle |
getCurrentCycle() | Current cycle number |
getXAllocationAmount(cycle) | XAllocation amount for cycle |
getVote2EarnAmount(cycle) | Vote2Earn amount for cycle |
isCycleDistributed(cycle) | Whether cycle was distributed |
setCycleDuration() | Set cycle length |
setXAllocationsDecay() / setVote2EarnDecay() | Configure decay rates |
setTreasuryPercentage() / setGmPercentage() | Adjust allocation splits |
| Role | Can |
|---|---|
MINTER_ROLE | Initiate distributions |
DECAY_SETTINGS_MANAGER_ROLE | Modify decay parameters |
CONTRACTS_ADDRESS_MANAGER_ROLE | Update external addresses |
XAllocationVoting (V9)
Periodic voting rounds for allocating funds to X2Earn apps. Uses quadratic funding with VOT3 voting power at round start. V9 added navigator citizen voting, freshness multiplier, and external library architecture.
| Function | Description |
|---|---|
startNewRound() | Initiate new allocation round. Computes allocationUsers (auto-voting + citizens) and governanceUsers (citizens only), fetches active proposals, passes to RelayerRewardsPool |
castVote(roundId, appIds, voteWeights) | Vote on apps (weights must exceed threshold). Reverts with DelegatedToNavigator for delegated citizens |
castVoteOnBehalfOf(voter, roundId) | Relayer executes auto-vote for user |
castNavigatorVote(citizen, roundId) | V9: vote-or-skip for navigator-delegated citizens using navigator's custom percentages. Skip window: 720 blocks before deadline |
toggleAutoVoting(address) | Enable/disable auto-voting. Reverts for navigators (NavigatorCannotEnableAutoVoting) and delegated citizens (DelegatedToNavigator) |
disableAutoVotingFor(address) | V9: privileged, called by NavigatorRegistry on delegation |
setUserVotingPreferences(appIds) | Store preferred app IDs for auto-voting |
hasUserVotedForApp(roundId, user, appId) | V9: check if user voted for specific app |
setVotingPeriod() | Configure round duration |
setAppSharesCap() | Max % any single app can receive |
setBaseAllocationPercentage() | Minimum base allocation % |
updateQuorumNumerator() | Adjust quorum threshold |
V9 freshness: countVote() computes XOR fingerprint of voted app IDs via FreshnessUtils, applies freshness multiplier from VoterRewards checkpoints to reward weight (not voting power).
V9 events: NavigatorVoteSkipped(citizen, navigator, roundId), FreshnessMultiplierApplied.
| Role | Can |
|---|---|
ROUND_STARTER_ROLE | Start new rounds |
GOVERNANCE_ROLE | Governance operations |
Integrates with: X2EarnApps, VoterRewards, Emissions, VeBetterPassport, NavigatorRegistry, B3TRGovernor, RelayerRewardsPool.
XAllocationPool
Distributes weekly B3TR emissions to X2Earn apps based on voting results. Apps claim at round end.
| Function | Description |
|---|---|
claim(roundId, appId) | App claims earned B3TR for a round |
claimableAmount(roundId, appId) | Returns allocation breakdown (total, unallocated, team, user pool) |
roundEarnings(roundId, appId) | Calculates allocations from base + variable with per-app caps |
getAppShares(roundId, appId) | Voting percentage (capped) |
toggleQuadraticFunding() | Enable/disable quadratic funding for next round |
Unallocated amounts (apps that didn't claim, rounding remainders) are sent to Treasury.
X2EarnRewardsPool
Reward pool for X2Earn apps to distribute B3TR to users for sustainable actions.
| Function | Description |
|---|---|
deposit(amount, appId) | Fund rewards pool for an app |
withdraw(amount, appId, reason) | Admin withdrawal to team wallet |
distributeReward(appId, amount, receiver) | Basic reward distribution |
distributeRewardWithProof(appId, amount, receiver, proofTypes, proofValues, impactCodes, impactValues, description) | Distribution with impact tracking |
distributeRewardWithProofAndMetadata(...) | Distribution with additional JSON metadata |
distributeRewardForRound(appId, amount, receiver, proof, actionRound) | Basic distribution attributed to a specific round |
distributeRewardWithProofForRound(..., actionRound) | Distribution with proof attributed to a specific round |
distributeRewardWithProofAndMetadataForRound(..., actionRound) | Distribution with proof + metadata attributed to a specific round |
toggleRewardsPoolBalance(appId, enable) | Enable/disable rewards pool for app |
pauseDistribution() / unpauseDistribution() | Admin pause |
addImpactKey() / removeImpactKey() | Manage allowed impact categories |
| Role | Can |
|---|---|
IMPACT_KEY_MANAGER_ROLE | Manage impact keys |
CONTRACTS_ADDRESS_MANAGER_ROLE | Configuration |
Storage maps app IDs to: available funds, rewards pool balances, enabled status, pause state.
X2EarnApps
Manages X2Earn application lifecycle: submission, endorsement, eligibility, admins/moderators/creators, reward distributors, and metadata.
App submission & management:
| Function | Description |
|---|---|
submitApp(teamWallet, admin, appName, metadataURI) | Submit new app (one per creator NFT holder) |
hashAppName(appName) | Get app ID from name |
app(appId) / apps() | Get app details |
allEligibleApps() | All apps eligible for voting |
setVotingEligibility(appId, bool) | Toggle voting eligibility |
setAppAdmin(appId, newAdmin) | Change app admin |
updateTeamWalletAddress(appId, addr) | Update team wallet |
setTeamAllocationPercentage(appId, pct) | Set team allocation % |
updateAppMetadata(appId, metadataURI) | Update IPFS metadata |
addAppModerator() / removeAppModerator() | Manage moderators (max MAX_MODERATORS) |
addRewardDistributor() / removeRewardDistributor() | Manage reward distributors (max MAX_REWARD_DISTRIBUTORS) |
addCreator() / removeAppCreator() | Manage creators (max MAX_CREATORS) |
removeXAppSubmission(appId) | Remove app submission (admin) |
Endorsement system (V8 — flexible, partial points):
| Function | Description |
|---|---|
endorseApp(appId, nodeId, points) | Endorse with Stargate node (max 49 pts per app per node, 110 total per app) |
unendorseApp(appId, nodeId, points) | Remove endorsement points (0 = remove all) |
checkEndorsement(appId) | Check if threshold met |
getScore(appId) / getScoreAtTimepoint(appId, block) | Current / historical endorsement score |
getEndorsers(appId) / getEndorserNodes(appId) | List endorsers |
getNodeAvailablePoints(nodeId) | Remaining points for a node |
getNodeActiveEndorsements(nodeId) | All active endorsements for a node |
canUnendorse(nodeId, appId) | Check cooldown |
endorsementScoreThreshold() | Required score (default 100) |
maxPointsPerNodePerApp() / maxPointsPerApp() | Configurable caps |
Query helpers: isEligible(appId, timepoint), isEligibleNow(appId), isBlacklisted(appId), isAppUnendorsed(appId), isAppAdmin(appId, addr), isAppModerator(appId, addr), isRewardDistributor(appId, addr), isCreatorOfAnyApp(addr), gracePeriod(), cooldownPeriod().
| Role | Can |
|---|---|
GOVERNANCE_ROLE | Manage settings, eligibility, endorsement config |
MIGRATION_ROLE | Seed endorsements during migration |
UPGRADER_ROLE | Upgrade contract |
Limits: MAX_MODERATORS, MAX_REWARD_DISTRIBUTORS, MAX_CREATORS per app.
X2EarnCreator (NFT)
Non-transferable ERC-721 for VeBetterDAO creators. One per address.
| Function | Description |
|---|---|
safeMint(address) | Mint to recipient (MINTER_ROLE) |
selfMint() | Self-mint when enabled |
burn(tokenId) | Remove token (BURNER_ROLE) |
Blocks all transfers (transferFrom reverts). Roles: MINTER_ROLE, BURNER_ROLE, PAUSER_ROLE.
DBAPool (Dynamic Base Allocation)
Distributes surplus B3TR from XAllocationPool to eligible apps using merit-capped flat distribution.
| Function | Description |
|---|---|
distributeDBARewards(roundId, appIds) | Split pool evenly across apps; cap at 2x vote allocation; overflow to treasury |
dbaRoundRewardsForApp(roundId, appId) | Reward amount for app/round |
canDistributeDBARewards(roundId) | Check distribution eligibility |
Role: DISTRIBUTOR_ROLE.
Governance (VeVote & VeBetterDAO)
When to use
Use when the user asks about: voting, proposals, steering committee elections, VOT3 governance, on-chain voting mechanisms.
Two Governance Systems
| System | Platform | Voting Asset | Purpose |
|---|---|---|---|
| VeVote | vevote.vechain.org | Stargate NFTs | Protocol upgrades, steering committee elections, network parameters |
| VeBetterDAO Governor | VeBetterDAO dApp | VOT3 token | dApp allocation rounds, ecosystem fund distribution, DAO proposals |
---
VeVote (Protocol Governance)
On-chain governance platform where Validators and Node holders vote on proposals. All votes are recorded on-chain (tamper-proof, publicly verifiable).
Proposal Types
- Steering Committee Voting -- Election of the Board of Steering Committee
- All Stakeholders Voting -- Protocol changes (e.g., VIP-253 Hayabusa upgrade)
Voting Power
Weighted by Stargate NFT tier level (highest to lowest):
Mjolnir X → Thunder X → Strength X → VeThor X → Mjolnir → Thunder → Strength → Flash → Lightning → Dawn
Voting units in the contract are scaled by 100 to avoid underflow (e.g., 150 = 1.5x).
Voting Rules
- Total voting power applied to the option you select
- One vote per wallet per proposal, cannot be changed
- Options: For, Against, Abstain
- Power calculated at the moment of vote (not at proposal start)
Delegation
Via Stargate NFT Node Manager feature: an NFT owner assigns a secondary wallet that gains full voting power for managed NFT(s).
Contract Address
| Contract | Network | Address |
|---|---|---|
| Steering Committee Vote | Mainnet | 0xDBAeC4165A6cff07901C41D3561EEFdCFbc20CB6 |
Developer Resources
- Monorepo: github.com/vechain/vevote --
packages/contracts/+apps/frontend/ - Legacy contracts: github.com/vechain/vevote-contracts
- Stack: Solidity + Hardhat (contracts), React + Vite (frontend), VeChain Kit (wallet)
---
VeBetterDAO Governance
Uses OpenZeppelin Governor pattern (AccessControl + UUPSUpgradeable).
Voting Token: VOT3
- Obtained by swapping B3TR at 1:1 ratio (auto-delegates to holder on receipt)
- Minimum 1 VOT3 to participate in governance
- See vebetterdao.md for B3TR/VOT3 token details and contract addresses
Proposal Requirements
- Must hold a GM Moon NFT (level 2+)
- Must create a Discourse thread at least 3 days before submitting
Proposal Types
- Actionable: triggers on-chain action (treasury transfer, contract call)
- Non-Actionable: expresses direction/idea without immediate on-chain execution
Governance Proposals
1. Proposer creates proposal with VOT3 deposit (V11 propose takes 7 args incl. maxBudget for the optional B3TR implementation cost; pass 0 to skip the community-execution flow) 2. Deposit threshold: 2% of total B3TR supply must be deposited in VOT3 → temperature check (capped at 5M VOT3) 3. If threshold reached before waiting period ends → proposal becomes active 4. Voting period opens; quorum: 30% of total VOT3 supply (FOR + AGAINST + ABSTAIN all count) 5. If quorum met and "yes" > "no" → queued to TimeLock → executed after delay 6. After Executed (or Succeeded for non-actionable) → V11 Community Execution flow takes over (see section below)
Deposits count as allocation voting power: locked VOT3 deposits are included in the XAllocation snapshot and grant voting power in allocation rounds even while locked.
Community Execution Framework (V11)
Standard proposals with maxBudget > 0 carry an on-chain B3TR implementation cost that is paid out after delivery. Grants are NOT in this flow — they use milestone payouts via proposeGrant.
Lifecycle (V11 states):
Pending → Active → Succeeded → Queued → Executed → InDevelopment → Completed → (Paid)
↘ Defeated / DepositNotMet / CanceledKey entrypoints on `B3TRGovernor` v11:
| Function | Caller | Purpose |
|---|---|---|
propose(targets, values, calldatas, description, startRoundId, depositAmount, maxBudget) | Anyone meeting standard requirements | Lock the implementation cost at creation. maxBudget = 0 disables the community-execution flow. |
markAsInDevelopment(proposalId, payee, description, implementationDiscussion, contributors[]) | Proposer or PROPOSAL_STATE_MANAGER_ROLE | One-shot. Registers the single payout address + metadata. Requires Executed (or Succeeded if non-executable). When maxBudget > 0, payee must be non-zero; when maxBudget == 0, payee must be zero. |
updateCommunityExecution(proposalId, payee, description, implementationDiscussion, contributors[]) | Proposer or PROPOSAL_STATE_MANAGER_ROLE | Replace any field while proposal is InDevelopment or Completed AND claimPayout not yet called. |
markAsCompleted(proposalId) | PROPOSAL_STATE_MANAGER_ROLE only | Flip dev state to Completed once delivery is verified. |
claimPayout(proposalId) | Anyone (idempotent) | Pulls the full maxBudget from Treasury to the registered payee in a single B3TR transfer. Requires Completed. |
resetDevelopmentState(proposalId) | PROPOSAL_STATE_MANAGER_ROLE only | Admin escape hatch. |
Funds flow: maxBudget is a commitment, not an escrow. B3TR stays in Treasury until claimPayout, which calls Treasury.transferB3TR(payee, maxBudget). The Governor must hold Treasury.GOVERNANCE_ROLE (granted as part of the V11 upgrade).
Contributors: contributors[] is an on-chain string array (GitHub/X handles or URLs) for attribution only, capped at maxContributorsPerProposal (currently 20). The single payee receives the full budget — distribution to contributors happens off-chain.
Events: ProposalBudgetSet, ProposalInDevelopment, ProposalInDevelopmentDetails, ProposalContributorsSet, ProposalCompleted, ProposalPayoutClaimed, ProposalDevelopmentStateReset.
Key errors: InvalidPayeeAddress, MissingProposalBudget, TooManyContributors, PayeesAlreadyFinalized, PayoutAlreadyClaimed, NotReadyToClaim, UnauthorizedCommunityExecution.
Allocation Rounds
- Weekly rounds where VOT3 holders vote on X2Earn app funding
- 100% vote-based allocation (no base allocation; base allocation % = 0 since Jan 2025)
- Allocation cap: 20% per app (ensures at least 6 apps participate)
- Quadratic Funding formula: allocation proportional to
(sum of sqrt(votes))^2, emphasizing number of distinct supporters over vote size. Admins can disable QF (switches to linear; takes effect next round) - Quorum: 1% of total VOT3 supply. If not met, distribution still occurs using last valid round's vote percentages. New apps in a failed round only receive base allocation (currently 0%)
- Snapshot: VOT3 holdings and completed actions are snapshotted at round start; changes after that don't count
- Voting: one vote per user per round; can split across multiple apps (e.g., 30 VOT3 to app A, 70 to app B)
- Distribution trigger:
claim()is public — anyone can call it. VeBetterDAO team runs a scheduler to trigger at each new round - Unallocated/unclaimed funds go to Treasury
Vote Delegation
- Auto-delegation enabled: converting B3TR → VOT3 or receiving VOT3 auto-delegates to your address
- Important for smart contracts: auto-delegation does NOT work for contracts; if a contract receives VOT3 and wants to participate in governance, it must call
delegate()manually (one-time)
Voter Rewards
- Vote2Earn Pool: Rewards all participants proportionally to VOT3 balance (linear since round 23; quadratic rewarding disabled)
- GM Rewards Pool: 5% of weekly emissions → voters with GM NFT (Moon level 2+), weighted by GM NFT reward weight
- Participation in both governance proposals and XAllocation votes counts for rewards
GM NFT Levels
| Level | Name | B3TR to Upgrade | Reward Weight |
|---|---|---|---|
| 1 | Earth | Free (requires governance participation) | -- |
| 2 | Moon | 5,000 | 1.1 |
| 3 | Mercury | 12,500 | 1.2 |
| 4 | Venus | 25,000 | 1.5 |
| 5 | Mars | 50,000 | 2 |
| 6 | Jupiter | 125,000 | 2.5 |
| 7 | Saturn | 250,000 | 3 |
| 8 | Uranus | 1,250,000 | 5 |
| 9 | Neptune | 2,500,000 | 10 |
| 10 | Galaxy | 12,500,000 | 25 |
Upgradeable Governance Parameters
- Voting Period: must equal or be shorter than Emissions cycle
- Quorum: 30% of total VOT3 supply
- Deposit Threshold: 2% of total B3TR supply (in VOT3), capped at 5M VOT3
- Voting Threshold: minimum 1 VOT3 to vote
- Minimum Voting Delay: 3 days (PENDING → active)
- Timelock Minimum Delay: wait time before execution after queuing
- Function Restrictions: can enable/disable whitelist of callable contract functions
- Allocation Cap: 20% max per app
- Base Allocation %: 0% (currently all vote-based)
- `maxContributorsPerProposal` (V11): cap on V11 contributors array — currently 20, set at V11 upgrade, no runtime setter (changing requires a Governor upgrade)
---
VePassport (Voting Eligibility)
Verifies wallet authenticity for VeBetterDAO allocation round voting. Requires 3 sustainable actions in the last 12 rounds.
| Contract | Network | Address |
|---|---|---|
| VePassport | Mainnet | 0x35a267671d8EDD607B2056A9a13E7ba7CF53c8b3 |
Navigators (Delegation & Multipliers)
When to use
Use when the user asks about: navigators, delegation, navigator staking, freshness multiplier, governance intent multiplier, navigator fees, slashing, NavigatorRegistry, or professional voting delegates.
For full implementation detail, use the dedicated vebetterdao-navigators skill.
Overview
Navigators are professional voting delegates who stake B3TR to vote on behalf of citizens in both allocation rounds and governance proposals. The feature ships in two phases (released together):
1. Rewards Multipliers — freshness (allocation) + governance intent multipliers that adjust reward weight 2. Navigator Delegation System — staking, delegation, voting, fees, slashing, lifecycle
Rewards Multipliers
Multipliers adjust reward weight only — on-chain voting power is never modified. Scale: basis points (10000 = 1x). Stored as Checkpoints.Trace208 in VoterRewards.
Freshness Multiplier (Allocation Voting)
Applied in RoundVotesCountingUtils.countVote() via FreshnessUtils library. XOR fingerprint of voted app IDs detects changes.
| Behavior | Multiplier |
|---|---|
| Updated this round | x3 (30000 bp) |
| Updated within 2 rounds | x2 (20000 bp) |
| No update >= 3 rounds | x1 (10000 bp) |
First-time voters get x3. Citizens inherit navigator's freshness.
Governance Intent Multiplier (Proposal Voting)
Applied in GovernorVotesLogic before registerVote(). Per-proposal, independent.
| Vote Type | Multiplier |
|---|---|
| For / Against | x1 (10000 bp) |
| Abstain | x0.30 (3000 bp) |
Citizens inherit navigator's decision multiplier. Freshness scales allocation reward weight; intent scales governance reward weight. GM is not stacked with them — when the GM pool is funded (v5+ live config), GM accumulates its own separate per-voter weight claimed against the GM pool, independent of allocation/governance reward weight.
Navigator System
Registration & Staking
- Permissionless — stake minimum 50,000 B3TR in NavigatorRegistry
- Staked B3TR is converted to VOT3 under the hood — counts as navigator's voting power (checkpointed)
- NavigatorRegistry self-delegates on VOT3 during initialization; per-navigator amounts queried via
getStakedAmountAtTimepoint - 10:1 delegation ratio: stake >= 10% of total delegated VOT3
- Max stake: 1% of circulating VOT3 (enforced at deposit only)
- On slash/withdraw: VOT3 converted back to B3TR before transfer
- On-chain reports mandatory at least once every 2 rounds
Delegation
- Citizens delegate specific VOT3 amount (not full balance) — stays in wallet, but locked
- VOT3 reads lock from NavigatorRegistry (
getDelegatedAmount) — no mapping on VOT3 - One navigator per citizen, snapshotted at round start
- Partial undelegation allowed (takes effect next round)
- No personhood check to delegate. Personhood validated at vote time (snapshot); non-person citizens are skipped
- Citizens can't vote manually while delegated
- Auto-voting disabled on delegation
| Function | Purpose |
|---|---|
delegate(navigator, amount) | First-time delegation |
increaseDelegation(amount) | Add more VOT3 |
reduceDelegation(amount) | Partial or full reduction |
undelegate() | Full removal |
Voting
- Allocation:
XAllocationVoting.castNavigatorVote(citizen, roundId)— navigator's custom percentages (basis points, sum to 10000) - Governance:
B3TRGovernor.castNavigatorVote(proposalId, citizen)— navigator's decision (For/Against/Abstain) - Voting power = delegated amount at snapshot (checkpointed), not full balance
- Navigator setting preferences/decisions = their own vote (personal VOT3 + staked B3TR converted to VOT3)
Rewards & Fees
1. Navigator fee = gross * navigatorFeePercentage / 10000 (→ NavigatorRegistry escrow)
2. Relayer fee = calculated on remainder (→ RelayerRewardsPool)
3. Citizen receives the rest- Citizen's own GM level applies. Relayer fee applies to both auto-voters and citizens
- Fee escrow: 4-round rolling unlock in NavigatorRegistry
Slashing
- Minor: 5% of current remaining stake (compounding), reportable by anyone via
reportRoundInfractions(navigator, roundId, proposalIds)after round ends - Six infractions: missed allocation vote, missed governance vote, stale preferences (>= 3 rounds), missed report, late preferences, below minimum stake
- Infractions 1-5 require delegations at round snapshot; infraction 6 (below min stake) applies regardless of delegations
- Below min stake uses two-checkpoint check: below at round start AND still below at round end — gives navigator one full round to recover
- At most one minor slash per round
- Major: governance process, up to 100% of stake + locked fees + removal
Lifecycle
- Exit:
announceExit()— 1 round notice, self-enforcing via checkpoint timing (nofinalizeExit) - Deactivation: governance proposal with slash amount
- Both trigger lazy invalidation — citizen delegations void at view level, VOT3 auto-unlocked
Relayer Integration
- Citizens ARE counted in expected actions:
allocationUsers = autoVoting + citizens,governanceUsers = citizens only castNavigatorVoteincludes skip-or-vote logic with 720-block skip window (skips for: citizen not a person at snapshot, navigator dead now, no preferences/decision at skip window)- Per-user skip tracking in RelayerRewardsPool V3 (
reduceUserAllocationVote,reduceUserGovernanceVote) - Governance votes registered as
RelayerAction.VOTE— relayers earn credit
Contract: NavigatorRegistry
UUPS upgradeable facade with 6 external libraries: NavigatorStakingUtils, NavigatorDelegationUtils, NavigatorVotingUtils, NavigatorFeeUtils, NavigatorSlashingUtils, NavigatorLifecycleUtils.
Key storage:
Checkpoints.Trace208 totalDelegatedCitizens— global citizen count (used by XAllocationVoting.startNewRound)mapping(address => uint256) navigatorCitizenCount— per-navigator countmapping(navigator => mapping(round => amount))fee escrow
Key functions: delegate, increaseDelegation, reduceDelegation, undelegate, register, addStake, reduceStake, withdrawStake, setAllocationPreferences, setGovernanceDecision, submitReport, announceExit, reportRoundInfractions, claimFee, depositNavigatorFee.
Modified Contracts
| Contract | Version | Navigator changes |
|---|---|---|
| VOT3 | V2 | Reads delegation lock from NavigatorRegistry, unlockedBalance() |
| XAllocationVoting | V9 | castNavigatorVote, disableAutoVotingFor, startNewRound with citizens + governance |
| B3TRGovernor | V10 | castNavigatorVote, getActiveProposals, proposalsForRound, relayerRewardsPool |
| VoterRewards | V7 | Multiplier checkpoints, navigator fee deduction, intent multiplier |
| RelayerRewardsPool | V3 | Per-user skip tracking, setTotalActionsForRoundWithGovernance, activeProposalsForRound |
VeBetterDAO (X2Earn Sustainability Apps)
When to use
Use when the user asks about:
- Building X2Earn or sustainability-rewarding apps
- Distributing B3TR token rewards to users
- VeBetterDAO allocation rounds and voting
- Submitting an app to VeBetterDAO
- B3TR / VOT3 tokens
- Sustainability proofs and impact tracking
What is VeBetterDAO?
VeBetterDAO is a DAO on VeChainThor that incentivizes sustainable behavior through token rewards. Developers build X2Earn apps (sustainability-focused applications) that reward users with B3TR tokens for performing verifiable sustainable actions -- recycling, reducing carbon footprints, buying sustainable goods, etc.
The community governs fund allocation through weekly allocation rounds where VOT3 holders vote on which apps receive funding, using a quadratic funding formula.
Core Tokens
| Token | Purpose |
|---|---|
| B3TR | Incentive token. Total supply: 1B over 12 years. Earned by users for sustainable actions |
| VOT3 | Governance token. Obtained by swapping B3TR 1:1. Used to vote on allocation rounds. Restriction: you can only convert back to B3TR the amount you originally converted — VOT3 received from other wallets cannot be converted |
Architecture Overview
B3TR Token Emissions (weekly, 12-year schedule)
|
v
+-----+------+--------+
| | |
v v v
XAllocation Vote2Earn Treasury
Pool Pool
|
v
XAllocationVoting (Quadratic Funding, VOT3-weighted)
|
v
Per-App Allocation (base + variable based on votes)
|
v
X2EarnRewardsPool (apps distribute to users)
|
v
Users receive B3TR for sustainable actionsThree Integration Patterns
Pattern 1: Smart Contracts Only
All reward validation and distribution logic on-chain via a custom Solidity contract that calls X2EarnRewardsPool.
Pattern 2: Smart Contracts + Backend
Validation logic in a backend, distribution triggered through a smart contract.
Pattern 3: Backend Only (most web2-friendly)
All logic in a traditional backend using @vechain/sdk-network to interact with X2EarnRewardsPool directly. No custom smart contract deployment needed.
Reward Distribution
Solidity: Basic Reward Distributor
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IX2EarnRewardsPool {
function distributeReward(
bytes32 appId,
uint256 amount,
address receiver,
string memory proof
) external;
function distributeRewardWithProof(
bytes32 appId,
uint256 amount,
address receiver,
string[] memory proofTypes,
string[] memory proofValues,
string[] memory impactCodes,
uint256[] memory impactValues,
string memory description
) external;
}
contract MyRewardDistributor {
IX2EarnRewardsPool public x2EarnRewardsPool;
bytes32 public APP_ID;
constructor(address _x2EarnRewardsPool, bytes32 _appId) {
x2EarnRewardsPool = IX2EarnRewardsPool(_x2EarnRewardsPool);
APP_ID = _appId;
}
function rewardUser(address receiver, uint256 rewardAmount) external {
x2EarnRewardsPool.distributeReward(APP_ID, rewardAmount, receiver, "");
}
function rewardUserWithProof(
address receiver,
uint256 rewardAmount,
string[] memory proofTypes,
string[] memory proofValues,
string[] memory impactCodes,
uint256[] memory impactValues,
string memory description
) external {
x2EarnRewardsPool.distributeRewardWithProof(
APP_ID, rewardAmount, receiver,
proofTypes, proofValues, impactCodes, impactValues, description
);
}
}Important: The deployed contract address must be registered as a "Reward Distributor" for your app via the VeBetterDAO governance dApp.
JavaScript: Backend Reward Distribution
import {
ProviderInternalHDWallet,
ThorClient,
VeChainProvider,
} from "@vechain/sdk-network";
const thorClient = ThorClient.at("https://testnet.vechain.org");
const wallet = new ProviderInternalHDWallet(
mnemonic.split(" "),
1, 0, true // testnet
);
const provider = new VeChainProvider(thorClient, wallet);
const signer = await provider.getSigner();
// Load X2EarnRewardsPool contract
const rewardsPool = thorClient.contracts.load(
X2_EARN_REWARDS_POOL_ADDRESS,
x2EarnRewardsPoolABI,
signer
);
// Distribute reward without proofs
await rewardsPool.transact.distributeReward(
APP_ID,
ethers.parseEther("10"), // 10 B3TR
receiverAddress,
""
);
// Distribute reward with sustainability proofs
await rewardsPool.transact.distributeRewardWithProof(
APP_ID,
ethers.parseEther("10"),
receiverAddress,
["link", "photo"], // proof types
["https://proof.url", "ipfs://..."], // proof values
["waste_mass", "carbon"], // impact codes
[100, 50], // impact values
"Recycled 100g of plastic waste"
);Batch Distribution with Multi-Clause
import { ABIContract } from '@vechain/sdk-core';
const clauses = users.map(user => ({
to: X2_EARN_REWARDS_POOL_ADDRESS,
value: '0x0',
data: ABIContract.encodeFunctionInput(
x2EarnRewardsPoolABI,
'distributeReward',
[APP_ID, ethers.parseEther(user.amount), user.address, ""]
),
}));
// Send as multi-clause transactionSustainability Proofs and Impact
Available Proof Types
link, photo, video, text
Available Impact Codes
carbon, water, energy, waste_mass, education_time, timber, plastic, trees_planted, calories_burned, sleep_quality_percentage, clean_energy_production_wh
Mandatory rule: At least proof OR impact must be provided when using distributeRewardWithProof; if neither is provided, the transaction reverts.
Distribution with Metadata
x2EarnRewardsPool.distributeRewardWithProofAndMetadata(
appId, amount, receiver,
proofTypes, proofValues,
impactCodes, impactValues,
description,
jsonMetadata // JSON string with location, referral, campaign info
)Submitting an App to VeBetterDAO
1. Acquire a Creator NFT: Fill out a form on the VeBetter platform for a background check, or apply for a VeChain Grant (receive funding + Creator NFT). 2. On-Chain Submission: Submit the app on-chain for endorsement consideration. 3. Get Endorsed: Connect with VeChain node holders via the VeBetter XApps Creators Discord. Need a cumulative endorsement score of 100 (a single MjolnirX node = 100 points, Strength node = 2 points). 4. Enter Allocation Rounds: Once endorsed to 100, the app is eligible for weekly B3TR funding.
Contract Addresses
Mainnet
| Contract | Address |
|---|---|
| B3TR | 0x5ef79995FE8a89e0812330E4378eB2660ceDe699 |
| VOT3 | 0x76Ca782B59C74d088C7D2Cce2f211BC00836c602 |
| B3TRGovernor | 0x1c65C25fABe2fc1bCb82f253fA0C916a322f777C |
| Emissions | 0xDf94739bd169C84fe6478D8420Bb807F1f47b135 |
| GalaxyMember | 0x93B8cD34A7Fc4f53271b9011161F7A2B5fEA9D1F |
| TimeLock | 0x7B7EaF620d88E38782c6491D7Ce0B8D8cF3227e4 |
| Treasury | 0xD5903BCc66e439c753e525F8AF2FeC7be2429593 |
| VoterRewards | 0x838A33AF756a6366f93e201423E1425f67eC0Fa7 |
| X2EarnApps | 0x8392B7CCc763dB03b47afcD8E8f5e24F9cf0554D |
| X2EarnRewardsPool | 0x6Bee7DDab6c99d5B2Af0554EaEA484CE18F52631 |
| XAllocationPool | 0x4191776F05f4bE4848d3f4d587345078B439C7d3 |
| XAllocationVoting | 0x89A00Bb0947a30FF95BEeF77a66AEdE3842Fe5B7 |
| VeBetterPassport | 0x35a267671d8EDD607B2056A9a13E7ba7CF53c8b3 |
| X2EarnCreator | 0xe8e96a768ffd00417d4bd985bec9EcfC6F732a7f |
| NodeManagement | 0xB0EF9D89C6b49CbA6BBF86Bf2FDf0Eee4968c6AB |
| GrantsManager | 0x055d20914657834c914d7c44bf65b566ab4b45a2 |
| DBAPool | 0x98c1d097c39969bb5de754266f60d22bd105b368 |
| RelayerRewardsPool | 0x34b56f892c9e977b9ba2e43ba64c27d368ab3c86 |
Testnet
| Contract | Address |
|---|---|
| B3TR | 0x95761346d18244bb91664181bf91193376197088 |
| X2EarnApps | 0x0b54a094b877a25bdc95b4431eaa1e2206b1ddfe |
| X2EarnRewardsPool | 0x2d2a2207c68a46fc79325d7718e639d1047b0d8b |
| XAllocationPool | 0x6f7b4bc19b4dc99005b473b9c45ce2815bbe7533 |
| XAllocationVoting | 0x8800592c463f0b21ae08732559ee8e146db1d7b2 |
| B3TRGovernor | 0xc30b4d0837f7e3706749655d8bde0c0f265dd81b |
| VOT3 | 0x6e8b4a88d37897fc11f6ba12c805695f1c41f40e |
| Emissions | 0x66898f98409db20ed6a1bf0021334b7897eb0688 |
| GalaxyMember | 0x38a59fa7fd7039884465a0ff285b8c4b6fe394ca |
| Treasury | 0x3d531a80c05099c71b02585031f86a2988e0caca |
| TimeLock | 0x835509222aa67c333a1cbf29bd341e014aba86c9 |
| VoterRewards | 0x851ef91801899a4e7e4a3174a9300b3e20c957e8 |
Developer Resources
- X-App-Template: github.com/vechain/x-app-template -- Demo sustainability app with mocked contracts
- VeBetterDAO Contracts: github.com/vechain/vebetterdao-contracts -- Full smart contract source for ABI/TypeChain generation
- Test Environment: staging.testnet.governance.vebetterdao.org -- Testnet dApp for managing apps and testing distribution
- Documentation: docs.vebetterdao.org
Getting Started Checklist
1. Get B3TR tokens on testnet 2. Register your app on the testnet governance dApp 3. Add a reward distributor (the PUBLIC ADDRESS of the wallet or contract calling distributeRewards) 4. Choose integration pattern (smart contract, hybrid, or backend-only) 5. Implement reward distribution with sustainability proofs 6. Test on testnet environment 7. Acquire Creator NFT and get endorsed to 100 points for mainnet