# VeBetter

VeBetter is a decentralized autonomous organization (DAO) fostering sustainability through the B3TR token. VOT3 governs the DAO, allowing community-driven decisions.

<div align="left" data-full-width="false"><figure><img src="/files/IRdzpOqU84gzaMJLtjlT" alt=""><figcaption></figcaption></figure></div>

VeBetter is a decentralized autonomous organization (DAO) platform built on [VechainThor](https://www.vechain.org/vechainthor/) that empowers its community through a suite of smart contracts designed for governance, incentive distribution, and asset management. The key components of the platform include:

1. **B3TR Token**: The incentive ERC-20 token with a 1 billion cap, used within the ecosystem for rewards and governance.
2. **Governance System**:
   * **B3TRGovernor**: Facilitates decentralized governance where any community member can create proposals. Proposals require a deposit of `VOT3` tokens to become active, and successful proposals are executed via the `TimeLock` contract.
   * **TimeLock**: Ensures a time delay in the execution of governance decisions for security and transparency.
3. **Incentive Mechanisms**:
   * **Emissions**: Manages the periodic distribution of `B3TR` tokens to various allocations including `XAllocation`, `Vote2Earn`, and Treasury.
   * **VoterRewards**: Rewards voters based on their voting power and `Galaxy Member` NFT level.
   * **X2Earn Apps and Rewards**: Supports x-2-earn applications by managing the insertion, management, and eligibility of apps for `B3TR` allocation rounds. Rewards users for sustainable actions within these apps through the `X2EarnRewardsPool`.
4. **User Privileges and Rewards**:
   * **GalaxyMember**: An upgradeable NFT system that determines user privileges and `B3TR` token rewards based on the NFT level.
5. **Asset Management**:
   * **Treasury**: Holds all DAO assets, including various ERC-20 and ERC-721 tokens. Asset transfers are governed by community proposals.
6. **Voting and Allocation**:
   * **XAllocationPool**: Distributes weekly `B3TR` emissions for x2earn apps.
   * **XAllocationVoting**: Manages voting for x2Earn application support, using a "Quadratic Funding" formula to calculate voting power based on `VOT3` holdings.

VeBetter leverages these contracts to create a robust and democratic ecosystem where community members can actively participate in governance, earn rewards, and contribute to the platform's growth.

### Resources

You can find the smart contracts repository at this [GitHub url.](https://github.com/vechain/vebetterdao-contracts) Use that repo to generate ABIs and Typechain Types to interact with the contracts.

Read more about our smart contracts and what they do in the [Smart Contracts](/vebetter/smart-contracts) section.

### Contracts addresses

Contracts have been deployed on the vechain mainnet at the following addresses.

<table><thead><tr><th width="252">Contract</th><th>Address</th></tr></thead><tbody><tr><td>B3TR</td><td>0x5ef79995FE8a89e0812330E4378eB2660ceDe699</td></tr><tr><td>B3TRGovernor</td><td>0x1c65C25fABe2fc1bCb82f253fA0C916a322f777C</td></tr><tr><td>Emissions</td><td>0xDf94739bd169C84fe6478D8420Bb807F1f47b135</td></tr><tr><td>GalaxyMember</td><td>0x93B8cD34A7Fc4f53271b9011161F7A2B5fEA9D1F</td></tr><tr><td>TimeLock</td><td>0x7B7EaF620d88E38782c6491D7Ce0B8D8cF3227e4</td></tr><tr><td>Treasury</td><td>0xD5903BCc66e439c753e525F8AF2FeC7be2429593</td></tr><tr><td>VOT3</td><td>0x76Ca782B59C74d088C7D2Cce2f211BC00836c602</td></tr><tr><td>VoterRewards</td><td>0x838A33AF756a6366f93e201423E1425f67eC0Fa7</td></tr><tr><td>X2EarnApps</td><td>0x8392B7CCc763dB03b47afcD8E8f5e24F9cf0554D</td></tr><tr><td>X2EarnRewardsPool</td><td>0x6Bee7DDab6c99d5B2Af0554EaEA484CE18F52631</td></tr><tr><td>XAllocationPool</td><td>0x4191776F05f4bE4848d3f4d587345078B439C7d3</td></tr><tr><td>XAllocationVoting</td><td>0x89A00Bb0947a30FF95BEeF77a66AEdE3842Fe5B7</td></tr><tr><td>VeBetter Passport</td><td>0x35a267671d8EDD607B2056A9a13E7ba7CF53c8b3</td></tr><tr><td>X2EarnCreator</td><td>0xe8e96a768ffd00417d4bd985bec9EcfC6F732a7f</td></tr><tr><td>NodeManagement</td><td>0xB0EF9D89C6b49CbA6BBF86Bf2FDf0Eee4968c6AB</td></tr><tr><td>GrantsManager</td><td>0x055d20914657834c914d7c44bf65b566ab4b45a2</td></tr><tr><td>Dynamic Base Allocations Pool</td><td>0x98c1d097c39969bb5de754266f60d22bd105b368</td></tr><tr><td>Relayers Rewards Pool (Auto-voting)</td><td>0x34b56f892c9e977b9ba2e43ba64c27d368ab3c86</td></tr></tbody></table>


# B3TR & VOT3 Tokens

## B3TR - Incentive Token

`Address: 0x5ef79995FE8a89e0812330E4378eB2660ceDe699`

B3TR is the incentive token of VeBetter. Its functions include:

1. General incentive token for VeBetter, including VeBetter Treasury Management
2. Value carrier and monetization mechanism for active participants and innovative enterprise models
3. Incentive token for sustainability applications
4. Back VOT3 tokens 1:1, the token required for VeBetter governance

The total supply of B3TR is capped at 1,000,000,000 tokens, with a weekly issuance schedule carried out over 12 years.

## VOT3 - Governance Token

`Address: 0x76Ca782B59C74d088C7D2Cce2f211BC00836c602`

VOT3 is the governance token of VeBetter. Its functions include:

1. Required to take part in governance
2. Convertible, 1:1 between B3TR and VOT3

You can convert back and forth between B3TR and VOT3 whenever you want, with the only limitation that you cannot convert VOT3 tokens sent to you by other wallets into B3TR, just the amount you originally converted.


# B3TR Emissions

VeBetter distributes the B3TR token via a long-term emission schedule designed to incentivize sustainable behavior and community participation in governance. Emissions are distributed weekly and are split across several key allocation pools.

### Recent Governance Change (April 2025)

As a result of an approved governance proposal, the following updates were implemented:

* The Treasury allocation was reduced from 20% to 15% for each cycle starting from cycle 46.
* The remaining 5% was reallocated to a new GM Rewards Pool, exclusively for Galaxy Member (GM) NFT holders who actively participate in governance voting

These changes ensure more direct rewards for active and engaged members of the community.

## Emissions Schedule <a href="#id-2.-emissions-schedule" id="id-2.-emissions-schedule"></a>

B3TR token has \~1 billion total supply, that will be emitted weekly over a period of 634 weeks or 12 years.

*N.B.* We will use the term **cycle** instead of **week** when referring to the emissions schedule.

| **Pool**      | **% of total supply** | **Initial emissions**                                                        | **Decay Rate**                                 |
| ------------- | --------------------- | ---------------------------------------------------------------------------- | ---------------------------------------------- |
| X-Allocations | 53%                   | 2,000,000                                                                    | 4% every 12 cycles​                            |
| Vote2earn     | 27%                   | Follows the X-Allocation emissions but with an additional decay rate applied | 20% of x-allocations emissions every 50 cycles |
| Treasury      | 16%                   | 25% of total allocation for X-Allocations and Vote2earn                      | No decay as pegged to the other emission       |
| GM Rewards    | 4%                    | 5% of weekly emissions, reallocated from the original 20% Treasury share     | No decay as pegged to the other emission       |

### Emissions Chart

[🔗 Explore Interactive B3TR Emissions Simulator](https://b3tr-emissions.streamlit.app/)

<figure><img src="/files/7BG05vWauYd3EfMaPj10" alt=""><figcaption></figcaption></figure>

## Emissions Parameters <a href="#emissions-parameters" id="emissions-parameters"></a>

The Emissions smart contract contains parameters for the emissions scheduling.

| **Param**                          | **Value**                                                     | **Upgradeable** |
| ---------------------------------- | ------------------------------------------------------------- | --------------- |
| X-Allocations address              | `0x4191776F05f4bE4848d3f4d587345078B439C7d3`                  | Yes             |
| Vote2earn address                  | `0x838A33AF756a6366f93e201423E1425f67eC0Fa7`                  | Yes             |
| Treasury address                   | `0xD5903BCc66e439c753e525F8AF2FeC7be2429593`                  | Yes             |
| Total supply                       | 1B                                                            | No              |
| Emissions frequency (cycle length) | 1 week                                                        | Yes             |
| X-Allocations decay rate           | 4%                                                            | Yes             |
| X-Allocations decay frequency      | every 12 cycles                                               | Yes             |
| Vote2earn decay rate               | 20%                                                           | Yes             |
| Vote2earn decay frequency          | every 50 cycles                                               | Yes             |
| Treasury % allocation              | 15% of total emissions for the cycle *(updated via proposal)* | Yes             |
| Gm Pool % Allocation               | 5% of total emissions for the cycle *(added via proposal)*    | Yes             |

## Triggering Emissions

Emissions need some sort of trigger, as it is not possible for a smart contract to invoke itself. There is a public function that can be triggered by any account. In addition to this, the foundation automatically triggers the emissions, if this operation fails, any other user can trigger it.

<br>


# Treasury

The Treasury is the beating heart of any DAO, representing the store of wealth and source of funds for the ecosystem. Adhering to the core principles of Web3, the VeBetter DAO Treasury will be transparent, fiscally efficient, and auditable.

Treasury management follows the rules and protocols defined in VeBetter Governance. The uncompromising principle of the Treasury Pool is that tokens will only be used for expanding and building the VeBetter ecosystem, making the world better in the process.

## Implementation

Treasury will hold all assets belonging to the DAO. Such assets include `VET`, `VTHO`, `B3TR`, `VOT3` and any other `ERC-20` or `ERC-721` tokens that have been transferred to the Treasury contract address.

Tokens can only be transferred from the Treasury to another address via a governance proposal. The same goes for converting to `B3TR`/ `VOT3` .

Token balances can be viewed by anyone by calling one of the balance functions.

In the case that the Treasury needs to stop all transactions, the smart contract can be paused.

This contract cannot transfer tokens out that are non-native or non ERC-721 or ERC-20.

## Contract Functionality <a href="#id-2.-contract-functionality" id="id-2.-contract-functionality"></a>

| **Function**         | **Access Control** | **Description**                                                                                                |
| -------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------- |
| `pause()`            | Contract Admin     | Pause contract so no transfers can be carried out                                                              |
| `upgradeToAndCall()` | Upgrader Role      | Upgrade implementation contract                                                                                |
| `transferVTHO()`     | Governance         | Withdraw VTHO from treasury                                                                                    |
| `transferB3TR()`     | Governance         | Withdraw B3TR from treasury                                                                                    |
| `transferVOT3()`     | Governance         | Withdraw VOT3 from treasury                                                                                    |
| `transferVET()`      | Governance         | Withdraw VET from treasury                                                                                     |
| `transferTokens()`   | Governance         | Withdraw any erc-20 token from treasury, address needs to be passed in so that contract can be interacted with |
| `transferNFT()`      | Governance         | Withdraw any NFT from treasury address needs to be passed in so that contract can be interacted with           |
| `convertB3TR()`      | Governance         | Converts B3TR for VOT3                                                                                         |
| `convertVOT3()`      | Governance         | Converts VOT3 to B3TR                                                                                          |

### Transfer Limits

Each token has a transfer limit in place to avoid moving huge sums of money in a single operation. Those limits can be updated by governance and are token-specific.

Current limits are:

* 200,000 VET
* 200,000 B3TR
* 3,000,000 VTHO
* 50,000 VOT3


# X2Earn Allocations

The pool’s purpose is to finance sustainable apps that join the VeBetter ecosystem. The purpose of the apps is to use those tokens to reward and incentivize sustainable actions through their applications.

## Allocation rounds

Distribution of B3TR from the x-allocation pool to the apps happens in cycles, which we will refer to from now on as *rounds*. Each round will last 1 week, and funds will be distributed once the round ends.

Apps receive B3TR tokens based on the support that they receive from the VOT3 holders through voting.

All unallocated funds of that round are sent to the Treasury contract.

<figure><img src="/files/2gP9szTIPyOWQKXYuIDO" alt=""><figcaption></figcaption></figure>

### Rules

* **Voting Token:** The token used for voting is VOT3.
* **Voting Frequency:** Each round of voting lasts one week, though this period could change in the future.
* **Voting Eligibility:** To be able to vote, users must be verified as real persons. Each user needs to prove they have completed 3 better actions within the last 12 rounds. These actions are subject to [decay over time.](/vepassport/checks/proof-of-participation) A "better action" is defined as receiving a reward from an app for performing a sustainability-related activity. [Learn more here.](https://docs.vebetterdao.org/vepassport/vepassport#proof-of-participation)
* **Votes Snapshot:** The VOT3 holdings and better action are snapshotted at the start of each round. VOT3 tokens acquired and better action done after that moment won't be considered when casting the vote.
* **Voting Flexibility:** Within each round, users can vote only once but have the flexibility to allocate their votes among multiple apps. For example, a user with 100 VOT3 might assign 30 VOT3 to app #1, 20 VOT3 to app #2, and 50 VOT3 to app #3.
* **Resetting Votes:** At the beginning of each round, all previous votes are reset, requiring users to cast their votes again. This design encourages the community to return and vote regularly, hence the introduction of a "vote-2-earn" mechanism, where users are rewarded for voting.
* **Allocation Shares:** At the end of each round, the smart contract calculates the ranking and determines the distribution of funds among the apps.
* **Quorum Requirements:** To ensure broad community involvement, each round must meet a specific quorum to validate the results. If the quorum is not reached, the distribution still occurs but is based on the percentages from the last valid round.

## Voting Process

Each emission distribution starts a new allocation round for x2earn applications.

At the start of each round, a snapshot of the VOT3 holdings is made. This snapshot includes both the token held in their wallet balance and any tokens they have deposited to support proposals (if applicable).

There can be only two possible outcomes of a round: it succeeds or fails. **To succeed the only requirement is that the quorum,** which is currently 1% of total VOT3 suppl&#x79;**, is reached.**

A user can cast his votes only when the round is active and only one time per round, by passing an array of x-application IDs and the fraction of votes he wants to allocate to each.

<figure><img src="/files/hNuOE090rNpGmb1WDtFW" alt=""><figcaption><p>Example of casting a vote</p></figcaption></figure>

## Earnings calculation <a href="#allocation-and-distribution-rules" id="allocation-and-distribution-rules"></a>

* **Allocation Structure:** The distribution from the X-Allocation Pool to the apps is:
  * 100% based on the percentage of votes each app receives since [Monday 19th 2025 proposal execution](https://governance.vebetterdao.org/proposals/79715332253006527158658105451871709430073160636438501298296079696687567453221).
* **Cap on Allocation:** To prevent any one project from dominating, there's a cap on how much each app can receive from the 70% pool. This cap ensures that at least six projects participate in the voting each week.
* **Redistribution:** Any leftover funds from the X-Allocation Pool will be sent to the Treasury and can be redistributed through DAO voting.

Both the minimum and maximum caps can be changed by the governance.

### Quorum impact on distribution

When the quorum is not reached during an allocation voting round, it can impact the distribution process. Let's assume we have 2 rounds, where the first one succeeded and the second one did not, here is how it would work:

* **Total Funding for Current Round**: The total amount for distribution is derived from the current round, regardless of what happened in previous rounds.
  * Example: If Round 1 had 90,000 B3TR to distribute, but Round 2 had 80,000, the allocations in Round 2 will use the 80,000 units as the funding pool.
* **Base Allocation**: Every application in the current round receives a minimum allocation from the total funding pool, even if the quorum isn't met. This is calculated based on the current round's funding amount.
* **Variable Allocation**: This additional funding is determined by the voting results from the last successful round (e.g., if Round 1 succeeded, the votes from that round influence allocations in Round 2).
  * If quorum fails in the current round, variable allocations calculation will rely on the last successful round votes.
  * New applications in a failed round, with no previous votes to draw from, will only receive the base allocation.

### Distribution trigger

Distributions are not automatically sent by the contract but need to be triggered. The `claim` function is public and anyone can claim the allocation for the apps. The VeBetterDAO team however created a scheduler service to execute this action at the start of each new round.

## Quadratic Funding

Quadratic Funding (QF) is a mechanism used by VeBetter DAO to amplify available resources and democratize fund allocation.

In this system, the proportion of the emissions pool allocated to each project is calculated by squaring the sum of the square roots of individual votes for the project and then normalizing this by the square of the total votes across all projects

$$\text{Funding Allocation for Project }i = \left( \sum\_{j} \sqrt{v\_{ij}} \right)^2$$

where *j* indexes the voters for each project

$$
\text{Normalized Funding Allocation for Project } i = \frac{\left( \sum\_{j} \sqrt{v\_{ij}} \right)^2}{\sum\_{k} \left( \sum\_{j} \sqrt{v\_{kj}} \right)^2} \times \text{Emissions Pool}
$$

where *j* indexes the voters, and *k* indexes all projects considered in the QF model for the round.

This formula ensures that the allocation is heavily influenced by the number of distinct supporters rather than the sum of their votes alone. As a result, projects that have broader community support, regardless of the size of individual votes, receive a more significant portion of the emissions pool.

This funding model emphasizes community consensus, ensuring that projects with the widest appeal, rather than those with the most concentrated VOT3 backing, receive the greatest B3TR allocation.

### Linear Voting

By default, QF is enabled for all voting rounds. **However, admins have the option to disable QF. If QF is disabled, linear voting will be used, where the allocation is directly proportional to the number of votes received**.

* **Important Note**: If QF is disabled by an admin in the middle of a round, the change will only take effect starting from the following round.

## Upgradeable parameters

The following properties can be updated by the governance:

* **Voting Period**: currently this equals Emission's cycles, and can never be higher than it.
* **Quorum**: percentage of VOT3 / Total supply participating in allocation voting.
* **Base Allocation Percentage**: percentage of round allocations to be divided among the apps each round, currently set at 0%.
* **Allocation Cap:** the maximum amount of votes (in percentage) that an app can receive, currently set at 20%.


# X2Earn Apps

The ‘X’ in X-2-Earn refers to the mathematical concept of the unknown variable. ‘X’ can be applied to any kind of sustainability ecosystem with an earn mechanism. For example, ‘Plant-2-Earn', for an ecosystem that rewards tree planting. Sweat-2-Earn, for Apps that reward working out, and so on. B3TR tokens distributed to X-2-Earn Apps are, in part, intended as a source of incentivization for users. They may serve other purposes, such as encouraging builders, or for marketing and sponsorships etc. B3TR reward distribution plans are at the discretion of projects and the voting community who will approve or disapprove of a project’s reward proposals through voting.

<figure><img src="/files/yQiQlXft7PmdlSxQLMjA" alt=""><figcaption></figcaption></figure>

## Join VeBetter

As of the beginning of November, VeBetter allows apps to join the ecosystem through the endorsement of VeChain node holders. This shift from admin-controlled app selection to vechain community-based endorsement reflects the DAO’s commitment to decentralization.

* **Background Check and Creator NFT Requirement**: XApp creators begin by filling out a form on the VeBetter platform to initiate the process. If they pass the screening, they are minted a Creator NFT, which verifies them for participation in the endorsement process.
* **On-Chain XApp Submission**: Once they have received the Creator NFT, XApp creators can submit their XApp on-chain for endorsement consideration. This submission officially registers the XApp on VeBetter platform, pending endorsements from VeChain node holders.
* **Connecting with Endorsers**: After receiving the Creator NFT, XApp creators gain access to VeBetter Discord server, where they can connect with VeChain node holders who may endorse their XApp. This community platform allows them to build relationships with potential endorsers and formally submit their XApp for consideration on VeBetter platform.
* **XApp Endorsement**: XApps must accumulate an endorsement score of 100 to become eligible for allocation rounds. Achieving this threshold enables an XApp to participate in weekly rounds to receive a share of the B3TR allocation pool.

## VeChain Node Scores

VeChain node holders are key decision-makers in the X2Earn endorsement process. Each type of VeChain node, represented by an NFT in the holder’s wallet, has an assigned endorsement score based on its level. These scores determine the impact each endorsement has on an XApp’s eligibility.

| VeChain Node Level | Endorsement Score |
| ------------------ | ----------------- |
| Strength           | 2                 |
| Thunder            | 13                |
| Mjolnir            | 50                |
| VeThorX            | 3                 |
| StrengthX          | 9                 |
| ThunderX           | 35                |
| MjolnirX           | 100               |

A wallet can only hold one of these VeChain Node NFTs at a time, and to obtain a node, users must maintain a specific amount of VET in their wallet (see [vechain nodes](https://docs.vechain.org/core-concepts/nodes) for more info). The cumulative endorsement scores from nodes determine an XApp’s eligibility to join VeBetter and participate in allocation rounds.

## Voting Eligibility and Endorsement Status

Once an XApp is endorsed, reaching a cumulative endorsement score of 100, it becomes eligible to receive funds in the allocation rounds. This eligibility can be adjusted by VeChain node holders based on the app's performance and compliance.

### **XApp Endorsement**

An XApp is officially considered endorsed when it accumulates an endorsement score of 100. This score is the sum of all VeChain node endorsements for the app. Upon reaching this threshold, the XApp automatically qualifies for the next XAllocation Voting round and will continue participating in future rounds as long as its score remains at or above 100.

* **Endorsement Limitations**: Each VeChain Node NFT can endorse only one XApp at a time. Similarly, each account can endorse only one XApp unless it leverages the NodeManagement contract to delegate multiple VeChain nodes.
* **Endorsement Cap**: Once an XApp reaches the endorsed status with a score of 100, it cannot receive additional endorsements from other nodes.

### **XApp Un-Endorsement and Grace Period**

Node holders have the authority to withdraw their endorsement if they no longer wish to support a specific XApp. If an XApp’s score falls below the 100-point threshold, it enters a grace period. During this time, the XApp has a limited opportunity to regain endorsements and restore its score to 100. If it fails to meet this requirement before the grace period ends, it will be removed from the XAllocation voting round.

* **Retention of Past Allocations**: Although the XApp is removed from future allocation rounds, it still retains any allocations received from previous rounds. The XApp may rejoin allocation rounds if it regains the necessary endorsement score of 100.

### **Integrity Checks**

To ensure the consistency and validity of endorsements, VeBetter conducts periodic checks on endorsing nodes.

## App ID

When your app is submitted to the contract an `appId` is generated by hashing the app name. This id cannot be updated in the future, even if you change the name of your app.

## Signaling

Authorized apps can report addresses they have banned, such as looters, bots or scammers. This helps VeBetter and other apps detect and defend against harmful activity across the ecosystem.

If an address is flagged by mistake, VeBetter or selected app admins can review the case and reset its signal counter.

**Community Dashboard:** <https://vechain-energy.github.io/vebetterdao-signal-admin/>\
Build by the community, this dashboard shows all signaled wallets.

## Metadata <a href="#x-apps-metadata" id="x-apps-metadata"></a>

When an app is added the following information is saved on-chain:

* **name**: the name of the app, cannot change once it's added.
* **app ID**: is the hash of the name of the app (from the previous point) and it's used as a unique identifier across all the smart contracts; once the app is added and this ID is generated it cannot be updated.
* **receiver address**: this is the address where the app will receive the allocation funds, also addressed to as "Treasury address".
* **creation timestamp**: the timestamp when the app was added.
* **metadata URI**: the IPFS CID containing all the information of the app, which will be used by the frontend to display the app details.
* **moderators**: a list of addresses that can update the metadataURI of an app.
* **admin**: this address can add/remove moderators, change the receiver address, transfer ownership to another admin, and update the metadata URI of the app.

The metadata URI needs to follow the following standard:

{% tabs %}
{% tab title="JSON" %}

```javascript
{
   "name":"My sustainable app",
   "description":"Run and get rewarded",
   "external_url":"https://openseacreatures.io/3",
   "logo":"https://storage.googleapis.com/opensea-prod.appspot.com/puffs/3.png",
   "header_image":"https://storage.googleapis.com/opensea-prod.appspot.com/puffs/3.png",
   "screenshots":[
      "https://storage.googleapis.com/opensea-prod.appspot.com/puffs/3.png",
      "https://storage.googleapis.com/opensea-prod.appspot.com/puffs/3.png",
      "https://storage.googleapis.com/opensea-prod.appspot.com/puffs/3.png"
   ],
   "social_urls":[
      {
         "name":"YouTube",
         "url":"https://www.youtube.com/@DLoaw"
      },
      {
         "name":"Instagram",
         "url":"https://www.instagram.com/@DLoaw"
      }
   ],
   "app_urls":[
      {
         "code":"play_store",
         "url":"https://www.playstore.com/@DLoaw"
      },
      {
         "code":"apple_store",
         "url":"https://www.applestore.com/@DLoaw"
      },
      {
         "code":"web_app",
         "url":"https://www.myapp.com"
      }
   ],
   "tweets": [],
   "categories": ["nutrition", "education-learning"]
}
```

{% endtab %}
{% endtabs %}


# Governance

{% hint style="info" %}
Following community proposal, since the [13th of August 2025](https://governance.vebetterdao.org/proposals/16456558618029822768724567372248444488437431846368752919370485354508180864756), VOT3 deposits on proposals also **count as voting power for XApp allocation votes**. The deposit threshold is capped at 5M VOT3. To submit a proposal, the proposer must [create a Discourse](https://vechain.discourse.group/latest) thread and be a [Moon (or higher) GM NFT](/vechain-node-and-staking-guides/legacy-vechain-node-guides-pre-stargate/vechain-nodes-x-gm-nfts-maximising-benefits-within-vebetter) holder.
{% endhint %}

{% hint style="warning" %}
This page describes the V11 Governor, which introduces the **Community Execution Framework**: every Standard proposal can now carry an on-chain B3TR implementation cost, a payout address, a developer description, an implementation-discussion link, and a list of contributors. Pre-V11 proposals (no `maxBudget`) keep working with no payout flow.
{% endhint %}

Anyone holding VOT3 is a member of VeBetter and can take part in voting. VOT3 is VeBetter's governance token, obtained by swapping B3TR at a 1:1 ratio. All members can vote on proposals, participate in governance discussions, and access the Treasury, with a minimum requirement of holding **1 VOT3**.

## Governance Stabilization Period and Initialization

At launch, VeBetter adhered to an initial set of governance rules until it had run for one year without any technical interruptions. The Stabilization Period was critical for ensuring the long-term efficacy and viability of VeBetter. To prevent exploits during the Stabilization Period, the VeChain Foundation maintained the ability to pause and restart B3TR token minting, only in the case of an exploit or other major issue. Once the requirements were met, community stakeholders can maintain or deprecate this functionality through governance.

## The V11 lifecycle at a glance

```
Pending → Active → Succeeded → Queued → Executed → InDevelopment → Completed → (Paid)
                  ↘ Defeated / DepositNotMet / Canceled
```

* **Pending → Active**: VOT3 deposit threshold must be reached during the deposit period.
* **Active → Succeeded**: quorum reached and FOR > AGAINST at the end of the voting round.
* **Succeeded → Queued → Executed**: actionable proposals pass through the Timelock before any on-chain calls are made. Non-executable proposals skip Queued/Executed and remain in Succeeded.
* **Executed (or Succeeded) → InDevelopment**: the proposer (or an admin) calls `markAsInDevelopment` to register a **payout address**, a **description**, an **implementation discussion** link, and a list of **contributors**. This is when the V11 community-execution flow takes ownership of the developer payout.
* **InDevelopment → Completed**: an admin (role `PROPOSAL_STATE_MANAGER_ROLE`) flips the proposal to Completed via `markAsCompleted` once delivery is verified.
* **Completed → Paid**: anyone can call `claimPayout` to pull the full implementation cost from the Treasury to the payee in a single transfer.

## Proposal Submission

Proposals are the backbone of the DAO. VeBetter maintains a Discourse forum for proposal discussion and a dashboard for voting results and history. To reach on-chain voting, a proposal goes through forum discussion, a community temperature check (the on-chain deposit), and finally an on-chain vote.

### Requirements

* **Hold a GM Moon NFT (or higher)** — upgrade your **Earth GM NFT** to **Moon**, or purchase one. If you don't hold an Earth GM NFT, **participate in at least one vote** to earn eligibility for the free Earth mint.
* **Create a Discourse thread** at least **3 days** before submitting the proposal, so the community can review it.

### Community support (deposit period)

Every new proposal goes through a deposit period. A deposit threshold of VOT3 — calculated as a percentage of total B3TR supply, capped at 5M VOT3 — must be met for the proposal to become active. This deposit acts as a temperature check: if the community believes the proposal is worth considering, members can contribute VOT3. If the threshold is reached before the end of the waiting period, the proposal becomes Active; otherwise, it is automatically marked DepositNotMet.

Deposits can be withdrawn once the proposal is cancelled or voting starts. While VOT3 is locked as a deposit it cannot be transferred or used to support other proposals, but **it is still counted in the allocation voting snapshot** and grants extra voting power in allocation rounds (e.g. tokens locked supporting a proposal that starts in Round #4 still count in Rounds #3 and #4).

### Creating a proposal (V11)

When drafting a proposal, the proposer provides:

* **Description** — what the proposal aims to achieve (off-chain markdown).
* **Targets / values / calldatas** — for actionable proposals only.
* **Start round** — the allocation round in which voting becomes active.
* **Deposit amount** — initial VOT3 contributed by the proposer.
* **Implementation cost (`maxBudget`)** — the on-chain B3TR budget that will be paid out to the developer payout address after delivery. Set to **0** for proposals that don't need a developer payout (pure governance directions, parameter changes, etc.).

The on-chain call is:

```solidity
function propose(
    address[] memory targets,
    uint256[] memory values,
    bytes[] memory calldatas,
    string  memory description,
    uint256 startRoundId,
    uint256 depositAmount,
    uint256 maxBudget        // V11: 0 disables the community-execution flow
) external returns (uint256 proposalId);
```

Setting `maxBudget > 0` emits `ProposalBudgetSet(proposalId, maxBudget)` and locks the implementation cost for the lifetime of the proposal — it can never be increased later.

### Proposal types

* **Actionable** — the proposal carries one or more on-chain calls that execute through the Timelock once Succeeded.
* **Non-actionable** — no on-chain calls; the proposal expresses a direction. After Succeeded the proposer can still record an implementation cost / payee via the community-execution flow.
* **Grants** — submitted via `proposeGrant` and follow the milestone-based payout flow (see [How to apply for grants](/vebetter/governance/how-to-apply-for-grants)). Grants do **not** use the V11 community-execution flow.

## Proposal Process

{% stepper %}
{% step %}

### Deposit Period

A temperature check. The community **must fund the proposal with VOT3** until it reaches the deposit threshold. Each contribution also boosts the contributor's allocation voting power. If the threshold isn't reached by the end of the waiting period, the proposal is automatically marked DepositNotMet. The proposer or an admin can cancel an active deposit period.
{% endstep %}

{% step %}

### Voting Period

Once the proposal is active, a snapshot of total VOT3 supply and each holder's balance is taken to calculate voting power. Holders cast **FOR / AGAINST / ABSTAIN**. Each proposal is active for one round. 100% of voting power is applied to the option you select — votes cannot be split.
{% endstep %}

{% step %}

### Outcome

When voting ends, if the **30% quorum** is reached and FOR > AGAINST, the proposal is **Succeeded**. Actionable proposals are queued in the Timelock and then **Executed**. Non-actionable proposals stay in Succeeded.
{% endstep %}

{% step %}

### In Development (V11)

After Executed (or Succeeded for non-actionable proposals), the proposer — or an admin holding `PROPOSAL_STATE_MANAGER_ROLE` — calls `markAsInDevelopment` to register:

* the **payee** (the single address that will receive the full implementation cost),
* a short **description** of the implementation,
* an **implementation discussion** URL,
* a list of **contributors** (GitHub / X handles or URLs, capped at `maxContributorsPerProposal`, currently 20).

`payee` must be non-zero when `maxBudget > 0`, and must be zero when `maxBudget == 0` (you can't pay out a proposal that never set a budget, and you can't have a budget without a destination). Any of these fields can be replaced later via `updateCommunityExecution`, as long as the payout has not yet been claimed.
{% endstep %}

{% step %}

### Completed

Once delivery is verified, an admin (`PROPOSAL_STATE_MANAGER_ROLE`) calls `markAsCompleted` to flip the proposal into the **Completed** state. From this point the proposal is eligible for payout.
{% endstep %}

{% step %}

### Payout

**Anyone** can call `claimPayout(proposalId)` once the proposal is Completed. The Governor pulls the full `maxBudget` from the Treasury and transfers it in a single B3TR payment to the registered payee. The call is idempotent — a second `claimPayout` reverts with `PayoutAlreadyClaimed`. After the payout, all V11 fields become immutable.

The payee is responsible for distributing funds to the contributors **off-chain**. The on-chain `contributors[]` list is for attribution only and does not control how the budget is split.
{% endstep %}
{% endstepper %}

<figure><img src="/files/Eox5r9CBYIXa9t7U0X0L" alt=""><figcaption><p>Proposal States</p></figcaption></figure>

<figure><img src="/files/nPmGBVqwUUUbnnTPTaBe" alt=""><figcaption><p>Lifecycle of the proposal</p></figcaption></figure>

### Quorum

Quorum is **30% of the total supply of VOT3**. All vote types (FOR, AGAINST, ABSTAIN) count toward quorum. Voting rewards are distributed regardless of the vote cast.

### Vote outcome

If quorum is not reached the proposal is **Defeated**. If quorum is reached, FOR is compared against AGAINST: more FOR than AGAINST → **Succeeded**, otherwise **Defeated**. Voting rewards are distributed regardless of the outcome.

### Execution and Timelock

VeBetter's Governor contract can execute actions on any contract on VeChainThor, provided that contract allows the action. A Timelock (OpenZeppelin's `TimelockController` combined with `GovernorTimelockControl`) delays execution so users can exit the system before a contentious decision lands. To execute, a proposal must first be queued in the Timelock and wait the configured minimum delay.

<figure><img src="/files/KxEPwJ3aFI6x0uIH5jBP" alt=""><figcaption><p>Governance setup</p></figcaption></figure>

### Vote Delegation

The Governor only counts **delegated** voting power. Auto-delegation is enabled on VOT3 transfers and on the B3TR → VOT3 swap, so EOAs receive voting power automatically. **Smart contracts** are excluded from auto-delegation — a contract that wants to vote must call `delegate(itself)` once.

If you want someone else to vote on your behalf, delegate to their address; you keep your tokens but they cast the vote.

## Quadratic Voting

Quadratic Voting (QV) re-calibrates voting power so large holders don't dominate. With QV enabled, voting power is the square root of the holder's VOT3 balance:

$$
\text{votingPower} = \sqrt{v}, \text{ where } v \text{ is the number of VOT3 tokens held}
$$

Votes are still cast as FOR / AGAINST / ABSTAIN, but the effective weight follows the recalibrated value.

### Linear Voting

QV is enabled by default. Admins (or governance) can disable QV at any time, switching to linear voting where voting power equals VOT3 balance. If QV is toggled during an ongoing round, the change only takes effect from the **next** round.

## Community Execution Framework (V11)

The V11 Community Execution Framework is the on-chain layer that lets the DAO **fund and verify the delivery** of a proposal end-to-end. It replaces the off-chain "we'll figure it out later" pattern with three on-chain commitments:

1. **An implementation cost** locked into the proposal at creation (`maxBudget`).
2. **A single payout address** registered when the team commits to delivery (`markAsInDevelopment`), editable until the payout is claimed.
3. **A public claim** anyone can trigger once an admin marks the work Completed (`claimPayout`).

### Funds flow

* The implementation cost is **not** locked in the Governor at proposal creation — it's a commitment, not an escrow. The Treasury still holds B3TR until `claimPayout` is called.
* On `claimPayout`, the Governor calls `Treasury.transferB3TR(payee, maxBudget)` to forward the full budget in one transaction. The Governor must hold `Treasury.GOVERNANCE_ROLE` for this to succeed — granted as part of the V11 upgrade.
* If the Treasury is short of B3TR at claim time, `claimPayout` reverts and can be retried later.

### Editing community-execution data

`updateCommunityExecution` lets the proposer (or an admin) replace the payee, description, implementation discussion, and contributors **while the proposal is InDevelopment or Completed and the payout has not yet been claimed**. Once `claimPayout` succeeds, all V11 fields are frozen forever.

### Authorization summary

| Action                       | Caller                                        |
| ---------------------------- | --------------------------------------------- |
| `propose` (with `maxBudget`) | Anyone meeting the standard requirements      |
| `markAsInDevelopment`        | Proposer **or** `PROPOSAL_STATE_MANAGER_ROLE` |
| `updateCommunityExecution`   | Proposer **or** `PROPOSAL_STATE_MANAGER_ROLE` |
| `markAsCompleted`            | `PROPOSAL_STATE_MANAGER_ROLE` only            |
| `resetDevelopmentState`      | `PROPOSAL_STATE_MANAGER_ROLE` only            |
| `claimPayout`                | Anyone (idempotent)                           |

### Events

* `ProposalBudgetSet(proposalId, maxBudget)` — emitted from `propose` when `maxBudget > 0`.
* `ProposalInDevelopment(proposalId)` — emitted from `markAsInDevelopment`.
* `ProposalInDevelopmentDetails(proposalId, payee, description, implementationDiscussion)` — emitted from `markAsInDevelopment` and `updateCommunityExecution`.
* `ProposalContributorsSet(proposalId, contributors)` — emitted alongside the details event.
* `ProposalCompleted(proposalId)` — emitted from `markAsCompleted`.
* `ProposalPayoutClaimed(proposalId, payee, amount)` — emitted from `claimPayout`.
* `ProposalDevelopmentStateReset(proposalId)` — emitted from `resetDevelopmentState`.

### Errors

* `InvalidPayeeAddress` — payee is the zero address while `maxBudget > 0`.
* `MissingProposalBudget` — caller passed a payee while `maxBudget == 0`.
* `TooManyContributors(provided, max)` — contributors array exceeds `maxContributorsPerProposal`.
* `PayeesAlreadyFinalized` — `markAsInDevelopment` was already called for this proposal.
* `PayoutAlreadyClaimed` — `claimPayout` was already called, or `updateCommunityExecution` is attempted after claim.
* `NotReadyToClaim` — `claimPayout` was called but the proposal has no registered payee or no budget.
* `UnauthorizedCommunityExecution(caller, proposalId)` — caller is neither the proposer nor an admin.

## Upgradeable parameters

The following parameters can be updated by governance (or `DEFAULT_ADMIN_ROLE` on the Governor where applicable):

* **Quorum**: currently 30% of total VOT3 supply.
* **Deposit Threshold**: percentage of total B3TR supply (in VOT3) required to activate a proposal — currently **2%**, capped at **5M VOT3**.
* **Voting Threshold**: minimum amount of VOT3 needed to cast a vote (currently 1).
* **Minimum Voting Delay**: minimum time a proposal must remain Pending before voting can start (currently 3 days).
* **Timelock Minimum Delay**: time between queuing and execution for actionable proposals.
* **Voting Period**: must be ≤ the Emissions Cycle. Extending it requires extending the Emissions Cycle first.
* **Function Restrictions**: when enabled, only whitelisted `(target, selector)` pairs can be called from a proposal.
* **Quadratic Voting**: can be enabled or disabled per round.
* **`maxContributorsPerProposal`** (V11): cap on the contributors array per proposal — set at the V11 upgrade (currently 20). There is no runtime setter; changing it requires a Governor upgrade.

## Where to find the contracts

| Contract                          | Purpose                                                                                                                                    |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `B3TRGovernor`                    | Main entrypoint — `propose`, `markAsInDevelopment`, `updateCommunityExecution`, `markAsCompleted`, `claimPayout`. Current version: **11**. |
| `GovernorCommunityExecutionLogic` | Library holding the V11 community-execution logic, called via delegatecall from `B3TRGovernor`.                                            |
| `TimelockController`              | OZ Timelock used for execution delay.                                                                                                      |
| `Treasury`                        | Holds B3TR; transfers to payee on `claimPayout`.                                                                                           |

The full ABI is published in [`@vechain/vebetterdao-contracts`](https://www.npmjs.com/package/@vechain/vebetterdao-contracts).


# How to apply for Grants ?

<figure><img src="/files/C3Zx54G7oLFfomsuRUdj" alt=""><figcaption></figcaption></figure>


# Voter Rewards

B3TR tokens are distributed weekly through VeBetter’s emissions system and sent to two separate reward pools:

* **Vote2Earn Pool**: Incentivizes all users to participate by rewarding them based on their **VOT3 token balance**
* **GM Rewards Pool** (New: [April 2025 Governance Update](https://governance.vebetterdao.org/proposals/29105190577567483236613349157882547619640909716326747339146460525546041993191)): Provides additional rewards to users who **hold a GM NFT and vote** during the cycle, with rewards based on the **reward weight** of their GM NFT level

To earn from either pool, you must cast a valid vote in a governance or allocation round during the cycle.

> All funds received by the Vote2Earn pool are used solely to reward voters proportionally based on VOT3.\
> The GM Rewards pool receives a fixed 5% of weekly emissions and distributes rewards to qualifying voters who hold a GM NFT.

## Galaxy Member NFT: Unlock Greater Rewards with Upgrades

VeBetter uses an upgradeable NFT system called the **Galaxy Member (GM) NFT** to reward committed community members. By holding a GM NFT and voting in a cycle, you become eligible to receive a portion of the **GM Rewards Pool**, which distributes 5% of weekly B3TR emissions.

The **higher your GM NFT level**, the greater your **reward weight**, determining your share of the GM pool during that voting cycle.

### Unlocking GM NFT Levels

There are **two ways** to upgrade your GM NFT:

### B3TR Requirements for Upgrades

| **Level** | **Name** | **B3TR Required** | **Reward Weight** |
| --------- | -------- | ----------------- | ----------------- |
| **2**     | Moon     | 5,000 B3TR        | 1.1               |
| **3**     | Mercury  | 12,500 B3TR       | 1.2               |
| **4**     | Venus    | 25,000 B3TR       | 1.5               |
| **5**     | Mars     | 50,000 B3TR       | 2                 |
| **6**     | Jupiter  | 125,000 B3TR      | 2.5               |
| **7**     | Saturn   | 250,000 B3TR      | 3                 |
| **8**     | Uranus   | 1,250,000 B3TR    | 5                 |
| **9**     | Neptune  | 2,500,000 B3TR    | 10                |
| **10**    | Galaxy   | 12,500,000 B3TR   | 25                |

### Benefits of Upgrading Your GM NFT

* **Maximized Rewards**:
  * Higher GM NFT levels increase your **reward weight** in the GM Rewards Pool — earn more B3TR when you vote.
* **Flexibility**:
  * Use B3TR for upgrades or enjoy free upgrades as a VeChain Node holder.
* **Dynamic Participation**:
  * Play an active role in VeBetter and get rewarded for your engagement across **both governance proposals and XAllocation votes**.

By upgrading your GM NFT and participating in governance (via voting on **governance proposal or XAllocation vote**), you unlock enhanced rewards through the **GM Rewards Pool**, which distributes 5% of weekly B3TR emissions.\
This not only boosts your personal rewards but also reinforces your long-term role in shaping the VeBetter ecosystem.

## Linear Rewards

After a successful DAO [proposal](ttps://governance.vebetterdao.org/proposals/72709653895201643147493896803002902200801427824992756263136121079630798867207) the rewards earned by participating in VeBetter governance are linear (instead of quadratic) starting from round 23, which means that you earn rewards proportionally to your VOT3 holdings at the time of the snapshot.

### Reward Formula

$$
Reward\_i = \left( \frac{\sum\_{v \in C} V\_{i,v}}{\sum\_{u} \sum\_{v \in C} V\_{u,v}} \right) \times Vote2Earn\_{\text{cycle}}
$$

Where

* $$V\_{i,v}$$ = VOT3 balance of user ***i*** when voting on proposal ***v***
* $$C$$ = all proposals (Governance and XAllocation Voting) in the cycle the user participated in
* $$u$$ = all users who voted on any proposal during the cycle
* $$Vote2Earn\_{cycle}$$​ = total Vote2Earn reward pool for the cycle

### Example:

### Given:

* **Total participants:** 1,000 voters
* **Vote2Earn Emissions:** 1,000,000 B3TR
* **User’s VOT3 snapshot for cycle**: 10,000
* **Total VOT3 across all voters and all proposals in the cycle:** 5,300,000
* **User voted on** 1 proposal

Calculation:

$$
Reward  = (10,000 / 5,300,000) \* 1,000,000 = 1,887 B3TR
$$

This voter’s 10,000 VOT3 represents **0.1887%** of the total VOT3 submitted during the cycle, earning them **1,886.79 B3TR** from the Vote2Earn reward pool.

## GM Rewards

The **GM Rewards Pool** was introduced via a successful DAO [proposal](https://governance.vebetterdao.org/proposals/29105190577567483236613349157882547619640909716326747339146460525546041993191) in **April 2025**. It distributes **5% of weekly B3TR emissions** to **Galaxy Member (GM) NFT holders** (Moon tier and above) who vote during a cycle.

Participation includes **both governance proposals and XAllocation votes** — all voting items within a cycle count.

Rewards are calculated using a **linear model** based on the user's **GM NFT level** and the **number of votes** you cast during the cycle.\
The higher your NFT level — and the more proposals you vote on — the greater your share of the GM Rewards Pool.

### Reward Formula

$$
\text{GMReward}*i = \left( \frac{\sum\limits*{v \in C} W\_{i,v}}{\sum\limits\_{u} \sum\limits\_{v \in C} W\_{u,v}} \right) \times GMRewardsPool\_{\text{cycle}}
$$

Where

* $$W\_{i,v}$$ = reward weight of user ***i*** when voting on proposal ***v*** (based on GM NFT level)
* $$C$$ = all proposals (Governance and XAllocation Voting) in the cycle the user participated in
* $$u$$ = all users who voted with a GM NFT during the cycle
* $$GMRewardsPool\_{\text{cycle}}$$ = 5% of total B3TR emissions for the cycle

### Example:

**Scenario:**

* **GM Rewards Pool this cycle:** 50,000 B3TR
* **User A:** Neptune-level GM (reward weight = 10), votes on **2 proposals**
* **User B:** Mars-level GM (reward weight = 2), votes on **2 proposals**
* **User C:** Galaxy-level GM (reward weight = 25), votes on **1 proposal**

**Total Reward Weight in the Cycle:**

* User A: $$10×2=20$$
* User B: $$2×2=4$$
* User C: $$25×1=25$$
* Total Weight: $$20+4+25=49$$

**Reward Calculations:**

**User A:**\
Reward = $${\frac{20}{49}\times 50,000 } = 20,408.16$$ B3TR

**User B:**\
Reward = $${\frac{4}{49}\times 50,000 } = 4,081.63$$ B3TR

**User C:**\
Reward = $${\frac{25}{49}\times 50,000 } = 25,510.20$$ B3TR

## Quadratic Rewarding (disabled from round 23)

Quadratic Rewarding (QR) in VeBetter is the approach used for distributing voting rewards. Under QR approach, the rewards a user receives will be determined by the square root of their VOT3 token holdings. This method ensures that while users with more tokens still receive higher rewards, the rate of increase in rewards does not grow linearly with the number of tokens held. Instead, it rises at a decreasing rate, promoting a fairer distribution of rewards and helping to close the wealth gap within our community.


# B3MO Quests

**B3MO's Community Quests** allow users and apps to create challenges that drive participation across the VeBetter ecosystem. B3MO, the AI agent, manages everything, holding funds and tracking actions.

The first release launches with two challenge types: **Sponsored** and **Bet**. Each type has different rules around visibility, win conditions, and participation limits.

{% hint style="info" %}
Developers can also create B3MO Quests directly through the `B3TRChallenges` contract. See [Create B3MO Quests from Contract](/developer-guides/create-b3mo-quests-from-contract).
{% endhint %}

### Win Conditions

Every challenge uses one of two win conditions, chosen by the creator at setup:

* **Max Actions** — The participant who completes the most actions by the end of the challenge wins the full prize pool.
* **Split Win** — The creator sets a target number of actions and a number of winners. Everyone who hits the target and claims the prize first shares the prize pool equally.

#### When to Use Which

**Max Actions** suits competitive challenges where you want a single standout winner.

**Split Win** works better when the goal is rewarding a group for consistent effort — for example, a community campaign or a team milestone.

### Challenge Types Overview

| Challenge | Visibility | Win Condition                       | Participant Limit              |
| --------- | ---------- | ----------------------------------- | ------------------------------ |
| Sponsored | Public     | Split Win                           | No limit                       |
| Sponsored | Private    | <p>Max Actions<br><br>Split Win</p> | <p>Max 100<br><br>No limit</p> |
| Bet       | Private    | Max Actions                         | Max 100                        |

### Sponsored Challenges

In a **Sponsored** challenge, the creator funds the entire prize pool. Participants don't need to stake anything — they simply join and start completing actions. This format is ideal for app campaigns, community events, or any situation where the goal is to drive participation.

#### Public

Anyone on VeBetter can discover and join a public Sponsored challenge. The win condition is always **Split Win**, and there is no participant limit.

{% hint style="success" icon="dash" %}
**Example:** A creator sets up a public challenge with a 10,000 B3TR prize pool, 5 winners, and a minimum of 10 actions. At the end, B3MO identifies the 5 participants who completed at least 10 actions first. Those who complete the actions and claim the prize first each receive 2,000 B3TR.
{% endhint %}

#### Private

Private Sponsored challenges are invite-only. The creator can choose either win condition:

* **Max Actions** — up to 100 participants
* **Split Win** — no participant limit

### Bet Challenges

A **Bet** challenge is a stake-to-compete format. Everyone who joins puts in the same amount of B3TR, which goes into a shared pot held by B3MO. Whoever completes the most actions when the challenge ends takes the entire pot.

{% hint style="info" %}
Bet challenges are **always private** and **always use Max Actions**. You can only join if the creator invites you. Up to 100 participants.
{% endhint %}

#### Rules

* Everyone stakes the same amount to enter
* Maximum 100 participants
* Always private — invite only

{% hint style="success" icon="dash" %}
**Example:** Five colleagues each stake 1,000 B3TR into a private Bet challenge — that's a 5,000 B3TR prize pool. Over two weeks, B3MO tracks their activity across VeBetter apps. The colleague who racks up the most actions wins the full 5,000 B3TR.
{% endhint %}

### At a Glance

* **Sponsored (Public):** Split Win only · No participant limit
* **Sponsored (Private):** Max Actions (100 max) or Split Win (no limit)
* **Bet (Private only):** Max Actions · Max 100 participants


# Smart Contracts

List and description of all smart contracts of VeBetter.

Contracts can be found at the following repository: <https://github.com/vechain/vebetterdao-contracts>

The VeBetter smart contracts have undergone a comprehensive audit by [Hacken](https://hacken.io/).

{% file src="/files/QdKI3aQjbCobARar2lYD" %}

Putting it all together we get a picture of the connections of all smart contracts with hierarchies and usages between each other.

{% file src="/files/LqVNg0gJ2w4gFZC7oEr7" %}

The following is the list of all smart contracts listed alphabetically:

## B3TR

This contract governs the issuance and management of B3TR fungible tokens within the VeBetter ecosystem, allowing for minting under a capped total supply.

*Extends ERC20 Token Standard with capping, pausing, and access control functionalities to manage B3TR tokens in the VeBetter ecosystem.*

`Address: 0x5ef79995FE8a89e0812330E4378eB2660ceDe699`

## B3TRProxy

This contract implements an upgradeable proxy for all of our upgradeable contracts. It is upgradeable because calls are delegated to an implementation address that can be changed. This address is stored in storage in the location specified by <https://eips.ethereum.org/EIPS/eip-1967\\[EIP1967>], so that it doesn't conflict with the storage layout of the implementation behind the proxy.

*Forked from Openzeppelin.*

## B3TRGovernor

This contract is the main governance contract for the VeBetter ecosystem. Anyone can create a proposal to both change the state of the contract, to execute a transaction on the timelock or to ask for a vote from the community without performing any on-chain action. In order for the proposal to become active, the community needs to deposit a certain amount of VOT3 tokens. This is used as a heath check for the proposal, and funds are returned to the depositors after vote is concluded. Votes for proposals start periodically, based on the allocation rounds (see xAllocationVoting contract), and the round in which the proposal should be active is specified by the proposer during the proposal creation.

A minimum amount of voting power is required in order to vote on a proposal. The voting power is calculated through the quadratic vote formula based on the amount of VOT3 tokens held by the voter at the block when the proposal becomes active.

Once a proposal succeeds, it can be executed by the timelock contract.

The contract is upgradeable and uses the UUPS pattern.

*Manages the governance process for the VeBetter ecosystem, allowing users to create and vote on proposals with VOT3 token deposits. This contract leverages OpenZeppelin's AccessControl and UUPSUpgradeable libraries for role-based access control and upgradeability. The core functionality, including proposal management, voting mechanisms, quorum calculations, and deposit logic, is modularly organized in external libraries, ensuring maintainability, flexibility, and ease of upgrades.*

`Address: 0x1c65C25fABe2fc1bCb82f253fA0C916a322f777C`

## Emissions

This contract is responsible for the scheduled distribution of emissions based on predefined cycles and decay settings.

*Manages the periodic distribution of B3TR tokens to XAllocation, Vote2Earn, and Treasury allocations. This contract leverages openzeppelin's AccessControl, ReentrancyGuard, and UUPSUpgradeable libraries for access control, reentrancy protection, and upgradability.*

`Address: 0xDf94739bd169C84fe6478D8420Bb807F1f47b135`

## GalaxyMember

This contract manages the unique assets owned by users within the Galaxy Member ecosystem.

*Extends ERC721 Non-Fungible Token Standard basic implementation with upgradeable pattern, burnable, pausable, and access control functionalities.*

`Address: 0x93B8cD34A7Fc4f53271b9011161F7A2B5fEA9D1F`

## NodeManagement

{% hint style="warning" %}

#### **Legacy contract**

This contract is part of the legacy node system. Active participation now uses StarGate staking NFTs.

[https://docs.stargate.vechain.org/](https://docs.stargate.vechain.org/?utm_source=chatgpt.com)
{% endhint %}

This contract acts as a proxy between VeChain Node Contracts and VeBetter, enabling node holders to delegate and manage multiple nodes within a single account.

`Address: 0xB0EF9D89C6b49CbA6BBF86Bf2FDf0Eee4968c6AB`

## Timelock

This contract is used to perform the actions of the B3TRGovernor contract with a time delay. The proposers and executors roles should be assigned only to the B3TRGovernor contract.

`Address: 0x7B7EaF620d88E38782c6491D7Ce0B8D8cF3227e4`

## Treasury

This contract is designed to manage all assets owned by the VeBetter

*This contract handles the receiving and transferring of assets, leveraging upgradeable, pausable, and access control features.*

`Address: 0xD5903BCc66e439c753e525F8AF2FeC7be2429593`

## VOT3

This contract governs the issuance and management of VOT3 tokens, which are the tokens used for voting in the VeBetter Ecosystem.

*Extends ERC20 Fungible Token Standard basic implementation with upgradeability, pausability, ability for gasless transactions and governance capabilities.*

`Address: 0x76Ca782B59C74d088C7D2Cce2f211BC00836c602`

## VoterRewards

This contract handles the rewards for voters in the VeBetter ecosystem. It calculates the rewards for voters based on their voting power and the level of their Galaxy Member NFT.

The contract is

* upgradeable using UUPSUpgradeable.
* using AccessControl to handle the admin and upgrader roles.
* using ReentrancyGuard to prevent reentrancy attacks.
* using Initializable to initialize the contract.
* following the ERC-7201 standard for storage layout.

`Address: 0x838A33AF756a6366f93e201423E1425f67eC0Fa7`

## X2EarnApps

This contract handles the x-2-earn applications of the VeBetter ecosystem. The contract allows the insert, management, and eligibility of apps for the B3TR allocation rounds.

*The contract is using AccessControl to handle the admin and upgrader roles. Only users with the DEFAULT\_ADMIN\_ROLE can add new apps, set the base URI, and set the voting eligibility for an app. Admins can also control the app metadata and management. Each app has a set of admins and moderators (built without using AccessControl) that can manage the app metadata and management.*

`Address: 0x8392B7CCc763dB03b47afcD8E8f5e24F9cf0554D`

## X2EarnCreators

This contract is designed to manage new XApp submissions within VeBetter, ensuring only verified creators can enter the ecosystem. This contract supports **Creator NFTs**, non-transferable ERC721 tokens, to grant creators access to the endorsement process.

*Extends ERC721 Non-Fungible Token Standard basic implementation with upgradeable pattern, pausable, and access control functionalities.*

`Address: 0xe8e96a768ffd00417d4bd985bec9EcfC6F732a7f`

## X2EarnRewardsPool

This contract is used by x2Earn apps to reward users that performed sustainable actions. The XAllocationPool contract or other contracts/users can deposit funds into this contract by specifying the app that can access the funds.

Admins of x2Earn apps can withdraw funds from the rewards pool, which are sent to the team wallet address. The contract is upgradeable through the UUPS proxy pattern and UPGRADER\_ROLE can authorize the upgrade.

`Address: 0x6Bee7DDab6c99d5B2Af0554EaEA484CE18F52631`

## XAllocationPool

This contract receives B3TR tokens from the Emissions contract and distributes them to the rewards pool contract and x2earn apps based on the allocation round outcome. Funds can be claimed at the end of each allocation round.

*Interacts with the Emissions contract to get the amount of B3TR available for distribution in each round, and the x2EarnApps contract to check app existence and receiver address. The contract is using AccessControl to handle roles for upgrading the contract and external contract addresses.*

`Address: 0x4191776F05f4bE4848d3f4d587345078B439C7d3`

## XAllocationVoting

This contract handles the voting for the most supported x2Earn applications through periodic allocation rounds. The user's voting power is calculated on his VOT3 holdings at the start of each round, using a "Quadratic Funding" formula.

*Rounds are started by the Emissions contract. Interacts with the X2EarnApps contract to get the app data (eg: app IDs, app existence, eligible apps for each round). Interacts with the VotingRewards contract to save the user from casting a vote. The contract is using AccessControl to handle roles for admin, governance, and round-starting operations.*

`Address: 0x89A00Bb0947a30FF95BEeF77a66AEdE3842Fe5B7`

## B3TR Multisig

The **B3TR Multisig** contract facilitates multisignature operations for enhanced security and collaborative management of the wallet. This contract requires approvals from multiple stakeholders before any transaction can be executed, ensuring that all actions are transparent and consensual.

This contract is not upgradable.

## Dynamic Base Allocation Pool

This contract receives surplus B3TR allocations from XAllocationPool, and was created to execute the following proposal: <https://governance.vebetterdao.org/proposals/24829756257606634701400089449417807964640877888736006394567167792281000041364>

Initially acts as a wallet/treasury where the VeBetter team can manually distribute surplus allocations to eligible apps.

`Address: 0x98c1d097c39969bb5de754266f60d22bd105b368`

## Relayer Rewards Pool

This contract manages the reward distribution system for relayers who facilitate auto-voting functionality in the VeBetter ecosystem. Relayers perform voting actions on behalf of users who have enabled auto-voting, and earn proportional rewards based on their completed voting actions.

The pool accumulates fees collected from voter rewards when users participate through the auto-voting mechanism. Relayers can claim their proportional share of rewards based on the number of weighted voting actions they successfully complete during each round.

`Address: 0x34b56f892c9e977b9ba2e43ba64c27d368ab3c86`

## NavigatorRegistry

This contract manages the Navigator delegation system for VeBetterDAO. Navigators are professional voting delegates who stake B3TR to vote on behalf of citizens in both allocation rounds and governance proposals. Staked B3TR is converted to VOT3 under the hood and counts as the navigator's personal voting power.

The contract handles navigator registration with B3TR staking, citizen delegation with checkpointed VOT3 amounts, voting preferences and governance decisions, a 20% fee on managed rewards (locked for 4 rounds), automatic minor slashing for missed duties, and a governance-driven exit/deactivation process with lazy invalidation of citizen delegations.

*Upgradeable via UUPS proxy pattern. Logic split into 6 external libraries (NavigatorStakingUtils, NavigatorDelegationUtils, NavigatorVotingUtils, NavigatorFeeUtils, NavigatorSlashingUtils, NavigatorLifecycleUtils) for contract size optimization. Uses ERC-7201 namespaced storage.*

`Address: 0xef238e33fc78ecc79beaf8386254a0fc67d048e0`

## Libraries

Some contracts (eg: B3TRGovernor) store their logic inside libraries to optimize the contract size. The following is the list of libraries we created and the addresses they are deployed to.

#### GovernorClockLogic

Library for managing the clock logic as specified in EIP-6372, with fallback to block numbers.

*This library interacts with the IVOT3 interface to get the clock time or mode.*

#### GovernorConfigurator

Library for managing the configuration of a Governor contract.

*This library provides functions to set and get various configuration parameters and contracts used by the Governor contract.*

#### GovernorDepositLogic

Library for managing deposits related to proposals in the Governor contract.

*This library provides functions to deposit and withdraw tokens for proposals, and to get deposit-related information.*

#### GovernorFunctionRestrictionsLogic

Library for managing function restrictions within the Governor contract.

*This library provides functions to whitelist or restrict functions that can be called by proposals.*

#### GovernorProposalLogic

Library for managing proposals in the Governor contract.

*This library provides functions to create, cancel, execute, and validate proposals.*

#### GovernorQuorumLogic

Library for managing quorum numerators using checkpointed data structures.

#### GovernorStateLogic

Library for Governor state logic, managing the state transitions and validations of governance proposals.

#### GovernorVotesLogic

Library for handling voting logic in the Governor contract.

## Contracts Upgradeability

We are using UUPS proxy for our upgradeable contracts. You can read more about it here:<https://docs.openzeppelin.com/contracts/5.x/api/proxy>.

#### Resources

{% embed url="<https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable>" %}

<table data-header-hidden><thead><tr><th width="211"></th><th width="182"></th><th></th></tr></thead><tbody><tr><td><strong>Contract</strong></td><td><strong>Upgradable</strong></td><td><strong>Authoriser</strong></td></tr><tr><td>B3TR</td><td>No</td><td></td></tr><tr><td>B3TRProxy</td><td>No</td><td></td></tr><tr><td>B3TRGovernor</td><td>Yes</td><td>Governance OR DEFAULT_ADMIN</td></tr><tr><td>Emissions</td><td>Yes</td><td>UPGRADER_ROLE</td></tr><tr><td>GalaxyMember</td><td>Yes</td><td>UPGRADER_ROLE</td></tr><tr><td>NodeManagement (legacy)</td><td>Yes</td><td>UPGRADER_ROLE</td></tr><tr><td>Timelock</td><td>Yes</td><td>UPGRADER_ROLE</td></tr><tr><td>Treasury</td><td>Yes</td><td>UPGRADER_ROLE</td></tr><tr><td>VOT3</td><td>Yes</td><td>UPGRADER_ROLE</td></tr><tr><td>VoterRewards</td><td>Yes</td><td>UPGRADER_ROLE</td></tr><tr><td>X2EarnApps</td><td>Yes</td><td>UPGRADER_ROLE</td></tr><tr><td>X2EarnCreators</td><td>Yes</td><td>UPGRADER_ROLE</td></tr><tr><td>X2EarnRewardsPool</td><td>Yes</td><td>UPGRADER_ROLE</td></tr><tr><td>XAllocationPool</td><td>Yes</td><td>UPGRADER_ROLE</td></tr><tr><td>XAllocationVoting</td><td>Yes</td><td>UPGRADER_ROLE</td></tr><tr><td>B3TR Multisig</td><td>No</td><td></td></tr><tr><td>GrantsManager</td><td>Yes</td><td>UPGRADER_ROLE</td></tr><tr><td>RelayersRewardsPool</td><td>Yes</td><td>UPGRADER_ROLE</td></tr><tr><td>DynamicBaseAllocationPool</td><td>Yes</td><td>UPGRADER_ROLE</td></tr><tr><td>RelayerRewardsPool</td><td>Yes</td><td>UPGRADER_ROLE</td></tr><tr><td>NavigatorRegistry</td><td>Yes</td><td>UPGRADER_ROLE</td></tr></tbody></table>

#### Library updates

In `B3TRGovernor`, we are utilising libraries inside some of the modules. To upgrade the functionalities inside these libraries the following steps must be done.

1. Update library
2. Deploy new library
3. Deploy new implementation contract connecting updated library with new library address
4. Upgrade the proxy to use this new implementation smart contract using the `upgradeToAndCall` function .


# Roles And Permissions

Roles define the permissions and access levels across different contracts and modules. This page outlines the structure of roles, their functions, and the path toward full decentralization.

To maintain a secure and flexible smart contract system, we leverage roles to manage administrative tasks and define who has the authority to perform specific actions. These roles control everything from minting tokens to upgrading contracts, pausing operations, and setting governance parameters.

The central goal of this structure is to gradually decentralize power from individual wallets to the DAO (the B3TRGovernor governance contract).

## Roles

This document categorizes roles and outlines their functionalities, detailing what permissions each role grants. Here's a quick summary of some common roles and what they do:

* **DEFAULT\_ADMIN\_ROLE**: The superuser role with the ability to grant, revoke, and renounce roles.
* **PAUSER\_ROLE**: Controls the ability to pause and unpause contract functionality.
* **MINTER\_ROLE**: Allows for token minting.
* **UPGRADER\_ROLE**: Permits contract upgrades and modifications.
* **CONTRACTS\_ADDRESS\_MANAGER\_ROLE**: Manages critical contract addresses.
* **DECAY\_SETTINGS\_MANAGER\_ROLE:** Manages parameters surrounding cycle lengths, allocation percentages and decay rates in the Emission contract.
* **GOVERNANCE\_ROLE**: Involved in governance decisions, proposal management, and voting.

All roles have in common the following functionality: they can renounce that role.

Once there isn’t any address that has the DEFAULT\_ADMIN\_ROLE then it won’t be possible to grant or revoke any role. If some contract is upgradeable and the DAO has the UPGRADER\_ROLE then the DAO could decide to upgrade the contract and assign the role to whoever they want.

## Permissions

The ultimate aim is to create a self-governing system where no single entity holds absolute control. This section of the page provides a detailed plan for achieving this goal, outlining the steps for transitioning roles to the B3TRGovernor contract, removing direct admin control, and enabling decentralized governance.

Follow the outlined steps to understand the current state of role assignments and the specific actions required to achieve a more autonomous system. Through this journey, we aim to establish a resilient and community-driven ecosystem where the power of decision-making rests in the hands of the DAO and its stakeholders.

## Contract: B3TR

| Role Name            | Functions                           | Function Descriptions                                    | Initial Assignees                    |
| -------------------- | ----------------------------------- | -------------------------------------------------------- | ------------------------------------ |
| DEFAULT\_ADMIN\_ROLE | grantRole, revokeRole, renounceRole | Grants or revokes roles; allows renunciation of its role | Admin Multi Signature                |
| PAUSER\_ROLE         | Pause, Unpause                      | Pauses or unpauses contract operations                   | ~~Admin Wallet~~                     |
| MINTER\_ROLE         | Mint                                | Mints new tokens                                         | ~~Admin Wallet~~, Emissions Contract |

#### **Steps for full decentralization:**

* [x] After we migrate to mainnet we revoke the MINTER\_ROLE from the admin wallet.
* [x] When we no longer want the power to pause the contract we revoke the PAUSER\_ROLE.
* [ ] We renounce the DEFAULT\_ADMIN\_ROLE

## Contract: B3TRGovernor

<table data-header-hidden><thead><tr><th width="193"></th><th width="206"></th><th></th><th></th></tr></thead><tbody><tr><td>Role Name</td><td>Functions</td><td>Function Descriptions</td><td>Initial Assignees</td></tr><tr><td>DEFAULT_ADMIN_ROLE</td><td><p>grantRole, revokeRole, renounceRole, cancel,</p><p>_authorizeUpgrade, relay, setDepositThreshold, setVotingThreshold, setMinVotingDelay, updateQuorumNumerator</p></td><td>Grants or revokes roles; allows renunciation of its role; cancel pending proposals;</td><td>Admin Wallet</td></tr><tr><td>PROPOSAL_EXECUTOR_ROLE</td><td>Execute</td><td>Executes queued proposals</td><td>Admin Wallet</td></tr><tr><td>PAUSER_ROLE</td><td>Pause, Unpause</td><td>Pauses or unpauses contract (no proposal creation, queuing, or execution)</td><td>Admin Wallet</td></tr><tr><td>GOVERNOR_FUNCTIONS_SETTINGS_ROLE</td><td>setWhitelistFunction, setWhitelistFunctions, setIsFunctionRestrictionEnabled</td><td>Whitelist function that people can trigger in their proposals, or disable this check.</td><td>Admin Wallet, BTRGovernor</td></tr><tr><td>CONTRACTS_ADDRESS_MANAGER_ROLE</td><td>setVoterRewards, setXAllocationVoting, updateTimelock</td><td>Manages contract addresses</td><td>Admin Wallet, BTRGovernor</td></tr></tbody></table>

#### **Steps for full decentralization:**

* [ ] B3TRGovernor is already responsible for upgrading, changing voting or deposit threshold, min voting delay, and quorum.
* [ ] We grant the GOVERNOR\_FUNCTIONS\_SETTINGS\_ROLE to the B3TRGovernor, and revoke it from the current wallet. Now governance can vote on whitelisting other functions or completely remove whitelisting of functions on proposal creation.
* [ ] We grant the CONTRACTS\_ADDRESS\_MANAGER\_ROLE to the B3TRGovernor, and revoke it from the current wallet.
* [ ] We renounce the PAUSER\_ROLE or grant it to the B3TRGovernor
* [ ] We renounce the DEFAULT\_ADMIN\_ROLE and PROPOSAL\_EXECUTOR\_ROLE

## Contract: Emissions

| Role Name                         | Functions                                                                                      | Function Descriptions                                     | Initial Assignees       |
| --------------------------------- | ---------------------------------------------------------------------------------------------- | --------------------------------------------------------- | ----------------------- |
| MINTER\_ROLE                      | Bootstrap, Start, renounceRole                                                                 | Allows minting of tokens, initializing processes          | ~~Admin Wallet~~        |
| DEFAULT\_ADMIN\_ROLE              | grantRole, revokeRole, renounceRole                                                            | Manages roles and contract parameters                     | Admin multisig contract |
| DECAY\_SETTINGS\_MANAGER\_ROLE    | setCycleDuration, setXAllocationsDecay, setVote2EarnDecay                                      | Sets emission cycle durations and related parameters      | Admin Wallet            |
|                                   | setXAllocationsDecayPeriod, setVote2EarnDecayPeriod                                            | Sets decay periods for various emission-related settings  |                         |
|                                   | setTreasuryPercentage, setScalingFactor, setMaxVote2EarnDecay                                  | Configures emission scaling factors and treasury settings |                         |
| CONTRACTS\_ADDRESS\_MANAGER\_ROLE | setXAllocationAddress, setVote2EarnAddress, setTreasuryAddress, setXAllocationsGovernorAddress | Configures addresses for key contracts                    | Admin Wallet            |
| UPGRADER\_ROLE                    | upgrade, renounceRole                                                                          | Allows contract upgrades                                  | ~~Admin Wallet~~        |

#### **Steps for full decentralization:**

* [x] We renounce the MINTER\_ROLE once we complete the mainnet migration
* [ ] We grant the UPGRADER\_ROLE to the B3TRGovernor and revoke it from the current wallet
* [ ] We grant the DEFAULT\_ADMIN\_ROLE to the B3TRGovernor and revoke it from the current wallet
* [ ] We grant the CONTRACTS\_ADDRESS\_MANAGER\_ROLE to the B3TRGovernor and revoke it from the current wallet
* [ ] We grant the **DECAY\_SETTINGS\_MANAGER\_ROLE** to the B3TRGovernor and revoke it from the current wallet

## Contract: GalaxyMember

| Role Name                         | Functions                                                                                        | Function Descriptions                                                          | Initial Assignees |
| --------------------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ | ----------------- |
| DEFAULT\_ADMIN\_ROLE              | setMaxLevel, setMaxMintableLevels, setBaseURI, setB3TRtoUpgradeToLevel, setIsPublicMintingPaused | Sets contract parameters for levels, minting, and URI, Controls public minting | Admin Wallet      |
| UPGRADER\_ROLE                    | Upgrade                                                                                          | Allows contract upgrades                                                       | Admin Wallet      |
| PAUSER\_ROLE                      | Pause, Unpause                                                                                   | Pauses and unpauses the contract                                               | Admin Wallet      |
| MINTER\_ROLE                      | Mint                                                                                             | Mint tokens for migration purposes                                             | Admin Wallet      |
| CONTRACTS\_ADDRESS\_MANAGER\_ROLE | setXAllocationsGovernorAddress, setB3trGovernorAddress                                           | Configures critical contract addresses                                         | Admin Wallet      |

#### **Steps for full decentralization:**

* [x] We renounce the MINTER\_ROLE once we complete the mainnet migration
* [ ] We grant the UPGRADER\_ROLE to the B3TRGovernor and revoke it from the current wallet
* [ ] We grant the CONTRACTS\_ADDRESS\_MANAGER\_ROLE to the B3TRGovernor and revoke it from the current wallet
* [ ] We renounce the PAUSER\_ROLE
* [ ] We grant the DEFAULT\_ADMIN\_ROLE to the B3TRGovernor and revoke it from the current wallet

## Contract: Timelock

| Role Name            | Functions                           | Function Descriptions                                        | Initial Assignees               |
| -------------------- | ----------------------------------- | ------------------------------------------------------------ | ------------------------------- |
| DEFAULT\_ADMIN\_ROLE | grantRole, revokeRole, renounceRole | Grants or revokes roles; allows renunciation of its own role | Admin Wallet, Timelock contract |
| Proposer             | schedule, cancel                    | Proposes, schedules, and cancels transactions                | B3TRGovernor                    |
| Executor             | Execute                             | Executes approved proposals and transactions                 | B3TRGovernor                    |
| UPGRADER\_ROLE       | upgrade                             | Allows contract upgrades                                     | Admin Wallet                    |

#### **Steps for full decentralization:**

* [ ] We grant the UPGRADER\_ROLE to the B3TRGovernor and revoke it from current wallet
* [ ] We renounce the DEFAULT\_ADMIN\_ROLE and now Timelock is self-administrating, which means that if the DAO wants to change the proposer or executor they will need to create a proposal that calls the Timelock contract to grant/revoke that role

## Contract: Treasury

| Role Name            | Functions                                             | Function Descriptions                           | Initial Assignees |
| -------------------- | ----------------------------------------------------- | ----------------------------------------------- | ----------------- |
| DEFAULT\_ADMIN\_ROLE | grantRole, revokeRole, renounceRole                   | Grants/revokes roles; can renounce its own role | Admin Wallet      |
| GOVERNANCE\_ROLE     | transferVTHO, transferB3TR, transferVOT3, transferVET | Manages VOT3, B3TR, VET and VTHO transfers      | B3TRGovernor      |
|                      | transferTokens, transferNFT                           | Manages NFT and ERC20 token transfers           |                   |
|                      | stakeB3TR, unstakeB3TR                                | Manages staking and unstaking                   |                   |
| PAUSER\_ROLE         | Pause, Unpause                                        | Pauses and unpauses contract operations         | Admin Wallet      |
| UPGRADER\_ROLE       | Upgrade                                               | Allows contract upgrades                        | Admin Wallet      |

#### **Steps for full decentralization:**

* [ ] The B3TRGovernor already has the GOVERNANCE\_ROLE, if we have some admin that has this role then we need to renounce it
* [ ] We grant the UPGRADER\_ROLE to the B3TRGovernor and revoke it from the current wallet
* [ ] We renounce the PAUSER\_ROLE
* [ ] We can grant the DEFAULT\_ADMIN\_ROLE to the B3TRGovernor or renounce it

## Contract: VOT3

| Role Name            | Functions                           | Function Descriptions                                    | Initial Assignees |
| -------------------- | ----------------------------------- | -------------------------------------------------------- | ----------------- |
| DEFAULT\_ADMIN\_ROLE | grantRole, revokeRole, renounceRole | Grants or revokes roles; allows renunciation of its role | Admin Wallet      |
| UPGRADER\_ROLE       | Upgrade                             | Allows contract upgrades                                 | Admin Wallet      |
| PAUSER\_ROLE         | Pause, Unpause                      | Pauses or unpauses contract operations                   | Admin Wallet      |

#### **Steps for full decentralization:**

* [ ] We grant the UPGRADER\_ROLE to the B3TRGovernor and revoke it from the current wallet.
* [ ] When we no longer want the power to pause the contract we revoke the PAUSER\_ROLE.
* [ ] We renounce the DEFAULT\_ADMIN\_ROLE role.

## Contract: VoterRewards

| Role Name                         | Functions                              | Function Descriptions                        | Initial Assignees               |
| --------------------------------- | -------------------------------------- | -------------------------------------------- | ------------------------------- |
| DEFAULT\_ADMIN\_ROLE              | setLevelToMultiplier, setScalingFactor | Sets reward scaling factors and levels       | Admin Wallet                    |
| UPGRADER\_ROLE                    | Upgrade                                | Allows contract upgrades                     | Admin Wallet                    |
| VOTE\_REGISTRAR\_ROLE             | registerVote                           | Registers user votes for rewards             | XAllocationVoting, B3TRGovernor |
|                                   | setVoteRegistrarRole                   | Assigns who has permission to register votes |                                 |
| CONTRACTS\_ADDRESS\_MANAGER\_ROLE | setEmissions, setGalaxyMember          | Sets key contract addresses                  | Admin Wallet                    |

#### **Steps for full decentralization:**

* [ ] VOTE\_REGISTRAR\_ROLE should be assigned only to the contracts performing voting
* [ ] We grant the UPGRADER\_ROLE to the B3TRGovernor and revoke it from the current wallet
* [ ] We grant the CONTRACTS\_ADDRESS\_MANAGER\_ROLE to the B3TRGovernor and revoke it from the current wallet
* [ ] We grant the DEFAULT\_ADMIN\_ROLE to the B3TRGovernor and revoke it from current wallet

## Contract: X2EarnApps

| Role Name            | Functions                          | Function Descriptions                          | Initial Assignees |
| -------------------- | ---------------------------------- | ---------------------------------------------- | ----------------- |
| DEFAULT\_ADMIN\_ROLE | setBaseURI, UpdateAppMetadata      | Configures base URI and updates app metadata   | Admin Wallet      |
|                      | Update receiver address/ app admin | Sets or updates app receiver address and admin |                   |
|                      | Add/Remove app moderators          | Manages app moderators                         |                   |
| UPGRADER\_ROLE       | Upgrade                            | Allows contract upgrades                       | Admin Wallet      |
| GOVERNANCE\_ROLE     | Add app, setVotingEligibility      | Adds new apps and defines voting eligibility   | Admin Wallet      |

#### **Steps for full decentralization:**

* [ ] We grant the UPGRADER\_ROLE to the B3TRGovernor and revoke it from the current wallet
* [ ] We grant the GOVERNANCE\_ROLE to the B3TRGovernor and revoke it from current wallet
* [ ] We grant the DEFAULT\_ADMIN\_ROLE to the B3TRGovernor and revoke it from current wallet

**NB**: This contract will be upgraded to handle app endorsement, so the “Add app” functionality triggered by a GOVERNANCE\_ROLE could be removed in a future release

## Contract: X2EarnRewardsPool

| Role Name                         | Functions     | Function Descriptions                     | Initial Assignees |
| --------------------------------- | ------------- | ----------------------------------------- | ----------------- |
| DEFAULT\_ADMIN\_ROLE              |               |                                           | Admin Wallet      |
| UPGRADER\_ROLE                    | Upgrade       | Allows contract upgrades                  | Admin Wallet      |
| CONTRACTS\_ADDRESS\_MANAGER\_ROLE | setX2EarnApps | Update the contract address of X2EarnApps | Admin Wallet      |

#### **Steps for full decentralization:**

* [ ] We grant the UPGRADER\_ROLE to the B3TRGovernor and revoke it from the current wallet
* [ ] We grant the CONTRACTS\_ADDRESS\_MANAGER\_ROLE to the B3TRGovernor and revoke it from the current wallet
* [ ] We renounce the DEFAULT\_ADMIN\_ROLE role

## Contract: XAllocationPool

| Role Name                         | Functions                                                                                  | Function Descriptions               | Initial Assignees |
| --------------------------------- | ------------------------------------------------------------------------------------------ | ----------------------------------- | ----------------- |
| DEFAULT\_ADMIN\_ROLE              | grantRole, revokeRole, renounceRole                                                        | Grants, revokes, or renounces roles | Admin Wallet      |
| UPGRADER\_ROLE                    | Upgrade                                                                                    | Allows contract upgrades            | Admin Wallet      |
| CONTRACTS\_ADDRESS\_MANAGER\_ROLE | setXAllocationVotingAddress, setEmissionsAddress, setTreasuryAddress, setX2EarnAppsAddress | Manages key contract addresses      | Admin Wallet      |

#### **Steps for full decentralization:**

* [ ] We grant the UPGRADER\_ROLE to the B3TRGovernor and revoke it from the current wallet
* [ ] We grant the CONTRACTS\_ADDRESS\_MANAGER\_ROLE to the B3TRGovernor and revoke it from the current wallet
* [ ] We grant the DEFAULT\_ADMIN\_ROLE to the B3TRGovernor and revoke it from current wallet

## Contract: XAllocationVoting

| Role Name                         | Functions                                                         | Function Descriptions                      | Initial Assignees          |
| --------------------------------- | ----------------------------------------------------------------- | ------------------------------------------ | -------------------------- |
| DEFAULT\_ADMIN\_ROLE              | grantRole, revokeRole, renounceRole                               | Grants, revokes, or renounces roles        | Admin Wallet               |
| UPGRADER\_ROLE                    | Upgrade                                                           | Allows contract upgrades                   | Admin Wallet               |
| ROUND\_STARTER\_ROLE              | startNewRound                                                     | Initiates a new voting round               | Emissions Contract         |
| GOVERNANCE\_ROLE                  | setVotingThreshold, setAppSharesCap                               | Sets parameters for voting                 | Admin Wallet, B3TRGovernor |
|                                   | setBaseAllocationPercentage, setVotingPeriod                      | Establishes voting periods and percentages |                            |
|                                   | updateQuorumNumerator                                             | Updates quorum requirements                |                            |
| CONTRACTS\_ADDRESS\_MANAGER\_ROLE | setX2EarnAppsAddress, setEmissionsAddress, setVoterRewardsAddress | Manages key contract addresses             | Admin Wallet               |

#### **Steps for full decentralization:**

* [ ] ROUND\_STARTER\_ROLE should always be the Emissions contract
* [ ] Renaunce GOVERNANCE\_ROLE
* [ ] We grant the UPGRADER\_ROLE to the B3TRGovernor and revoke it from the current wallet
* [ ] We grant the CONTRACTS\_ADDRESS\_MANAGER\_ROLE to the B3TRGovernor and revoke it from the current wallet
* [ ] We grant the DEFAULT\_ADMIN\_ROLE to the B3TRGovernor and revoke it from current wallet

## Contract: Dynamic Base Allocation Pool

| Role Name            | Functions                           | Function Descriptions               | Initial Assignees |
| -------------------- | ----------------------------------- | ----------------------------------- | ----------------- |
| DEFAULT\_ADMIN\_ROLE | grantRole, revokeRole, renounceRole | Grants, revokes, or renounces roles | Admin Wallet      |
| UPGRADER\_ROLE       | Upgrade                             | Allows contract upgrades            | Admin Wallet      |
| DISTRIBUTOR\_ROLE    | distributeDBARewards                | Sends to surplus allocation to apps | Admin Wallet      |

#### **Steps for full decentralization:**

* [ ] We grant the UPGRADER\_ROLE to the B3TRGovernor and revoke it from the current wallet
* [ ] We grant the DEFAULT\_ADMIN\_ROLE to the B3TRGovernor and revoke it from current wallet
* [ ] We update the contract to filter eligible apps onchain avoiding where everyone can trigger the distribution function and we can get rid of the DISTRIBUTOR\_ROLE


# Trust Assumptions

## Emissions

The parameters related to emissions are adjustable; however, modifying them without careful consideration could negatively impact the overall emissions. It is crucial to maintain these settings as stable as possible.

## Roles and Security

Our DAO has multiple roles, each with its admin powers, which presents a potential vector for attack. We acknowledge this risk and have implemented best practices for securing the private keys associated with these roles. These measures are crucial in protecting our system from unauthorized access and potential security breaches.

## Initial centralization

We are committed to gradually transitioning to a fully decentralized system. This transition aims to reduce the reliance on centralized admin powers, thereby enhancing the security and robustness of our governance structure. The move towards decentralization is a deliberate process to ensure stability and maintain trust as we shift control from centralized figures to the DAO members.


# Navigators

Navigators are trusted community members who vote on allocation rounds and governance proposals on behalf of citizens who delegate VOT3 to them.

## Why Navigators?

Not everyone can follow every app and every proposal each round. Navigators provide active curation and accountability — they stake B3TR as skin in the game, publish their allocation rationale each round, and adjust strategy based on ecosystem developments.

This is different from auto-voting, which simply repeats past patterns. Navigators are expected to actively curate their votes, explain decisions, and submit reports. Citizens can compare different Navigators' philosophies and track records before choosing one.

Citizens must maintain a valid VePassport (personhood) to have their navigator votes cast. If a citizen's passport is invalid at the round snapshot, their vote is skipped for that round and they will not earn rewards.

## Rewards Multipliers

Alongside Navigators, VeBetterDAO introduces two rewards multipliers to incentivize active participation:

### Freshness Bonus (Allocation Voting)

* If you update your app selection this round: **3x** rewards
* If you updated recently (but not this round): **2x** rewards
* If you keep voting the same app set for many rounds: **1x** rewards
* First-time voters start with the highest freshness bonus (**3x**)

### Governance Intent Bonus (Proposal Voting)

* Voting **For** or **Against** governance proposals: full rewards
* Voting **Abstain**: reduced rewards (**0.3x** for that proposal)

These multipliers affect **rewards only** — they do not change your actual voting power or token balance. Your Galaxy Member multiplier still applies on top.

## For Citizens

See [For Citizens](/navigators/for-citizens) to learn how delegation works, what happens to your VOT3, and how rewards are calculated.

## For Navigators

See [For Navigators](/navigators/for-navigators) to learn about registration, duties, penalties, and the exit process.

## For Developers

See [For Developers](/navigators/for-developers) for contract architecture, key functions, and integration details.


# For Citizens

This page explains what happens when you delegate to a Navigator.

## How to Delegate

1. Choose a Navigator you trust
2. Choose how much **VOT3** to delegate
3. Confirm delegation

You can delegate to **one Navigator at a time**.

## What Happens to Your VOT3

* Your VOT3 **stays in your wallet**
* The delegated portion becomes **locked** while delegated
* Locked VOT3 cannot be transferred or converted until you undelegate
* Your wallet balance still shows your full amount; only the unlocked portion is transferable
* Your **voting power** is your delegated VOT3 amount only — undelegated VOT3 does not count toward voting power while you are delegated
* Voting power is snapshotted at the start of each round

## How Voting Works While Delegated

* Your Navigator votes for you in allocation rounds and governance proposals
* You cannot cast manual votes while delegated — you must undelegate first
* Your voting outcomes follow your Navigator's decisions

## Rewards and Fees

* Rewards are based on your **delegated amount**, not your full VOT3 balance
* Your own **Galaxy Member** level still applies
* A **20% Navigator fee** is deducted automatically from rewards you earn through managed votes
* Rewards are automatically claimed for you by relayers

## Passport Requirement

You must hold a valid **VePassport** (personhood) to have your navigator votes cast. Passport validity is checked at the **round snapshot** — the moment the round starts.

* If your passport is **valid** at the snapshot: your navigator votes normally on your behalf
* If your passport is **invalid** at the snapshot: your vote is **skipped** for that round and you will not earn rewards

To maintain eligibility, keep performing sustainable actions through VeBetterDAO apps. If your passport lapses, re-establish it before the next round starts.

## Switching or Leaving

* You can reduce delegation, fully undelegate, or switch to another Navigator
* Changes take effect from the next round
* If your Navigator exits or is removed, your delegation is automatically released and your VOT3 unlocks — no action needed on your part

## How to Evaluate a Navigator

Before delegating, check:

* Voting history and consistency
* Published reports and rationale
* Freshness behavior (active updates vs stale patterns)
* Governance activity
* Number of citizens and total delegated amount
* Stake level and overall credibility

## FAQ

### Do I lose custody of my VOT3 when I delegate?

No. Your VOT3 remains in your wallet. It is only locked while delegated.

### Can I vote manually while delegated?

No. You must undelegate first.

### Can I switch Navigators?

Yes. You can switch, and the change applies from the next round.

### What happens if my VePassport is invalid?

Your vote is skipped for that round and you earn no rewards. Other citizens delegated to the same Navigator are not affected. Regain a valid passport before the next round to resume participation.

### What if my Navigator stops participating?

Anyone can report round misconduct on-chain. If reports are valid, the Navigator can be penalized.

### Can I support a governance proposal with my delegated VOT3?

No. You must undelegate first. Only undelegated VOT3 can be used for proposal support deposits.


# For Navigators

This page explains what you commit to when you register as a Navigator.

## Becoming a Navigator

To register, you:

* Stake at least **50,000 B3TR**
* Fill in your motivation and background
* Add disclosures and social links
* Accept Navigator responsibilities and terms

Registration is permissionless — anyone who meets the minimum stake can register.

## Your Capacity

* Capacity follows a **10:1 ratio** — every 1 B3TR staked supports up to 10 VOT3 delegated
* More stake means more delegation capacity
* Maximum stake is **1% of VOT3 total supply** (enforced at deposit time only)
* If your current delegations are high, you may be blocked from reducing stake

## Your Duties

You are expected to:

* **Maintain your stake above the minimum** at all times — if your stake drops below minimum (e.g. due to slashing), you must top it up immediately or face further penalties
* Set allocation preferences each round
* Vote on governance proposals relevant to your citizens
* Submit a report at least once every 2 rounds
* Complete your tasks before the cutoff deadline (about 24 hours before round end)

## Citizen Passport Validity

Citizens must hold a valid VePassport (personhood) at the round snapshot for their navigator vote to be cast. If a citizen's passport is invalid at that time, their vote is **skipped** — this does not affect your other citizens or trigger any penalty against you.

## Your Rewards

* You earn a **20% fee** from rewards generated by votes you manage
* Fees are locked for **4 rounds** before they can be claimed

### Staking and Voting Power

* Staked B3TR is **converted to VOT3 under the hood** and counts as your personal voting power
* Your total voting power = personal VOT3 balance + staked B3TR (as VOT3)
* Staked B3TR does not earn direct rewards
* The staked VOT3 cannot be used to support proposals or be powered down — it only counts for voting

## Penalties for Missing Duties

If you miss duties, anyone can report the round on-chain:

* Minor penalties are applied **at most once per round**
* If a round is validly reported, you can be slashed **5%** of your remaining stake for that round
* Typical minor issues include: missed votes, missed reports, stale preferences, or late preferences
* Even if multiple issues happened in the same round, only one 5% penalty is applied
* **Being below minimum stake is itself a slashable infraction** — if your stake drops below minimum (e.g. from a previous slash), you have **until the end of the round** to top it up. If you don't recover by round end, you will be slashed again. Example: slashed in round 3 (50K → 47.5K), you have all of round 4 to add stake. If you top up to 50K+ during round 4, no penalty. If you don't, you get slashed again at round 4 end.
* While below minimum stake, you cannot accept new delegations

For severe misconduct, governance can remove you and slash up to 100% of stake plus locked fees.

## Exiting

* You announce exit with a **1-round notice**
* Duties still apply during notice
* After notice, you can withdraw stake
* Citizens are automatically released (their delegated VOT3 unlocks)

## FAQ

### Does my staked B3TR increase my voting power?

Yes. Your staked B3TR is converted to VOT3 under the hood and counts as your personal voting power. It cannot be used to support proposals or powered down — it is only for voting.

### Do I control citizens' wallets?

No. Citizens keep custody of their VOT3 in their own wallets.

### Can I still be penalized if I vote late?

Yes. Late preferences can be reported and penalized.

### Can I stop immediately?

No. You must announce exit and complete the notice period.


# For Developers

Technical reference for the Navigator system contracts.

## Architecture

The Navigator system is implemented across several contracts:

| Contract               | Role                                                                                                |
| ---------------------- | --------------------------------------------------------------------------------------------------- |
| **NavigatorRegistry**  | Central contract — registration, staking, delegation, voting preferences, fees, slashing, lifecycle |
| **XAllocationVoting**  | `castNavigatorVote(citizen, roundId)` — allocation votes for delegated citizens                     |
| **B3TRGovernor**       | `castNavigatorVote(proposalId, citizen)` — governance votes for delegated citizens                  |
| **VoterRewards**       | Deducts navigator fee at claim time, deposits to NavigatorRegistry escrow                           |
| **VOT3**               | Transfer lock for delegated amounts, B3TR-to-VOT3 conversion for navigator staking                  |
| **RelayerRewardsPool** | Per-user skip tracking, governance action registration                                              |

NavigatorRegistry is a UUPS upgradeable contract with logic split into 6 external libraries: NavigatorStakingUtils, NavigatorDelegationUtils, NavigatorVotingUtils, NavigatorFeeUtils, NavigatorSlashingUtils, NavigatorLifecycleUtils.

## Staking and B3TR-to-VOT3 Conversion

When a navigator stakes B3TR, the NavigatorRegistry converts it to VOT3 under the hood via `VOT3.convertToVOT3()`. This makes the staked amount count as voting power through the ERC20Votes checkpoint system.

* NavigatorRegistry self-delegates on VOT3 during initialization (`VOT3.delegate(address(this))`)
* Per-navigator staked amounts are tracked with `Checkpoints.Trace208` for snapshot queries
* On withdrawal or slashing, VOT3 is converted back to B3TR via `VOT3.convertToB3TR()`
* The staked VOT3 only counts for voting power — it cannot support proposals or be powered down

### Voting Power Calculation

`VotesUtils.getVotes()` (allocation) and `GovernorVotesLogic.getVotes()` (governance) both include `NavigatorRegistry.getStakedAmountAtTimepoint(account, timepoint)` for non-delegated users. This returns 0 for non-navigators, so no conditional check is needed.

## Delegation

Citizens delegate a specific VOT3 amount to one navigator at a time. The delegated amount is:

* **Locked** — VOT3 `_update()` reads `NavigatorRegistry.getDelegatedAmount(from)` to enforce transfer lock
* **Checkpointed** — `Checkpoints.Trace208` for snapshot-based voting power
* **Snapshotted at round start** — mid-round changes take effect next round

### Key Functions

| Function                      | Description                                 |
| ----------------------------- | ------------------------------------------- |
| `delegate(navigator, amount)` | First-time delegation                       |
| `increaseDelegation(amount)`  | Add more VOT3 to current delegation         |
| `reduceDelegation(amount)`    | Reduce delegation (takes effect next round) |
| `undelegate()`                | Full removal                                |

## Voting Mechanics

### Allocation Voting

Two separate functions (NOT merged):

* `castVoteOnBehalfOf(voter, roundId)` — existing auto-voting flow (unchanged)
* `castNavigatorVote(citizen, roundId)` — for delegated citizens. Voting power = delegated amount at round snapshot. Navigator's app preferences and percentages are applied.

Navigator setting preferences (`setAllocationPreferences`) also counts as their own allocation vote.

### Governance Voting

`B3TRGovernor.castNavigatorVote(proposalId, citizen)`:

* Citizen must be delegated to a navigator at proposal snapshot
* Navigator must have set a decision (1=Against, 2=For, 3=Abstain)
* Voting power = delegated amount at proposal snapshot
* Intent multiplier applied for rewards

### Skip-or-Vote Logic

Both allocation and governance `castNavigatorVote` functions include built-in skip logic:

1. Navigator dead at snapshot: revert `NotDelegatedToNavigator`
2. Citizen not a person at snapshot (invalid VePassport): skip immediately, reduce expected actions
3. Navigator dead now (exited/deactivated after snapshot): skip immediately, reduce expected actions
4. Navigator alive + preferences/decision set: vote normally
5. Navigator alive + no preferences/decision + skip window reached (2 hours before deadline): skip
6. Navigator alive + no preferences/decision + skip window not reached: revert (relayer retries later)

## Rewards and Fees

Fee ordering at claim time:

1. **Navigator fee** = gross reward x feePercentage / 10000 (goes to NavigatorRegistry escrow)
2. **Relayer fee** = calculated on remainder (goes to RelayerRewardsPool)
3. **Citizen** receives the rest

Navigator fees are locked for a configurable number of rounds (default 4) before the navigator can claim them.

## Slashing

### Minor Slashing

Anyone can call `reportRoundInfractions(navigator, roundId, proposalIds)` after a round ends. The contract checks all six infraction types on-chain:

1. Missed allocation vote (requires delegations at round snapshot)
2. Late preferences — set after cutoff (requires delegations)
3. Stale preferences — no update for 3+ rounds (requires delegations)
4. Missed report — must submit every N rounds (requires delegations)
5. Missed governance vote (requires delegations)
6. **Below minimum stake** — stake was below `minStake` at round start AND still below at round end (applies **regardless of delegations**)

Infractions 1-5 are only evaluated if the navigator had active delegations at the round snapshot. Infraction 6 applies to all registered navigators — maintaining the minimum stake is an unconditional duty. The two-checkpoint check (start + end) gives navigators **one full round to recover** after a slash drops their stake.

If any infraction is found, one minor slash is applied: **5% of current remaining stake** (compounding). At most one slash per round.

#### Below minimum stake — timing example

Assume `minStake = 50,000 B3TR` and minor slash = 5%.

| Round | Stake at start | What happens                      | Stake at end | Slashed for belowMinStake?                   |
| ----- | -------------- | --------------------------------- | ------------ | -------------------------------------------- |
| R3    | 50,000         | Slashed 5% for missed duties      | 47,500       | No — was at minimum at start                 |
| R4    | 47,500         | Navigator tops up 3,000 mid-round | 50,500       | No — was below at start but recovered by end |
| R5    | 50,500         | Normal operation                  | 50,500       | No — above minimum                           |

If the navigator does **not** recover:

| Round | Stake at start | What happens                 | Stake at end | Slashed for belowMinStake?       |
| ----- | -------------- | ---------------------------- | ------------ | -------------------------------- |
| R3    | 50,000         | Slashed 5% for missed duties | 47,500       | No — was at minimum at start     |
| R4    | 47,500         | No action taken              | 47,500       | **Yes** — below at start and end |
| R5    | 45,125         | Slashed again (cascading)    | 42,869       | **Yes** — still below            |

### Major Slashing

Via governance: `deactivateNavigator(navigator, slashPercentage, slashFees)`. Can slash up to 100% of stake plus forfeit all unclaimed locked fees.

## Key View Functions

| Function                                            | Returns                                                     |
| --------------------------------------------------- | ----------------------------------------------------------- |
| `getStake(navigator)`                               | Current staked amount                                       |
| `getStakedAmountAtTimepoint(navigator, timepoint)`  | Historical staked amount (for voting power)                 |
| `getDelegatedAmount(citizen)`                       | Current delegated VOT3 amount                               |
| `getDelegatedAmountAtTimepoint(citizen, timepoint)` | Historical delegation (for snapshot voting)                 |
| `getNavigator(citizen)`                             | Current navigator address                                   |
| `getNavigatorAtTimepoint(citizen, timepoint)`       | Historical navigator (respects dead-navigator invalidation) |
| `isNavigator(account)`                              | True if registered and active                               |
| `canAcceptDelegations(navigator)`                   | True if active, above min stake, not exiting                |
| `getAllocationPreferences(navigator, roundId)`      | App IDs and percentages for a round                         |
| `getProposalDecision(navigator, proposalId)`        | Governance decision (1=Against, 2=For, 3=Abstain)           |

## Relayer Integration

At round start, `XAllocationVoting.startNewRound` computes expected actions:

* `allocationUsers = autoVotingUsers + totalDelegatedCitizens`
* `governanceUsers = totalDelegatedCitizens` (citizens only — relayers don't cast governance votes for auto-voters)

Per-user skip tracking in RelayerRewardsPool prevents deadlocks: when all vote actions for a user are skipped, the claim action is auto-reduced too.

### Passport Validation

`castNavigatorVote` in both XAllocationVoting and B3TRGovernor validates the citizen's passport (personhood) at the round/proposal snapshot. If the citizen is not a valid person at that snapshot, the vote is **skipped** (not reverted) — the relayer pool expected actions are reduced and a skip event is emitted. This matches the existing auto-voting skip behavior.


# Get Started

## Requirements

If you want to create an x2earn app it needs to have the following features:

* Be able to **distribute B3TR** tokens on the VeChain blockchain
* Be able to **submit a proof** (in JSON format) of the sustainable action the user was rewarded for

Bonus:

* Allow the user to **connect** with their [wallet](https://vechain-kit.vechain.org/) to your app

This guide provides instructions for setting up a project within the VeBetter ecosystem. Your app will participate in weekly allocation rounds, receive B3TR tokens at the beginning of each round, and distribute these

<figure><img src="/files/QltJkxf8K5ekMOO58NNo" alt=""><figcaption><p>Architecture overview of components that could be involved in creating a x2earn app</p></figcaption></figure>

## Test Environment

Use our [Test Environment](https://staging.testnet.governance.vebetterdao.org/) to create a test app running **in the VeBetter ecosystem.**

{% content-ref url="/pages/PJUOQ03h4RP1moj5NYQZ" %}
[Test Environment](/developer-guides/test-environment)
{% endcontent-ref %}

## **Distribute B3TR**

Get some B3TR tokens on testnet, add a reward distributor then connect a smart contract or a backend and distribute rewards to your users.

{% content-ref url="/pages/n6k0iIiz88BByA1mDxJx" %}
[Testnet B3TR tokens](/developer-guides/testnet-b3tr-tokens)
{% endcontent-ref %}

{% content-ref url="/pages/aBjTa19uEGYHWRaf69Df" %}
[Reward Distribution](/developer-guides/reward-distribution)
{% endcontent-ref %}

## Proofs and Impacts

Every time you reward a user you also need to specify the reason, the proof of the user's action and the sustainability impact it had.

{% content-ref url="/pages/D412snNwyHj7OxHlFGL3" %}
[Sustainability Proof and Impacts](/developer-guides/sustainability-proof-and-impacts)
{% endcontent-ref %}

## Resources

Have doubts? Check our additional resources specifically picked for you to speed up your development.

{% content-ref url="/pages/IQZG7UENOWkmSlzrz2Q0" %}
[Resources](/developer-guides/resources)
{% endcontent-ref %}

## Submit App

When your app is ready submit it to VeBetter and join the movement!

{% content-ref url="/pages/rpHCk8QHlu5gnSZJCP0u" %}
[Submit Your App](/developer-guides/submit-your-app)
{% endcontent-ref %}

## RuleBook

{% content-ref url="/pages/Hc60uRwqgaaxhjeN5EfL" %}
[RuleBook for Apps](/developer-guides/rulebook-for-apps)
{% endcontent-ref %}

## Security

{% hint style="danger" %}
Before going live be sure to go through our [Security Considerations](/developer-guides/security-considerations) along the [RuleBook](/developer-guides/rulebook-for-apps). Make sure to apply security measures to your app, avoiding hacks and farmers.
{% endhint %}

{% content-ref url="/pages/8ASkrKpkcvjtSLb4UI8s" %}
[Security Considerations](/developer-guides/security-considerations)
{% endcontent-ref %}


# Test Environment

You have two testing environments: testnet and an instance of the blockchain running locally (a [solo node](https://docs.vechain.org/core-concepts/networks/thor-solo-node)).

Testing your app on testnet is more straightforward since all contracts are already deployed by us and you can use our testnet dApp to add apps, interact with smart contracts, and manage reward distribution.

Testing on solo will be a bit more complicated because you will need to deploy some mocked VeBetter contracts by yourself, but we tried to make that easy as well.

## Testnet

Use our testnet environment, running on vechain testnet network, to create apps, interact with smart contracts, and manage reward distribution.

* Go to <https://staging.testnet.governance.vebetterdao.org/apps>
* Create a new app following the form (it will mint for you a creator nft)
* After adding the app it needs to pass the endorsement check, navigate to <https://staging.testnet.governance.vebetterdao.org/admin>, select the "X2Earn Apps" tab, and click the "Check Endorsement" button for your app.
* Then you can navigate to <https://staging.testnet.governance.vebetterdao.org/admin>, start a new round by clicking "Start new round & claim allocations" (you will probably need to do it a couple of times before you begin getting b3tr from allocations)
* To allow your contract to distribute the rewards, you need to click the cogs icon, enter the Settings section of your app, and add the address of your contract (which will call the `distributeReward` function) as a "Reward Distributor".

That's it, you are all set and can distribute rewards through your backend or smart contract.

Testnet contract addresses:

```json
"B3TR": "0x95761346d18244bb91664181bf91193376197088",
"B3TRGovernor": "0xc30b4d0837f7e3706749655d8bde0c0f265dd81b",
"Emissions": "0x66898f98409db20ed6a1bf0021334b7897eb0688",
"GalaxyMember": "0x38a59fa7fd7039884465a0ff285b8c4b6fe394ca",
"TimeLock": "0x835509222aa67c333a1cbf29bd341e014aba86c9",
"Treasury": "0x3d531a80c05099c71b02585031f86a2988e0caca",
"VOT3": "0x6e8b4a88d37897fc11f6ba12c805695f1c41f40e",
"VoterRewards": "0x851ef91801899a4e7e4a3174a9300b3e20c957e8",
"X2EarnApps": "0x0b54a094b877a25bdc95b4431eaa1e2206b1ddfe",
"X2EarnRewardsPool": "0x2d2a2207c68a46fc79325d7718e639d1047b0d8b",
"XAllocationPool": "0x6f7b4bc19b4dc99005b473b9c45ce2815bbe7533",
"XAllocationVoting": "0x8800592c463f0b21ae08732559ee8e146db1d7b2",
"NavigatorRegistry": "0x15a38b65f26bdbca50addf3865732613a45bbc00"
```

## Local node

Testing on the solo node (aka: local node running on your computer simulating VeChain blockchain) is a bit more complicated than testing on testnet, since you will need to deploy the VeBetter contracts locally and interact with them to create your app, obtain the APP\_ID, start an allocation round, vote, start round again, and add the reward distributor.

We recommend following the testnet path, but if you need to do it on the solo network you will need to mock a few VeBetter contracts:

* `B3TR` token mock: you need a fake token to distribute
* `X2EarnApps` mock: you need a contract where to add your app, generate an APP\_ID and add a reward distributor
* `X2EarnRewardsPool` mock: you need a contract to distribute the rewards

While the `X2EarnRewardsPoolMock` contract can be the exact same contract deployed on mainnet and testnet, the other two can be customized in order to have only the essential logic needed for running tests.

You can take a look at the mocked contracts in the [X-App-Template](https://github.com/vechain/x-app-template) repository, under the `contracts/mocks` folder.

After you added the mock contracts to your repository you should adjust the deploy script in a way that you will deploy and configure the mocked contracts only if you are deploying to the `vechain_solo` network.

Your script should look something like this:

```typescript
import { ethers, network } from "hardhat";
import { Challenges, Cleanify, RolesManager } from "../../typechain-types";
import { networkConfig } from "@repo/config";
import { deployProxy } from "../helpers/upgrades";
import { faker } from "@faker-js/faker";

let REWARD_TOKEN_ADDRESS = "0xE5FEfcB230364ef7f9B5B0df6DA81B227726612b"; // mainnet address

export async function deploy(): Promise<{
    mySustainableContractAddress: string;
}> {
    console.log(
        `Deploying on ${network.name} (${networkConfig.network.defaultNodeUrl})...`
    );

    console.log(`Deploying my app contract...`);
    const MySustainableContract = await ethers.getContractFactory("MySustainableContract");
    const mySustainableContract = await MySustainableContract.deploy();
    await mySustainableContract.waitForDeployment();
    console.log(`Sustainable Contract deployed to ${await mySustainableContract.getAddress()}`);

    if (network.name === "vechain_solo") {
        console.log(`Deploying mock RewardToken...`);
        const RewardToken = await ethers.getContractFactory("B3TR_Mock");
        const rewardToken = await RewardToken.deploy();
        await rewardToken.waitForDeployment();
        REWARD_TOKEN_ADDRESS = await rewardToken.getAddress();
        console.log(`RewardToken deployed to ${REWARD_TOKEN_ADDRESS}`);

        console.log("Deploying X2EarnApps mock contract...");
        const X2EarnApps = await ethers.getContractFactory("X2EarnAppsMock");
        const x2EarnApps = await X2EarnApps.deploy();
        await x2EarnApps.waitForDeployment();
        console.log(`X2EarnApps deployed to ${await x2EarnApps.getAddress()}`);

        console.log("Deploying X2EarnRewardsPool mock contract...");
        const X2EarnRewardsPool = await ethers.getContractFactory(
            "X2EarnRewardsPoolMock"
        );
        const x2EarnRewardsPool = await X2EarnRewardsPool.deploy(
            deployer.address,
            REWARD_TOKEN_ADDRESS,
            await x2EarnApps.getAddress()
        );
        await x2EarnRewardsPool.waitForDeployment();
        console.log(
            `X2EarnRewardsPool deployed to ${await x2EarnRewardsPool.getAddress()}`
        );

        console.log("Adding app in X2EarnApps...");
        await x2EarnApps.addApp(deployer.address, deployer.address, "MySustainableApp");
        const appID = await x2EarnApps.hashAppName("MySustainableApp");

        console.log(`Funding contract...`);
        await rewardToken.approve(
            await x2EarnRewardsPool.getAddress(),
            ethers.parseEther("10000")
        );
        await x2EarnRewardsPool.deposit(ethers.parseEther("2000"), appID);
        console.log("Funded");

        console.log("Add MySustainableContract as distributor...");
        await x2EarnApps.addRewardDistributor(
            appID,
            await mySustainableContract.getAddress()
        );
        console.log("Added");

        console.log(
            "Set APP_ID and X2EarnRewardsPool address in Challenges contract..."
        );
        await mySustainableContract.setVBDAppId(appID);
        await mySustainableContract.setX2EarnRewardsPool(
            await x2EarnRewardsPool.getAddress()
        );
        console.log("Set");
    }
    
    return {
        mySustainableContract: await mySustainableContract.getAddress()
    };
}
```

That's it, you can now deploy your contracts locally/run tests where you simulate the VeBetter contracts, your app added to the ecosystem, and tokens distribution.


# Testnet B3TR tokens

There are two ways to obtain B3TR on testnet for development: a public **faucet** (fastest) or **allocation rounds** (closer to the real production flow).

## B3TR Testnet Faucet

The fastest way to get a small amount of B3TR for development and testing.

* **App:** <https://vechain.github.io/b3tr-testnet-faucet/>
* **Source:** <https://github.com/vechain/b3tr-testnet-faucet>
* **Faucet contract (testnet):** `0xfca716f9c93575f428fe49402424454077ccbfee`
* **B3TR token (testnet):** `0x026771d1be764467f8bdb78bb230df10c924b00d`

Connect your wallet (VeWorld or WalletConnect), click **Claim B3TR**, and the faucet contract transfers a fixed amount of B3TR to your address. Each address can claim up to a configurable daily limit.

{% hint style="info" %}
The faucet is meant for development. For larger amounts (e.g. funding a reward distributor for an x2Earn app), use allocation rounds — see below.
{% endhint %}

### Programmatic claim

The faucet is a regular contract; you can call it from any script:

```solidity
interface IB3TRFaucet {
  function claimTokens() external;
  function canClaim(address user) external view returns (bool);
  function remainingClaimsForToday(address user) external view returns (uint256);
}
```

```javascript
import { ethers } from "ethers"

const FAUCET = "0xfca716f9c93575f428fe49402424454077ccbfee"
const FAUCET_ABI = ["function claimTokens()"]

const tx = await new ethers.Contract(FAUCET, FAUCET_ABI, signer).claimTokens()
await tx.wait()
```

### Running out / contributing

If the faucet is empty, anyone with B3TR can call `fundFaucet(amount)` (after approving) to top it up. PRs to the repo are welcome — see [vechain/b3tr-testnet-faucet](https://github.com/vechain/b3tr-testnet-faucet).

## Allocation rounds

If you need to **distribute rewards from your x2Earn app**, you should get B3TR from allocation rounds — that's the same flow your app will use in production.

You can **start a new allocation round** (in production those are started automatically each Monday and last a week, in testnet you need to manually trigger them, and they last 10 minutes), wait 10 minutes, then distribute the rewards to your app (done automatically in production, but you need to manually trigger on testnet).

You can access those functionalities from the "[Admin](https://staging.testnet.governance.vebetterdao.org/admin)" tab.

{% embed url="<https://streamable.com/2seek2>" %}

{% hint style="danger" %}
Remember that to actually distribute rewards you will need to add your wallet as a reward distributor in your app's settings. Read more in the [Rewards Distribution section](/developer-guides/reward-distribution).
{% endhint %}


# Reward Distribution

**To enhance the transparency** of the VeBetter platform and x2earn apps, following also the ["dApp Tracker" proposal](https://governance.vebetterdao.org/proposals/48098052949649968323435845011935575242371156821795293696975298342916966237360), we have developed a centralized reward distributor contract. This contract must be used by the apps to ensure that every transfer of a B3TR token related to a sustainable action is publicly tracked and accessible to the community.

You need to call this contract to distribute the rewards.

### Round Attribution

By default, when you distribute a reward, the action is recorded in the **current round**. If your app allows users to accumulate actions and claim them later, the action will be attributed to the round when the claim happens — not when the action was performed.

To attribute actions to the correct round, use the `ForRound` variants of the distribution functions. These accept an additional `actionRound` parameter (the round ID when the action was actually performed):

* `distributeRewardForRound`
* `distributeRewardWithProofForRound`
* `distributeRewardWithProofAndMetadataForRound`

The `actionRound` must be greater than 0.

{% content-ref url="/pages/tzKJ08CD1y0q81JCETlh" %}
[JavaScript](/developer-guides/reward-distribution/javascript)
{% endcontent-ref %}

{% content-ref url="/pages/7FapZfU2NYxnTF0JLwUT" %}
[Solidity](/developer-guides/reward-distribution/solidity)
{% endcontent-ref %}


# JavaScript

Setup a lambda function or an endpoint that will send the B3TR tokens to the user, providing also a proof and impacts of the rewarding action.

We will use [@vechain/sdk-network](https://docs.vechain.org/developer-resources/sdks-and-providers/sdk) and [@vechain/vebetterdao-contracts](https://github.com/vechain/vebetterdao-contracts) to interact with VeBetter's `X2EarnRewardsPool` contract to distribute the rewards.

Run the following command to install the packages:

```shell
yarn add @vechain/sdk-network @vechain/vebetterdao-contracts
```

To distribute the rewards you will need 2 information:

* `Node URL`

```
TESTNET: https://testnet.vechain.org
MAINNET: https://mainnet.vechain.org
```

* Your `APP_ID` on VeBetter: create app [here](https://dev.testnet.governance.vebetterdao.org/) to obtain the APP\_ID.

Now you can distribute the reward like this:

{% tabs %}
{% tab title="Using MNEMONIC" %}

```javascript
import {
  ProviderInternalHDWallet,
  ThorClient,
  VeChainProvider,
  VeChainSigner,
} from "@vechain/sdk-network";
import { X2EarnRewardsPool } from "@vechain/vebetterdao-contracts";

function rewardUser() {
    // To transfer B3TR we first need to connect to the blockchain with
    // a wallet capable of signing and broadcastisting transactions
    const thor = ThorClient.at(process.env.NODE_URL || "");
    const provider = new VeChainProvider(
      thor,
      new ProviderInternalHDWallet(
        process.env.REWARD_SENDER_MNEMONIC?.split(" ") || []
      )
    );
    const rootSigner = await provider.getSigner();

    // Call the VeBetterDAO smart contract
    const x2EarnRewardsPoolContract = thor.contracts.load(
      process.env.X2EARN_REWARDS_POOL_ADDRESS || "",
      X2EarnRewardsPool.abi,
      rootSigner as VeChainSigner
    );
    
    const tx =
      await x2EarnRewardsPoolContract.transact.distributeRewardDeprecated(
        process.env.VEBETTERDAO_APP_ID || "",
        10,
        address,
        JSON.stringify({
          version: 2,
          description: "User refilled water from a sustainable source",
          proof: {
            image: "https://image.png",
            link: "https://twitter.com/tweet/1",
          },
          impact: {
             carbon: 100,
             water: 200
          }
        })
      );

    await tx.wait();
}

```

{% endtab %}

{% tab title="Using PRIVATE KEY" %}

```javascript
import {
  ProviderInternalHDWallet,
  ThorClient,
  VeChainProvider,
  VeChainSigner,
} from "@vechain/sdk-network";
import { X2EarnRewardsPool } from "@vechain/vebetterdao-contracts";

const PRIVATE_KEY = ""
const ACCOUNT_ADDRESS_OF_PK = ""

function rewardUser() {
    // To transfer B3TR we first need to connect to the blockchain with
    // a wallet capable of signing and broadcastisting transactions
    const thor = ThorClient.at(process.env.NODE_URL || "");
    const wallet = new ProviderInternalBaseWallet(
        [
            {
                privateKey: Buffer.from(
                    PRIVATE_KEY.slice(2),
                    'hex',
                ),
                address: ACCOUNT_ADDRESS_OF_PK,
            },
        ],
    );
    const provider = new VeChainProvider(
        thor,
        wallet,
        false,
    );
    const signer = await provider.getSigner(
        ACCOUNT_ADDRESS_OF_PK,
    );

    // Call the VeBetterDAO smart contract
    const x2EarnRewardsPoolContract = thor.contracts.load(
      process.env.X2EARN_REWARDS_POOL_ADDRESS || "",
      X2EarnRewardsPool.abi,
      rootSigner as VeChainSigner
    );
    
    const tx =
      await x2EarnRewardsPoolContract.transact.distributeRewardDeprecated(
        process.env.VEBETTERDAO_APP_ID || "",
        10,
        address,
        JSON.stringify({
          version: 2,
          description: "User refilled water from a sustainable source",
          proof: {
            image: "https://image.png",
            link: "https://twitter.com/tweet/1",
          },
          impact: {
             carbon: 100,
             water: 200
          }
        })
      );

    await tx.wait();
}

```

{% endtab %}
{% endtabs %}

{% hint style="info" %}

#### Sustainability Proof

Read more about the proof standard and how we expect you to provide it in the [Sustainability Proofs and Impacts](/developer-guides/sustainability-proof-and-impacts) section.
{% endhint %}

{% hint style="danger" %}
To be able to distribute the rewards you will need to add the PUBLIC ADDRESS of the wallet calling the `distributeRewards` function as a Reward Distributor of your app.\
\
To do so, you need to:

1\) Connect with your app's admin wallet to the governance dapp

2\) Go to your app's page

3\) Click the *cogs* button to enter the settings page

4\) Scroll down to the "Reward Distributors" section, and add the public address as a reward distributor

5\) Save changes
{% endhint %}

<figure><img src="/files/sm9Zfrk775VqbwzT1V4R" alt=""><figcaption></figcaption></figure>


# Solidity

In this example, we assume that you are building a smart contract where users can submit some sustainable action that is being approved/rejected by some moderator. If the action is approved the user can claim his rewards. No backend is involved.

Your contract should look like this:

<pre class="language-solidity"><code class="lang-solidity"><strong>// SPDX-License-Identifier: MIT
</strong>pragma solidity 0.8.20;

// can find here: https://github.com/vechain/vebetterdao-contracts/tree/main/contracts/interfaces
import "./interfaces/IX2EarnRewardsPool.sol";

/**
 * Example contract with key functionality to interact with the x2Earn rewards pool
 * and distribute rewards.
 * You can customize this contract in the way 
 */
contract MySustainableAppContract {
    IX2EarnRewardsPool public x2EarnRewardsPool;
    bytes32 public VBD_APP_ID;
    
    // a dummy mapping pretending you have a way to track and 
    // validate user actions on chain.
    mapping(uint256 actionId => ActionStruct) public sustainableActions;
    mapping(uint256 actionId => bool) public rewardsClaimed;
    
    // You will need to setup the address of the X2EarnRewardsPool contract
    // and your APP_ID on VeBetterDAO
    constructor(IX2EarnRewardsPool _x2EarnRewardsPool, bytes32 _VBD_APP_ID) {
        x2EarnRewardsPool = _x2EarnRewardsPool;
        VBD_APP_ID = _VBD_APP_ID;
    }

    /**
     * @notice A function that allows a user to claim a reward for a specific
     * sustainable action that they performed.
     * 
     * IMPORTANT: the address of this contract must be set as a distributor 
     * of your APP in order to move funds from the X2EarnRewardsPool contract. 
     * You can set this on the VeBetterDAO governance app.
     */
    function claimReward(uint256 _actionId) external {
        // ... some code to check if the action is valid and user can claim

        // If distributeReward fails, it will revert
        x2EarnRewardsPool.distributeReward(
            VBD_APP_ID,
            actions[_actionId].rewardAmount,
            msg.sender, // this is the user calling the claimReward function
            "" // proof and impacts not provided
        );

        rewardClaimed[_actionId] = true;

        emit RewardClaimed(_actionId, msg.sender);
    }
}
</code></pre>

### Attributing Actions to a Specific Round

If your app allows users to accumulate actions and claim later, use `distributeRewardForRound` to attribute the action to the round it was performed in:

```solidity

    function claimReward(uint256 _actionId, uint256 _actionRound) external {
        // ... some code to check if the action is valid and user can claim

        // Attribute the action to the round it was performed in
        x2EarnRewardsPool.distributeRewardForRound(
            VBD_APP_ID,
            actions[_actionId].rewardAmount,
            msg.sender,
            "",
            _actionRound // the round when the action was actually performed
        );

        rewardClaimed[_actionId] = true;

        emit RewardClaimed(_actionId, msg.sender);
    }
```

{% hint style="warning" %}
The address of this contract must be set as a **distributor** of your APP in order to move funds from the X2EarnRewardsPool contract.

You can set this on the VeBetter governance app.

<img src="/files/BexwKB5hdyLXQ5rK4d1p" alt="" data-size="original">
{% endhint %}

{% hint style="info" %}

#### Sustainability Proof

Read more about the proof standard and how we expect you to provide it in the [Sustainability Proofs and Impacts](/developer-guides/sustainability-proof-and-impacts) section.
{% endhint %}

{% hint style="danger" %}
To be able to distribute the rewards you will need to add the PUBLIC ADDRESS of the wallet calling the `distributeRewards` function as a Reward Distributor of your app.\
\
To do so, you need to:

1\) Connect with your app's admin wallet to the governance dapp

2\) Go to your app's page

3\) Click the *cogs* button to enter the settings page

4\) Scroll down to the "Reward Distributors" section, and add the public address as a reward distributor

5\) Save changes
{% endhint %}

<figure><img src="/files/sm9Zfrk775VqbwzT1V4R" alt=""><figcaption></figcaption></figure>


# Manage distributors funds

Every app receives B3TR from weekly allocation rounds in a contract called X2EarnRewardsPool and those rewards are now configurable by the app admin. In fact, you can split allocated tokens between **distributable rewards pool** for your user and a **treasury pool**, withdrawal for operational needs. You also have the possibility to **pause distribution** anytime, this won't affect the reward pool unless you move funds to the app balance.

This **dual-pool mechanism** allows you to have more control over your distribution funds.\
\
You can manage these configurations directly from the **app admin dashboard** in the VeBetter app. Or by interacting with our **`X2EarnRewardsPool` contract.**

{% hint style="warning" %}
Only the **app admin** can set this **distributable rewards pool,** by increasing/ decreasing the wished amount.\
\
If you are **new to the DAO**, note that this feature will be enabled by default. You will have to **immediately refill your rewards pool**, up to the amount you want to distribute.
{% endhint %}

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5gLJKT3UdlvblZqAiaZ2%2Fuploads%2FNcjwDzd4KWvUcx7ZcIii%2FDEMO-locking-mechanism.mp4?alt=media&token=a726789b-9e53-42a8-9c0c-99c953732a0d>" %}

### Q\&A

<details>

<summary>What happen if my rewards pool goes to 0 ?</summary>

If your balance is empty, it's either because you enabled the feature without adding funds to your rewards pool, or because you've run out of funds. You can either **refill** your rewards pool or **disable** the feature entirely at any time:

**Via VeBetterDAO Dashboard**

* **Refill**: Add funds directly through the VBD dashboard
* **Disable**: Toggle off the feature in settings

**Via** `X2EarnRewardsPool`**Smart Contract**

<pre class="language-solidity"><code class="lang-solidity">// Option 1: Refill your rewards pool with additional funds
// @param amount The amount of tokens to add to your rewards pool
X2EarnRewardsPool.increaseRewardsPoolBalance(bytes32 appId, uint256 amount)


// Option 2: Toggle rewards functionality on/off
// @param enable Set to false to disable rewards, true to enable
<strong>X2EarnRewardsPool.toggleRewardsPoolBalance(bytes32 appId, bool enable)
</strong></code></pre>

</details>


# Sustainability Proof and Impacts

The proof will be stored on-chain in the form of an emitted event and will have the following JSON format:

```json
{
   version: 2,
   description: 'The description of the action',
   proof: { 
      image: 'https://image.png', 
      link: 'https://twitter.com/tweet/1' 
   },
   impact: { 
      carbon: 100, 
      water: 200 
   }
}
```

## Parameters

You will provide this proof as a parameter when calling the distribute rewards function in the `X2EarnRewardsPool` contract.

* **proofTypes**: an array with the proof types that you are providing. Eg:\
  `["link", "image"]`
* **proofValues**: an array with the values of the types provided in the previous array. Eg: `["https://twitter.com/tweet/1233121231", "https://whatever.com/image.png"]`
* **impactCodes**: an array with the codes of impacts you are providing. Eg:\
  `["water", "timber"]`
* **impactValues**: an array with the values of the impacts provided in the previous array. Eg:\
  `[1000, 23]`
* **description**: you can attach also a description to your action, it's optional.

When calling this function it is mandatory to provide at least proof or impact, if none of them is provided then the transaction will revert.

The transaction will revert also if something is wrong with the data you pass.

## Examples

To provide proofs and impacts you need to distribute the rewards through the X2EarnRewardsPool contract with the following function:

{% tabs %}
{% tab title="JavaScript" %}

```javascript
import { ProviderInternalHDWallet, ThorClient, VeChainProvider, VeChainSigner } from "@vechain/sdk-network"
import { X2EarnRewardsPool } from "@vechain/vebetterdao-contracts"

const thor = ThorClient.fromUrl("https://mainnet.vechain.org")
const provider = new VeChainProvider(
  thor,
  new ProviderInternalHDWallet("your space separated mnemonic".split(" ")),
)
const rootSigner = await provider.getSigner()

// Call the method
const x2EarnRewardsPoolContract = thor.contracts.load(X2EarnRewardsPool.address.mainnet, X2EarnRewardsPool.abi, rootSigner as VeChainSigner)
const tx = await x2EarnRewardsPoolContract.transact.distributeRewardWithProof(
  APP_ID,
  amount,
  receiverAddress,
  ["link", "image"],
  ["https://link-to-proof.com", "https://link-to-image.com/1.png"],
  ["waste_mass"],
  [100],
  "User performed a sustainable action on my app",
)

await tx.wait()
```

{% endtab %}

{% tab title="Solidity" %}

```solidity
import "./interfaces/IX2EarnRewardsPool.sol";

contract MyContract {
    function sendReward() onlyAdmin {
        // this declaration is needed because solidity has 
        // an issue with dynamic vs fixed-size arrays
        string[] memory proofTypes = new string[](1);
        proofTypes[0] = "link";
        
        string[] memory proofUrls = new string[](1);
        proofUrls[0] = action.proofUrl;
        
        string[] memory impactTypes = new string[](1);
        impactTypes[0] = "waste_mass";
            
        uint256[] memory impactValues = new uint256[](1);
        // let's pretend you have another function that calculates your impact
        impactValues[0] = calculateWasteMass(
            challenge.litterSize,
            challenge.litterCount
        );
        
        IX2EarnRewardsPool x2EarnRewardsPool = IX2EarnRewardsPool(x2EarnRewardsPoolAddress);
        
        // If distributeReward fails, it will revert
        x2EarnRewardsPool.distributeRewardWithProof(
            VBD_APP_ID,
            rewardAmount,
            receiver,
            proofTypes,
            proofUrls,
            impactTypes,
            impactValues,
            "User participated in a solo cleanup"
        );
    }
}

```

{% endtab %}
{% endtabs %}

## Proofs <a href="#title-text" id="title-text"></a>

You can attach proof of the user's sustainable action when you distribute the reward. The proof can be a link, video, photo, and text. You can provide more than one proof (eg: a photo and a link).

The current proof types supported are:

<pre><code><strong>"image"
</strong><strong>"link"
</strong><strong>"text"
</strong><strong>"video"
</strong></code></pre>

## Impacts <a href="#title-text" id="title-text"></a>

Determining the environmental impact of each sustainable action will require the development of a set of criteria and metrics for each type of action.

{% hint style="warning" %}
**Warning: the impact values MUST be a number and the unit is considered the default minimum (so milliliters, grams, wh, etc.). So if you saved 1 litter of water then you should put it as an impact of `"water" : "1000"`.**
{% endhint %}

### Categories <a href="#categories" id="categories"></a>

1. **Carbon Footprint Reduction**\
   **Key:** `carbon`\
   **Description:** Measures the decrease in greenhouse gas emissions.\
   **Metric:** Grams (g) of CO2 equivalent reduced or removed.
2. **Resource Conservation**\
   **Key:** `water` (for water conservation), `energy` (for electricity conservation)\
   **Description:** Assesses the reduction in the use of natural resources like water, electricity, and raw materials.\
   **Metric:** Milliliters (ml) of water saved, watt-hours (Wh) of electricity saved.
3. **Waste Reduction**\
   **Key:** `waste_mass`\
   **Description:** Evaluates the decrease in waste generated and improves waste management.\
   **Metric:** Grams (g) of waste diverted from landfills, number of items recycled.
4. **Timber Conservation**\
   **Key:** `timber`\
   **Description:** Measures the reduction in the use or waste of timber resources.\
   **Metric:** Grams (g) of timber saved.
5. **Plastic Reduction**\
   **Key:** `plastic`\
   **Description:** Evaluates the decrease in the use or waste of plastic materials.\
   **Metric:** Grams (g) of plastic saved or reduced.
6. **Education Time**\
   **Key:** `education_time`\
   **Description:** Measures the amount of time a user spends learning about a sustainability topic.\
   **Metric:** Seconds spent learning.
7. **Trees Planted**\
   **Key:** `trees_planted`\
   **Description:** Tracks the number of trees planted as part of sustainability efforts.\
   **Metric:** Number of trees planted.
8. **Calories Burned**\
   **Key:** `calories_burned`\
   **Description:** Measures the energy expenditure from physical activity or exercise, promoting health and sustainability.\
   **Metric:** Calories (kcal) burned.
9. **Sleep Quality**\
   **Key:** `sleep_quality_percentage`\
   **Description:** Assesses the quality of sleep as a percentage, encouraging better health and productivity.\
   **Metric:** Percentage (%) of sleep quality improvement.
10. **Clean Energy Production**\
    **Key:** `clean_energy_production_wh`\
    **Description:** Measures the amount of clean energy produced, contributing to sustainable energy solutions.\
    **Metric:** Watt-hours (Wh) of clean energy generated.

The following are the impact codes you will need to use:

```
"carbon"
"water"
"energy"
"waste_mass"
"education_time",
"timber"
"plastic"
"trees_planted"
"calories_burned"
"sleep_quality_percentage"
"clean_energy_production_wh"
```

#### We ask each app to find a way to calculate the impact they are having based on the previously listed categories. If your app does not fit in any of the above categories please feel free to submit your own category and impact definition. <a href="#action-specific-impact-models" id="action-specific-impact-models"></a>

## **Deprecated template (version 1)**

**If no "version" field is found in the the json proof then you should consider it as version 1.**

```json
{
  "app_name": "cleanify",
  "action_type": "litter_picking",
  "proof": {
    "proof_type": "link",
    "proof_data": "https://x.com/TengMab95659/status/1814152547202195788"
  },
  "metadata": {
    "description": "@TengMab95659 picked up 8 small pieces of litter.",
    "additional_info": ""
  },
  "impact": {
    "waste_mass": "300",
    "biodiversity": "1"
  },
}
```

Deprecated impacts:

```
waste_items
people
biodiversity
```

## Round Attribution

All distribution functions have `ForRound` variants that accept an additional `actionRound` parameter. Use these when actions are claimed in a different round than when they were performed:

* `distributeRewardWithProofForRound(..., actionRound)`
* `distributeRewardWithProofAndMetadataForRound(..., actionRound)`

The `actionRound` is the round ID when the sustainable action was actually performed. This ensures the action is correctly attributed for scoring and challenges.

{% hint style="success" %}
If you want to store additional data beyond impacts or proofs, you might consider using the reward metadata function, which allows you to include other meaningful extra information. [Go to Reward Metadata Docs](/developer-guides/reward-metadata)
{% endhint %}


# Reward Metadata

The Rewards Metadata feature allows applications to enrich reward distributions with additional contextual information. This is facilitated through the `distributeRewardWithProofAndMetadata` function, which accepts a JSON-formatted string as metadata.\
\
The provided metadata is then emitted via the `RewardMetadata` event, enabling off-chain services to efficiently index, analyze, and utilize the data for tracking and reporting purposes.

### Suggested Metadata Structure

To maintain consistency across applications, it's recommended to follow a standardized metadata structure. Below is an example of a JSON-formatted metadata string:

```json
{
  "location": {
    "city": "Berlin",
    "country": "Germany",
    "region": "EU"
  },
  "referral_source": "social_media",
  "campaign_id": "earth_day_2025"
}

```

{% hint style="warning" %}
Keep in mind that including location metadata may require updating your privacy policy and terms of service.
{% endhint %}

### Examples

To provide metadata you need to distribute the rewards through the X2EarnRewardsPool contract with the following function:

{% tabs %}
{% tab title="JavaScript" %}

```javascript
import { ProviderInternalHDWallet, ThorClient, VeChainProvider, VeChainSigner } from "@vechain/sdk-network";
import { X2EarnRewardsPool } from "@vechain/vebetterdao-contracts";

const thor = ThorClient.fromUrl("https://mainnet.vechain.org");
const provider = new VeChainProvider(
  thor,
  new ProviderInternalHDWallet("your space separated mnemonic".split(" "))
);
const rootSigner = await provider.getSigner();

// Define metadata as an object
const metadata = {
  "location": {
    "city": "Berlin",
    "country": "Germany",
    "region": "EU"
  },
  "referral_source": "social_media",
  "campaign_id": "earth_day_2025"
};

// Call the method
const x2EarnRewardsPoolContract = thor.contracts.load(
  X2EarnRewardsPool.address.mainnet,
  X2EarnRewardsPool.abi,
  rootSigner as VeChainSigner
);

const tx = await x2EarnRewardsPoolContract.transact.distributeRewardWithProofAndMetadata(
  APP_ID,
  amount,
  receiverAddress,
  ["link", "image"],
  ["https://link-to-proof.com", "https://link-to-image.com/1.png"],
  ["waste_mass"],
  [100],
  "User performed a sustainable action on my app",
  JSON.stringify(metadata) // Convert metadata object to JSON string
);

await tx.wait();

```

{% endtab %}

{% tab title="Solidity" %}

```python
import "./interfaces/IX2EarnRewardsPool.sol";

contract MyContract {
    function sendRewardWithMetadata() onlyAdmin {
        // this declaration is needed because solidity has 
        // an issue with dynamic vs fixed-size arrays
        string[] memory proofTypes = new string[](1);
        proofTypes[0] = "link";
        
        string[] memory proofUrls = new string[](1);
        proofUrls[0] = action.proofUrl;
        
        string[] memory impactTypes = new string[](1);
        impactTypes[0] = "waste_mass";
            
        uint256[] memory impactValues = new uint256[](1);
        // let's pretend you have another function that calculates your impact
        impactValues[0] = calculateWasteMass(
            challenge.litterSize,
            challenge.litterCount
        );
        
        IX2EarnRewardsPool x2EarnRewardsPool = IX2EarnRewardsPool(x2EarnRewardsPoolAddress);
        
        // Constructing metadata JSON string
        string memory metadata = '{"location":{"city":"Berlin","country":"Germany","region":"EU"},"referral_source":"social_media","campaign_id":"earth_day_2025"}';
    
        
        // If distributeReward fails, it will revert
        x2EarnRewardsPool.distributeRewardWithProofAndMetadata(
            VBD_APP_ID,
            rewardAmount,
            receiver,
            proofTypes,
            proofUrls,
            impactTypes,
            impactValues,
            "User participated in a solo cleanup",
            metadata
        );
    }
}

```

{% endtab %}
{% endtabs %}

### Emitted Event: `RewardMetadata`

Upon successful execution of the `distributeRewardWithProofAndMetadata` function, the `RewardMetadata` event is emitted with the following parameters:

* **amount** (`uint256`): The distributed reward amount.
* **appId** (`bytes32`): The application identifier.
* **receiver** (`address`): The address receiving the reward.
* **metadata** (`string`): The JSON-formatted metadata string.
* **distributor** (`address`): The address initiating the distribution.

This event allows off-chain systems to listen for and process reward distributions along with their associated metadata.

### Guidelines

* **Optional Usage**: The `metadata` is optional. If your application doesn't require additional context, you can continue using the existing `distributeRewardWithProof` function.
* **Standardization**: Adhere to the suggested metadata structure to ensure consistency and facilitate seamless data integration across the ecosystem.
* **Data Validation**: Implement validation checks to ensure the metadata JSON is correctly formatted and contains relevant information before invoking the distribution function.

### Round Attribution

If you need to attribute the action to a specific round, use `distributeRewardWithProofAndMetadataForRound` which accepts an additional `actionRound` parameter at the end. See [Sustainability Proofs](/developer-guides/sustainability-proof-and-impacts#round-attribution) for details.


# Security Considerations

X2Earn Apps should consider implementing necessary security measures to guard against farmers unfairly obtaining b3tr tokens.

### Farming Approaches

* *Single Person, Single Wallet* -> In this scenario the attacker is a single person using a single wallet address. They try to repeat the same claim for b3tr rewards multiple times for the same wallet address. If the dApp is using AI for image validation, they could attempt to use a fake image over and over again.
* *Single Person, Multiple Wallets* -> In this scenario the attacker is a single person but now using multiple wallet addresses. For example they might submit a claim for a reward, then logout of the dApp then login with a different wallet address in VeWorld and repeat the same claim. The attacker then repeats this exercise switching between different accounts to make multiple claims for rewards.
* *Scripts (aka Bots)* -> This is where the attacker has coded a script that submits a claim for rewards. The script might try a single wallet or use multiple wallets to submit the claim for a reward. If the dApp is using AI for image verification, the script might generate a new image or adjust a previously created image.
* *Multiple Collaborating People, Multiple Wallets* -> In this scenario a group of attackers are collaborating together, they may share the same wallet, share social login details. As they are collaborating together they are collecting rewards for the group, which they can share between the group later.
* *Exploiting Vulnerabilities* -> In this scenario the attacker exploits vulnerabilities in smart contracts or back-end API services to create Bots or manually bypass the front-end of the dApp.

### Potential Solutions

#### Securing Back-End APIs

* *Certificate based authentication* -> For example if there is a `/account` endpoint this should be secured with the signed certificate the user signs in VeWorld. The back-end can then validate the certificate, and use the signed address in from the certificate to identify the users wallet.
* *Captcha verification* -> For example if there is a `/claim` endpoint this should be secured with a ReCaptcha. This is to protect against scripted/bot attacks, as it ensures that the back-end APIs can only be used from the front-end of the dApp.
* *CORS domains* -> This is to ensure that the back-end API's can only be called with a request from the same domain. For example if the API is running at `api.myapp.com` and a request to it is made from `api.fakeapp.com`, it will be rejected.
* *Rate limiting* -> Depending on the design of the dApp a user will only be allowed to make a limited number of claims for rewards per day, per week. There are different strategies here, for example:
  * Inspecting the date-time when the users address last received a reward, and not allowing more claims for a time period after that. For example a user can't make another claim until 24hrs after their previously paid reward. This can be implemented in the back-end database or by reading the last reward event on-chain.
  * Determining the current round (week) and how many claims the user has submitted in that timeframe. Thus limiting the user to a fixed number of claims per week.
  * Using device identification techniques to uniquely identify the mobile device the user is using, and limiting the number of claims for rewards not just on address but also on device.

#### How Sustainable Actions are Verified

* *AI based validation* -> The prompts used to validate an image should be thoroughly tested to ensure that the AI is validating as expected. If the AI is used to extract data out of an image (e.g. A receipt) it should be tested to ensure that *hallucinations* are not occurring. The AI should be asked to produce a confidence score, if that is below a threshold the image could be flagged for manual verification.
* *No unique identifier* -> To verify a sustainable action there should be some indisputable evidence of it. For example a social media post, data from an external system, a receipt as proof of purchase or a date-time stamp. In the case of AI image verification, the AI should be prompted to recognise relevant data in the image that can be used for a uniqueness check.

#### Suspicious Behaviour & Ban List

Apps should have the means to identify suspicious behaviour within their dApp, for example rewards being paid every 10 seconds to accounts that have no other transaction history. Apps should have the means to ban accounts or entire devices from using their service.

#### Management of Private Keys

The distributor account private key should be secure within the dApp and not be able to be sniffed in the traffic the dApp generates. If the dApp is using back-end contracts or APIs to sign the reward transaction these should have a secure way of storing the private keys.

#### Device Fingerprinting

Farmers might attempt to install VeWorld (or your native app), multiple times on the same device, and use a different wallet per instance of the app. This is especially true of Android devices, where software exists to allow multiple instances of an app to be installed. A dApp should consider using tools such as FingerprintJS (or its paid version), to identify a users device, and ban the device rather than just the users account(s). If developing a native dApp, protections against multiple installs should be built into the dApp.

### Other Strategies

* *Management of funds* -> The allocation the dApp receives from the DAO on a weekly basis is *at risk* if there are vulnerabilities within the dApp. The dApp owner if concerned about farmers should reduce the b3tr balance of the dApp by withdrawing funds to their treasury account and drip feeding it back to the dapp when needed. Once the concerns are alleviated this strategy can end. The dApp owner can also mitigate this risk by setting a portion of the weekly allocation for distribution and another portion as treasury funds. Treasury funds can be withdrawn at any time.
* *Identify verification* -> Apps can also offer login methods other to VeWorld, for example Google, Facebook, Twitter. In these cases dApp owners should consider validation of the users social media profiles, for example does the facebook profile have a complete profile, was the google account created in last 30mins. Apps could also consider sending verification emails.
* *Progressive unlocking* -> A new account in the dApp might have tigher rate limits and lower rewards. As the user continues to use the dApp they progressively unlock higher rate limits and higher rewards. This means an attacker has to spend more efforts to reach the higher rewards slowing their progress.
* *Scaling Rewards by Demand ->* This is a strategy to scale down user rewards in peek demands and scale them back up at quiet times. The goal is to make the weekly allocation a dApp received last the full week, but also guard against spikes in users (or bots) claiming rewards. One way to do this is to compute the *average rewards per second* since the start of the week, and project it forward to the end of the week, and see if above/below the Apps weekly budget. If above budget, the dApp can then scale down users rewards until back on track.

### Conclusion

Stopping farmers is a difficult task and in some scenarios very difficult to achieve without impacting genuine users. Often the approach is to slow the farmers progress so that their effort/reward ratio is no longer worth it.

### Recommended Service: *Guardian* (Advanced Fraud Detection)

To help Apps tackle many of the challenges described above, we recommend evaluating a service called [**Guardian**](https://docs.guardianstack.ai/) — a modern, enterprise-grade fraud detection and risk assessment platform.

<figure><img src="/files/8UxpdtQxydqXETpkzKoG" alt=""><figcaption></figcaption></figure>

Guardian was built from real-world experience fighting the exact pain points outlined in this document: bot activity, multi-wallet farming, VPN/proxy abuse, device spoofing, browser tampering, and coordinated fraud attempts. It provides accurate detection signals and behavioural risk scoring that can be integrated directly into front-end or back-end flows, making it especially valuable for ecosystems like **VeBetter**, where protecting reward integrity is critical.

This is **not** a paid advertisement; Guardian is simply a tool that aligns well with the needs of sustainability-focused applications.

For projects interested in trying it, a **50% discount** is available using the code **VEBETTER50** at checkout.

Guardian Website: <https://dashboard.guardianstack.ai/>

Guardian Docs: <https://docs.guardianstack.ai/>


# AI Image Validation

X2Earn Apps that send captured photos for image analysis to AI should consider adding specific tasks in their AI prompts to detect:

* Image quality
* Doctored or Unrealistic modifications
* Photo of a computer screen
* Watermarks
* Painted or hand-drawn text replacing real data

... or other unrealistic items that a "fake" photo could capture.

### Example:

In this example we are assuming that we are taking a photo from a dApp runs inside VeWorld and so the photo will be captured by the users mobile camera.

The backend of the app would like the AI to return a json structure giving:

```
{
  "evaluation_feasible": true,
  "doctored_unrealistic_score": 0.0,
  "doctored_unrealistic_reasons": [],
  "screen_capture_score": 0.0,
  "screen_capture_reasons": [],
  "watermark_score": 0.0,
  "watermark_reasons": [],
  "watermark_text": "",
  "painted_text_score": 0.0,
  "painted_text_reasons": [],
  "final_label": "clean",
  "final_confidence": 0.0
}
```

Where:

| Item                                                                  | Description                                                                                                                                                                                                                                                                                  |
| --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| evaluation\_feasible                                                  | True if the quality of the image is sufficient to perform other checks, False if the quality is poor and other checks could be unreliable                                                                                                                                                    |
| <p>doctored\_unrealistic\_score<br>doctored\_unrealistic\_reasons</p> | A score between 0-1 if the AI has detected doctored or unrealistic items in the image. The reasons array will be populated with a summary                                                                                                                                                    |
| <p>screen\_capture\_score<br>screen\_capture\_reasons</p>             | A score between 0-1 if the AI has detected that the image was taken from a computer screen. The reasons array will be populated with a summary                                                                                                                                               |
| <p>watermark\_score<br>watermark\_reasons</p>                         | <p>A score between 0-1 if the AI has detected that the image contains watermarks.</p><p>The reasons array will be populated with a summary</p>                                                                                                                                               |
| <p>painted\_text\_score<br>painted\_text\_reasons</p>                 | <p>A score between 0-1 if the AI has detected user drawn text in the image.<br>The reasons array will be populated with a summary</p>                                                                                                                                                        |
| <p>final\_label<br>final\_score</p>                                   | <p>A final classification label of:</p><ul><li>clean</li><li>doctored\_unrealistic</li><li>screen\_capture</li><li>watermarked</li><li>handdrawn</li><li>multiple\_flags</li><li>inconclusive<br></li></ul><p>A final score between 0-1 as the level of confidence in the classification</p> |

We can use a multi-stage prompt to guide the AI through these tasks:

{% code overflow="wrap" %}

```
Mobile Photo Authenticity Check — Multi-Stage Prompt

Objective:
Given a photo provided by a mobile device, evaluate it through multiple analytical stages to determine:
1. If the photo has been doctored or altered in an unrealistic way.
2. If the photo has been taken from a computer screen rather than being an original capture of a real-world scene.
3. If the photo contains visible or partially obscured watermarks.

Instructions:
You must progress through the stages in sequence. At each stage, clearly indicate whether the photo passes or fails, and explain the reasoning.

Output:
Return only the final JSON object in the specified schema—no extra text.

---

STAGE 1 — Quick Triage (visibility & quality):
1. Is the content visible and in focus enough to evaluate?  
2. Are there heavy obstructions, extreme blur, or tiny resolution?  
3. If evaluation is not feasible, mark `evaluation_feasible=false` and explain briefly.

---

STAGE 2 — “Doctored / Unrealistic” Screening:
Check for visual signs of synthetic or manipulated content. Consider:
- Physics & geometry: inconsistent shadows, impossible reflections, mismatched perspective/vanishing points, warped straight lines near edits.
- Material cues: plastic-like skin, repeated textures, smeared hair/eyelashes, “melting” edges, duplicated fingers/ears.
- Edge artifacts: halos, cut-out borders, fringing, mismatched depth of field.
- Compression anomalies: localized blockiness/quality shifts suggesting pasted regions.
- Lighting: inconsistent color temperature or specular highlights vs. environment.
- Text & patterns: deformed text/logos, repeated tiling.
- Context coherence: scale mismatches, impossible combinations.

Output:
- `doctored_unrealistic_score` (0–1)
- `doctored_unrealistic_reasons` (bullet list)

---

STAGE 3 — “Photo of a Screen” Screening:
Evidence the subject was displayed on a digital screen and re‑photographed:
- Screen structure: visible pixel grid/subpixels, scanlines, PWM/refresh bands, moiré.
- Device clues: bezels, notch, status bar, window chrome, cursor, taskbar, scroll bars.
- Optical clues: rectangular glare, Newton rings, rainbowing consistent with glass.
- Focus/parallax: focus on flat screen surface; keystone perspective of a monitor.
- White point/gamut: uniform backlight glow, overly blue/green whites.

Output:
- `screen_capture_score` (0–1)
- `screen_capture_reasons` (bullet list)

---

STAGE 4 — Watermark / Overlay Detection:
Detect watermarks or ownership/stock overlays that may indicate non-original content or re-use:
- Typical forms: semi-transparent text/logos (“Getty Images”, “Shutterstock”, “Adobe Stock”, creator handles), diagonal repeating patterns, corner logos, date/time stamps that appear composited.
- Visual traits: consistent alpha translucency, uniform repetition across the frame, crisp overlay unaffected by scene lighting/perspective, different resolution/sharpness vs. underlying image.
- Placement: along edges/corners/center diagonals; multiple repeats; patterned tiling.
- Edge cases: legitimate **camera UI overlays** (e.g., timestamp) vs. stock watermarks—distinguish when possible.
- Context: if a watermark is present, note its content (if legible) but **do not identify a person**.

Output:
- `watermark_score` (0–1)
- `watermark_reasons` (bullet list)
- If confidently recognized, add a short `watermark_text` string (e.g., `"Shutterstock"`, `"creator handle @name"`); otherwise empty.

---

STAGE 5 - Detect Hand-Drawn or Painted-On Text:
Detect if the image has text that was manually added using a paint or drawing program, rather than being part of the original scene:
- Look for uneven, non font based handwriting or shapes inconsistent with printed text
- Identify brush strokes, smudging, or digital pen artifacts in the text
- Detect text blending poorly with the image background or overlapping objects unnaturally
- Check for consistent resolution between the text and the rest of the image

Output:
- `painted_text_score` (0-1)
- `painted_text_reasons` (bullet list)

---


STAGE 6 — Final Decision & Confidence:
- `evaluation_feasible`: boolean.  
- `final_label`: one of `"clean"`, `"doctored_unrealistic"`, `"screen_capture"`, `"watermarked"`, `handdrawn`, `"multiple_flags"`, `"inconclusive"`.  
- `final_confidence` (0–1): overall confidence in `final_label`.  
- Keep reasoning concise; cite visible cues only.

---

OUTPUT — JSON Schema (return only this):
{
  "evaluation_feasible": true,
  "doctored_unrealistic_score": 0.0,
  "doctored_unrealistic_reasons": [],
  "screen_capture_score": 0.0,
  "screen_capture_reasons": [],
  "watermark_score": 0.0,
  "watermark_reasons": [],
  "watermark_text": "",
  "painted_text_score": 0.0,
  "painted_text_reasons": [],
  "final_label": "clean",
  "final_confidence": 0.0
}
```

{% endcode %}


# Create B3MO Quests from Contract

This guide shows how to create a B3MO Quest directly through the `B3TRChallenges` contract, without using the VeBetterDAO platform UI.

The walkthrough creates a **Sponsored Public Split Win** quest:

* the creator funds the full prize pool
* anyone can join while the quest is pending
* the first `numWinners` participants that reach `threshold` actions can claim a fixed prize

{% hint style="info" %}
In the contracts, B3MO Quests are still named "challenges". You will see names such as `B3TRChallenges`, `createChallenge`, and `challengeId` in the ABI.
{% endhint %}

## Requirements

You need:

* B3TR in the creator wallet
* VTHO in the creator wallet to pay gas
* the `B3TR`, `B3TRChallenges`, and `XAllocationVoting` contract addresses for your network
* a future allocation round for `startRound`
* optional X2Earn app IDs if you want to count actions only from specific apps

Install the packages:

```shell
yarn add @vechain/sdk-core @vechain/sdk-network ethers
```

## Contract Addresses

| Network | Node URL                      | B3TR                                         | B3TRChallenges                               | XAllocationVoting                            |
| ------- | ----------------------------- | -------------------------------------------- | -------------------------------------------- | -------------------------------------------- |
| Testnet | `https://testnet.vechain.org` | `0x3d920eab29134c23c4477686749608391a635587` | `0x4a6bc52a7eecac26a13e284b75266c0c40cbde91` | `0x8770a4659e42b7b4d7ac7fcaa27ef21b209372de` |
| Mainnet | `https://mainnet.vechain.org` | `0x5ef79995FE8a89e0812330E4378eB2660ceDe699` | `0x92a98f23ca4f9703781cf56088b76a1482667166` | `0x89A00Bb0947a30FF95BEeF77a66AEdE3842Fe5B7` |

## Flow

```mermaid
flowchart TD
  developerScript["Developer Script"] --> readRound["Read currentRoundId"]
  developerScript --> approveB3TR["Approve B3TR"]
  approveB3TR --> createQuest["Call createChallenge"]
  createQuest --> pendingQuest["Quest Pending"]
  pendingQuest --> usersJoin["Users Join"]
  usersJoin --> activeQuest["Quest Active"]
  activeQuest --> splitClaim["Eligible Users Claim SplitWin Prize"]
```

## Create a Sponsored Public Split Win Quest

Set the environment variables:

```shell
NODE_URL=https://testnet.vechain.org
PRIVATE_KEY=your_private_key_without_0x
CREATOR_ADDRESS=0xyour_wallet_address
B3TR_ADDRESS=0x3d920eab29134c23c4477686749608391a635587
B3TR_CHALLENGES_ADDRESS=0x4a6bc52a7eecac26a13e284b75266c0c40cbde91
X_ALLOCATION_VOTING_ADDRESS=0x8770a4659e42b7b4d7ac7fcaa27ef21b209372de
```

Then run:

```typescript
import {
  ABIContract,
  Address,
  Clause,
  HexUInt,
  Transaction,
  type TransactionClause,
} from "@vechain/sdk-core";
import {
  ProviderInternalBaseWallet,
  signerUtils,
  ThorClient,
  VeChainProvider,
} from "@vechain/sdk-network";
import { parseEther } from "ethers";

const ChallengeKind = { Stake: 0, Sponsored: 1 } as const;
const ChallengeVisibility = { Public: 0, Private: 1 } as const;
const ChallengeType = { MaxActions: 0, SplitWin: 1 } as const;

const b3trAbi = [
  {
    type: "function",
    name: "approve",
    stateMutability: "nonpayable",
    inputs: [
      { name: "spender", type: "address" },
      { name: "amount", type: "uint256" },
    ],
    outputs: [{ name: "", type: "bool" }],
  },
] as const;

const xAllocationVotingAbi = [
  {
    type: "function",
    name: "currentRoundId",
    stateMutability: "view",
    inputs: [],
    outputs: [{ name: "", type: "uint256" }],
  },
] as const;

const challengesAbi = [
  {
    type: "function",
    name: "createChallenge",
    stateMutability: "nonpayable",
    inputs: [
      {
        name: "params",
        type: "tuple",
        components: [
          { name: "kind", type: "uint8" },
          { name: "visibility", type: "uint8" },
          { name: "challengeType", type: "uint8" },
          { name: "stakeAmount", type: "uint256" },
          { name: "startRound", type: "uint256" },
          { name: "endRound", type: "uint256" },
          { name: "threshold", type: "uint256" },
          { name: "numWinners", type: "uint256" },
          { name: "appIds", type: "bytes32[]" },
          { name: "invitees", type: "address[]" },
          { name: "title", type: "string" },
          { name: "description", type: "string" },
          { name: "imageURI", type: "string" },
          { name: "metadataURI", type: "string" },
        ],
      },
    ],
    outputs: [{ name: "", type: "uint256" }],
  },
] as const;

const required = (name: string) => {
  const value = process.env[name];
  if (!value) throw new Error(`Missing ${name}`);
  return value;
};

async function main() {
  const thor = ThorClient.at(required("NODE_URL"));
  const creatorAddress = required("CREATOR_ADDRESS");

  const provider = new VeChainProvider(
    thor,
    new ProviderInternalBaseWallet([
      {
        privateKey: HexUInt.of(required("PRIVATE_KEY").replace(/^0x/, "")).bytes,
        address: creatorAddress,
      },
    ]),
    false,
  );

  const voting = thor.contracts.load(
    required("X_ALLOCATION_VOTING_ADDRESS"),
    xAllocationVotingAbi,
  );
  const [currentRound] = await voting.read.currentRoundId();

  const stakeAmount = parseEther("1000");
  const startRound = currentRound + 1n;
  const endRound = startRound + 1n;

  const params = {
    kind: ChallengeKind.Sponsored,
    visibility: ChallengeVisibility.Public,
    challengeType: ChallengeType.SplitWin,
    stakeAmount,
    startRound,
    endRound,
    threshold: 10n,
    numWinners: 5n,
    appIds: [],
    invitees: [],
    title: "Recycle 10 items",
    description: "First 5 participants with 10 tracked actions win.",
    imageURI: "",
    metadataURI: "",
  };

  const approveClause = Clause.callFunction(
    Address.of(required("B3TR_ADDRESS")),
    ABIContract.ofAbi(b3trAbi).getFunction("approve"),
    [required("B3TR_CHALLENGES_ADDRESS"), stakeAmount],
  ) as TransactionClause;

  const createQuestClause = Clause.callFunction(
    Address.of(required("B3TR_CHALLENGES_ADDRESS")),
    ABIContract.ofAbi(challengesAbi).getFunction("createChallenge"),
    [params],
  ) as TransactionClause;

  const clauses = [approveClause, createQuestClause];
  const gas = await thor.transactions.estimateGas(clauses, creatorAddress);
  const txBody = await thor.transactions.buildTransactionBody(
    clauses,
    gas.totalGas,
  );

  const signer = await provider.getSigner(creatorAddress);
  const rawSignedTx = await signer.signTransaction(
    signerUtils.transactionBodyToTransactionRequestInput(txBody, creatorAddress),
  );

  const signedTx = Transaction.decode(
    HexUInt.of(rawSignedTx.slice(2)).bytes,
    true,
  );

  const sent = await thor.transactions.sendTransaction(signedTx);
  const receipt = await sent.wait();

  console.log(`Transaction: ${sent.id}`);
  console.log(`Reverted: ${receipt?.reverted}`);
}

main().catch(error => {
  console.error(error);
  process.exit(1);
});
```

The transaction has two clauses:

1. `B3TR.approve(B3TRChallenges, stakeAmount)`
2. `B3TRChallenges.createChallenge(params)`

If the second clause reverts, the whole transaction reverts and the approval is not applied.

## Parameters

| Field           | Sponsored Public Split Win value                                         |
| --------------- | ------------------------------------------------------------------------ |
| `kind`          | `1` (`Sponsored`)                                                        |
| `visibility`    | `0` (`Public`)                                                           |
| `challengeType` | `1` (`SplitWin`)                                                         |
| `stakeAmount`   | Total B3TR prize pool, in wei                                            |
| `startRound`    | A future allocation round. Use `currentRoundId() + 1` for the next round |
| `endRound`      | Last round where actions count                                           |
| `threshold`     | Minimum action count required to claim a Split Win slot                  |
| `numWinners`    | Number of prize slots                                                    |
| `appIds`        | Empty array for all apps, or selected X2Earn app IDs                     |
| `invitees`      | Empty array for public quests                                            |
| `title`         | Max 120 bytes                                                            |
| `description`   | Max 500 bytes                                                            |
| `imageURI`      | Optional, max 512 bytes                                                  |
| `metadataURI`   | Optional, max 512 bytes                                                  |

For Split Win, `stakeAmount / numWinners` is fixed when the quest is created. The contract requires at least `1 B3TR` per winner.

## Valid Quest Combinations

| Kind        | Visibility | Type         | Required fields                                                                     |
| ----------- | ---------- | ------------ | ----------------------------------------------------------------------------------- |
| `Sponsored` | `Public`   | `SplitWin`   | `threshold > 0`, `numWinners > 0`, no invitees required                             |
| `Sponsored` | `Private`  | `MaxActions` | `threshold = 0`, `numWinners = 0`, invitees optional                                |
| `Sponsored` | `Private`  | `SplitWin`   | `threshold > 0`, `numWinners > 0`, invitees optional                                |
| `Stake`     | `Private`  | `MaxActions` | `threshold = 0`, `numWinners = 0`, participants must approve and stake when joining |

Public Stake quests, public MaxActions quests, and Stake SplitWin quests are invalid.

## Lifecycle

* `Pending`: users can join. The creator can cancel before `startRound`.
* `Active`: the quest has started and actions are counted through VeBetterPassport.
* `Completed`: rewards or refunds can be claimed.
* `Cancelled`: creator cancelled before the quest started.
* `Invalid`: the quest did not meet its activation rules.

Split Win quests do not use `completeChallenge`. Winners call `claimSplitWinPrize` while the quest is active. After `endRound`, the creator can call `claimCreatorSplitWinRefund` to reclaim unclaimed slots.

MaxActions quests are different: once the quest has ended, a participant or creator calls `completeChallenge`, then winners call `claimChallengePayout`.

## Common Errors

| Error                          | Meaning                                                            |
| ------------------------------ | ------------------------------------------------------------------ |
| `InvalidAmount`                | `stakeAmount` is zero                                              |
| `BetAmountBelowMinimum`        | `stakeAmount` is below `minBetAmount()`                            |
| `InvalidStartRound`            | `startRound` is not in the future                                  |
| `InvalidEndRound`              | `endRound` is before `startRound`                                  |
| `InvalidChallengeTypeForCombo` | The selected kind, visibility, and type combination is not allowed |
| `InvalidTypeConfiguration`     | `threshold` or `numWinners` does not match the selected type       |
| `InsufficientPrizePerWinner`   | Split Win prize per winner is below `1 B3TR`                       |
| `ChallengeUnknownApp`          | One of the selected `appIds` does not exist in `X2EarnApps`        |
| `MaxChallengeDurationExceeded` | The round range is longer than `maxChallengeDuration()`            |
| `MaxSelectedAppsExceeded`      | Too many selected app IDs                                          |

Use `maxChallengeDuration()`, `maxSelectedApps()`, `maxParticipants()`, and `minBetAmount()` on `B3TRChallenges` to read the current limits before building your form or script.


# RuleBook for Apps

This ruleBook is a proposal based application, to protect the sustainability and fairness of the ecosystem.

To preserve fair distribution of weekly allocation and prevent gaming of the system, the following **rules** and **prohibitions** apply to any App seeking or receiving **B3TR incentives.**

For more context, please refer to these updates:

* [12 May 2025 Governance update](https://governance.vebetterdao.org/proposals/44152250438943884062434103573124650362722284846407941118984384695777887098183)
* [20 July 2025 Governance update](https://governance.vebetterdao.org/proposals/92759402299820464968039964071970445559062409931673742225647875754087456338977)

### 1. Direct Double Dipping <a href="#id-1-direct-double-dipping" id="id-1-direct-double-dipping"></a>

Apps must not use their own rewards to incentivize behaviors already directly compensated by protocol-level Vote2Earn incentives (e.g., proposal voting).

### 2. Recursive Rewarding (Incentive Layering) <a href="#id-2-recursive-rewarding-incentive-layering" id="id-2-recursive-rewarding-incentive-layering"></a>

Apps must not reward users for interacting with another incentivized App when:

* The action is already subject to B3TR allocation.
* The behavior results in redundant compensation for the same activity.

This includes:

* Wrapping or mirroring existing Apps to farm additional incentives.
* Stacking reward layers for a single on-chain action.
* Reciprocal arrangements between Apps that loop rewards for shared behaviors.

### 3. Fragmentation for Reward Multiplication <a href="#id-3-fragmentation-for-reward-multiplication" id="id-3-fragmentation-for-reward-multiplication"></a>

Splitting functionalities into multiple Apps for the purpose of inflating total allocations is not allowed. Interdependent or co-deployed Apps may be evaluated as a unit.

### 4. Social Amplification Loops <a href="#id-4-social-amplification-loops" id="id-4-social-amplification-loops"></a>

Rewarding users for promoting, relaying, or proxying already-incentivized actions (e.g., vote sharing or vote proxying) is disallowed if the base action is already rewarded by the protocol.

### 5. In-app Governance <a href="#id-5-in-app-governance" id="id-5-in-app-governance"></a>

#### 5.1. User-Affirmed Governance & UI

* **User Confirmation**: Any modification of user vote preferences must be executed through a clear, user-signed transaction. Background updates without a dedicated user-confirmed transaction are prohibited.
* **Visibility of Choice**: The UI must display all endorsed Apps, ensuring users can modify selections for any project before confirmation.
* **Opt-Out Requirement**: Apps must provide a visible UI component to opt out of the governance service at any time.
* **Conversion Allowance**: Apps may include a function to convert B3TR to VOT3 when a user initiates in-app voting as long as such transaction is disclosed and confirmed by the user.

#### 5.2. Self-Promotion

Apps may prioritize themselves in the interface and pre-fill vote preferences as follows:

* **New Users**: If no existing preferences exist, the App may pre-fill with 100% weight toward itself.
* **Existing Users**: The App may add itself to the list, provided its pre-filled weight is lower than or equal to any individual App in the user’s new selection.

#### 5.3. True Neutrality

If an App provides governance services and the user opts in without specifying preferences, or preferences become ineligible, the following defaults apply:

* **App Allocation**: No vote shall be cast until the user explicitly confirms a selection through a signed transaction.
* **Proposal Voting**: DAO-wide proposals must be set to “Abstain.”

#### 5.4. Vote Redistribution

* **Weight Redistribution**: If an App in a user’s preference becomes ineligible, its weight must be redistributed equally among the user’s remaining selected Apps.
* **Redirection Prohibition**: Apps cannot redirect weight from ineligible projects to the host App or any project not explicitly included in the user’s most recent confirmed selection. If all projects become ineligible in the user’s selection, Rule 5.3 applies.
* **Vote Modification**: Apps are prohibited from modifying a user’s existing vote preferences, including the addition or removal of eligible projects, except where explicitly required by the redistribution logic defined in Rule 5.4 (Weight Redistribution and Redirection Prohibition), and according to Self-Promotion described in Rule 5.2.

**Exemption**: Rules under section 5 apply to all in-app voting integrations unless limited by the functional logic of the native VBD auto-voter, as its automation and logic are subject to DAO governance and community contributions.

### 6. Anti-Bribery Measures <a href="#id-6-anti-bribery-measures" id="id-6-anti-bribery-measures"></a>

Apps may not offer manual rewards, “x2earn” multipliers, or any perks that assist in unlocking them if such incentives are conditioned on the user voting for that specific App.

### 7. Capital Integrity <a href="#id-7-capital-integrity" id="id-7-capital-integrity"></a>

Apps are prohibited from using allocation or grant funding received from the VeBetter DAO Treasury to vote in weekly App allocation rounds.

**Exemption**: Apps maintain the right to use Treasury grant funds and allocation to support and vote on proposals.

TLDR;

* Rewarding users beyond the App action-based incentives is strictly prohibited.
* No extra rewards for actions already incentivized by VeBetter are allowed.
* In-app governance must be user-affirmed, transparent, and neutral.
* Bribing users for votes, as well as using Treasury grant funding or App allocation to vote in weekly allocation rounds, is prohibited.

<br>


# Submit Your App

As of the start of November the VeChain node holders, referred to as "endorsers," are serving as the primary decision-makers in determining which XApps are admitted to the VeBetter ecosystem. Developers and innovators can engage with the ecosystem and submit their [X2Earn applications](/vebetter/x2earn-apps) through a structured process that includes community endorsement and voting.

## Submission Process

To submit an app to the VeBetter ecosystem, every project must first acquire a Creator NFT, which verifies the creator and allows them to participate in the endorsement process. Here’s how it works:

1. **Acquiring the Creator NFT**
   * **Application Process**: XApp creators begin by filling out a form on the VeBetter platform, which initiates a background check to verify the team and the app’s legitimacy.
   * **Alternative Paths**: Creators can also apply for a grant through the [VeChain Grants program](https://vechain.org/grants/). If successful, they will receive funding as well as a Creator NFT, which validates their project within the ecosystem.
2. **On-Chain XApp Submission**\
   After receiving the Creator NFT, XApp creators can submit their app on-chain for [endorsement](/vechain-node-and-staking-guides/legacy-vechain-node-guides-pre-stargate/endorsement-guide-for-vechain-node-holders) consideration. This official submission registers the app on the VeBetter platform, allowing it to seek endorsements from VeChain node holders.
3. **Connecting with Endorsers**\
   Upon acquiring the Creator NFT, XApp creators gain access to the VeBetter XApps Creators Discord server, where they can network with VeChain node holders who may endorse their app. This community platform provides opportunities for creators to present their app, build relationships with potential endorsers, and gain the necessary endorsement score to enter allocation rounds.
4. **Endorsement and Funding Eligibility**\
   Once an app is submitted and endorsed with a cumulative score of 100, it will officially be added to the VeBetter ecosystem. It will be eligible to be weekly funded with B3TR tokens as a result of the [allocation rounds](/vebetter/x2earn-allocations): you will compete against other apps to receive as many B3TR tokens as possible, with holders of the token that will vote for the app they think deserves it the most.

{% content-ref url="/pages/Z1WsYCFIK80Nx1tjrxed" %}
[Endorsement Guide for VeChain Node Holders](/vechain-node-and-staking-guides/legacy-vechain-node-guides-pre-stargate/endorsement-guide-for-vechain-node-holders)
{% endcontent-ref %}

## **On-Chain App Submission Requirements**

When submitting your app to VeBetter you will need to provide 2 important information:

* **Treasury address**: this is the address where B3TR tokens will be sent in case you will need to withdraw some tokens from the received weekly allocations (eg: you need some B3TR for marketing, team shares, etc.). This address can be a multi-sig or a simple EOA, it's up to you.
* **Admin address**: this is the address that has superpowers for your app; it can update any details of the app, change the Treasury address, or move the ownership to another wallet. You can use the same wallet you use for the Treasury, another multi-sig, or a simple EOA as well.

## Your APP ID

Once your app is added **you will obtain an APP\_ID** that VeBetter and other projects will use to recognize your app.\
You **will also need to use your Admin address to add a&#x20;*****Reward Distributor*** to distribute your rewards to the users. This is a simple address and it should belong to the contract or wallet that you will use to distribute the rewards. Be aware that this address can also withdraw funds, so protect its access correctly.

## B3TR Allocations

You will **receive your first B3TR tokens at least one week after joining VeBetter**, following the completion of at least one voting round. Therefore, you will need to address the scenario where people might see your app in VeBetter and attempt to use it before you are able to distribute rewards.

## Your App categories

When submitting your app, you can select up to 2 categories that best describe its purpose and functionality. These categories help VeBetter filter and organize apps effectively, ensuring users can easily discover relevant app.

Categories in your App Metadata are stored using their `id` value, while the `name` is simply how the category will appear inside VeBetterDAO during the submission or the metadata modification process.

```typescript
[
  { "id": "others",                        "name": "Others" },
  { "id": "education-learning",            "name": "Learning" },
  { "id": "fitness-wellness",              "name": "Lifestyle" },
  { "id": "green-finance-defi",            "name": "Web3" },
  { "id": "green-mobility-travel",         "name": "Transportation" },
  { "id": "nutrition",                     "name": "Food & Drinks" },
  { "id": "plastic-waste-recycling",       "name": "Recycling" },
  { "id": "renewable-energy-efficiency",   "name": "Energy" },
  { "id": "sustainable-shopping",          "name": "Shopping" },
  { "id": "pets",                          "name": "Pets" }
]

```

{% hint style="info" %}
If you are submitting a **native application,** please link to your app a landing page.
{% endhint %}


# X2Earn Creators NFT

The **X2Earn Creator NFTs** are integral to VeBetter’s process for managing and validating new XApp submissions. These NFTs serve as an access key for creators, enabling them to submit their applications on-chain and engage with the VeBetter endorsement process through VeChain node holders.

## **Overview**

* **Purpose**: X2Earn Creator NFTs are used within VeBetter to authorize new XApp submissions and provide access to the endorsers (VeChain node holders). These NFTs ensure that only vetted and verified creators can submit apps for consideration.
* **Standard**: Creator NFTs are non-transferable tokens compliant with the ERC721 standard, implemented using the OpenZeppelin (OZ) library.

## **Minting and Eligibility**

* **Minting Authority**: Only the X2Earn App Review Panel has the authority to mint Creator NFTs. The panel grants these NFTs if they deem the app suitable, legitimate, and ready for the endorsement process within VeBetter.
* **Non-Transferability**: Creator NFTs are non-transferable, meaning they cannot be sold or transferred to another user, ensuring that only the verified creator retains access.

## **Functionality and Permissions**

* **Submission Access**: Once an app creator have granted a Creator NFT, they can submit their XApp on-chain for endorsement. This submission formally registers the app within the VeBetter ecosystem, allowing it to seek endorsements from node holders.
* **Additional NFT for Team member**: After the initial submission, the XApp admin (creator) can add up to two additional creators, for a maximum of three creators per application. Each additional creator will receive their own Creator NFT.
* **Single NFT Limitation**: Users are limited to holding only one Creator NFT at any given time. If a user wishes to contribute to another application, they must either revoke their current Creator NFT from the xapp admin or use a separate account.

## **Blacklisting and Burn Mechanism**

* **Blacklisting Policy**: If an XApp is blacklisted for any reason, and the creator is not associated with any other active XApp, their Creator NFT will be burned. This prevents creators of non-compliant or blacklisted apps from submitting new projects without re-approval.
* **NFT Burn**: The burning mechanism ensures that blacklisted creators cannot bypass VeBetter’s review process by holding onto their Creator NFT. This policy enhances the integrity of the ecosystem by holding creators accountable for their submissions.

## Key Points for Developers

* **Token Standard**: ERC721 (non-transferable)
* **Minting Authority**: X2Earn App Review Panel
* **Max NFTs per User**: One NFT per user, regardless of the number of XApps
* **Additional NFTs**: Admin have the ability to mint up to two extra NFTs for team members. These additional creators will be restricted to their assigned app only and cannot use their creator NFTs to submit new apps.
* **Single Creator Association**: Each creator is assigned to exactly one app.


# Resources

To aid in the development process, we've created several valuable resources:

* Play with our [test environment](https://dev.testnet.governance.vebetterdao.org/)\
  Utilize our testnet environment to add apps to the ecosystem, interact with smart contracts, and manage reward distribution. Detailed information about the test environment can be found in its [dedicated section](#test-environment), providing you with a sandbox to refine and test your applications before going live.
* [VeChain Kit](https://vechain-kit.vechain.org/): an all-in-one javascript library for building VeChain applications.
* Read the [Integration](/developer-guides/get-started) and the [Sustainability Proofs](/developer-guides/sustainability-proof-and-impacts) sections to understand how to distribute B3TR tokens
* **X-App-Template** (<https://github.com/vechain/x-app-template>)\
  This template serves as a foundational guide to help you code your app and interact effectively with VeBetter. It's a demo of an app where you can scan grocery receipts and be rewarded if you buy sustainably.
* [Vechain Getting Started Documentation](https://docs.vechain.org/developer-resources/getting-started)\
  Documentation of everything you need to know about vechain and blockchain technology to create a decentralized app.
* [VeBetter contracts](https://github.com/vechain/vebetterdao-contracts)\
  A package containing all the smart contracts used in mainnet. You can also install this repository as a dependency in your project and use it to access the ABIs of the contracts and their addresses.


# Automation

Learn how to automate your weekly voting and reward claiming. A relayer service handles all transactions for you with a 10% fee (capped at 100 B3TR) to cover gas costs.

## Auto-Voting & Auto-Claiming Rewards

{% hint style="success" %}
**MVP Phase**: Automation is currently in its MVP phase. Features, requirements, and fee structures are subject to change based on user feedback and operational requirements.
{% endhint %}

### Overview

This feature allows you to automate your weekly voting and reward claiming process. Once enabled, a relayer service will automatically cast your votes and claim your rewards on your behalf each week.

### Getting Started

1. Navigate to the [**allocations**](https://governance.vebetterdao.org/allocations) **page**
2. Ensure you meet all eligibility [requirements](https://docs.vebetterdao.org/vebetter/automation#whats-required-to-enable)
3. Select your preferred apps for auto-voting
4. **Toggle-on** Auto-voting & claim
5. That's it! Your votes and rewards will be handled starting from next week onwards.

<div data-full-width="false" data-with-frame="true"><figure><img src="/files/tVT6b35RbowwS1T6iwrE" alt="" width="375"><figcaption></figcaption></figure></div>

### What’s Required to Enable

To use this service, you must meet **all** of the following criteria at the time of snapshot:

* **Hold at least 1 VOT3 token** in your wallet
* **Complete 3 sustainable actions** before the snapshot
* **Not be flagged as a bot** by any App owner
* **Have selected at least one eligible app** for voting

### How It Works

#### Note for First-Time Activation

If you enable automation **during the current round**, the service will kick in **from the next round onwards**.

**What this means:**

* You’ll still need to **manually claim your rewards** when the current round ends.

#### Weekly Automation Cycle

1. **Snapshot**: At the start of each voting round, a snapshot is taken to determine eligible participants
2. **Auto-Voting**: The service automatically casts votes based on your selected app preferences
3. **Auto-Claiming**: After the round ends, your rewards are automatically claimed and deposited to your wallet

### Service Fee

#### 📊 Fee Structure

To cover the gas costs of automating your transactions, a **10% fee** is applied to your weekly claimed rewards.

{% hint style="info" %}
The fee and cap are **community-driven**. Since we are still in the MVP phase, this setup helps us fine-tune the model and better understand the operational costs of keeping the service running. The community is welcome to propose adjustments and share their findings so we can collaboratively evaluate whether updates are appropriate.
{% endhint %}

**Fee Details:**

* **Rate**: 10% of your weekly rewards
* **Cap**: Maximum fee of **100 B3TR** per week
* **Benefit**: You don't pay any gas fees directly. The service handles all transactions for you

**Fee Example:**

| Your Weekly Rewards | Fee (10%)  | You Receive | Service Gas Coverage |
| ------------------- | ---------- | ----------- | -------------------- |
| 500 B3TR            | 50 B3TR    | 450 B3TR    | ✅ Full gas paid      |
| 1,500 B3TR          | 100 B3TR\* | 1,400 B3TR  | ✅ Full gas paid      |
| 5,000 B3TR          | 100 B3TR\* | 4,900 B3TR  | ✅ Full gas paid      |

{% hint style="info" %}
⚡ **Why the fee?** The service monitors all automation users and automatically processes transactions on your behalf. The 10% fee (capped at 100 B3TR) covers the gas costs and ensures reliable, hands-free automation every week.
{% endhint %}

### Important: Maintaining Eligibility

Your automation can be automatically **disabled** if any of the following occurs:

#### ⚠️ Auto-Disable Scenarios

**1. App Ineligibility**

* If all the apps you've selected for auto-voting become ineligible (removed or suspended), your automation will be turned off
* **Action required**: Update your app selections to include eligible apps, then re-enable auto-voting

**2. VOT3 Balance**

* If your VOT3 balance drops below 1 token at the time of snapshot
* **Action required**: Ensure you maintain at least 1 VOT3 in your wallet

**3. Stops Performing Sustainable Actions**

* If your [cumulative participation score](https://docs.vebetterdao.org/vepassport/checks/proof-of-participation#cumulative-score) drops below the threshold
* **Action required**: Continue to perform sustainable actions to maintain your eligibility

**4. Bot Detection**

* If you are flagged as a bot by any app owner during the snapshot
* **Action required**: File an appeal and complete the KYC flow. Then you need to come back to the [allocations](https://governance.vebetterdao.org/allocations) page to setup your automation again.

> 💡 **Tip**: Regularly check your automation status and app selections to ensure uninterrupted automation.

### Constraints <a href="#important-constraints" id="important-constraints"></a>

#### Manual Actions While Auto-Voting Is Active <a href="#manual-actions-while-auto-voting-is-active" id="manual-actions-while-auto-voting-is-active"></a>

When auto-voting is **active**, you **cannot** vote or claim rewards manually. The service handles everything automatically.

**Manual Claiming After 5 Days (Exception):**

* If the service hasn't claimed your rewards within **5 days** after a round ends, you can claim them manually
* This 5-day window ensures the automation service has enough time to process all auto-claims
* Your rewards are always protected. You'll never lose them

> ⚠️ **Remember**: Once automation is active, sit back and let the service do its job. Manual claiming is only available as a backup after 5 days.

### Understanding Your Status <a href="#understanding-your-status" id="understanding-your-status"></a>

Your automation status will show one of three states the allocations page:

#### 🟡 Auto-Voting Is Enabled <a href="#f0-9f-9f-a1-starting-next-round" id="f0-9f-9f-a1-starting-next-round"></a>

{% hint style="info" %}
**Auto-voting is enabled. It takes effect from the next round.**
{% endhint %}

* **What it means**: You just enabled auto-voting, but automation hasn't started yet
* **What happens**:
  * Current round: You need to vote manually (if you haven't already)
  * Next round: Automation will automatically kick in
* **Why the delay**: Auto-voting activates at the beginning of the next round to ensure a clean start with the snapshot

#### 🟢 Auto-Voting Is Active <a href="#f0-9f-9f-a2-auto-voting-active" id="f0-9f-9f-a2-auto-voting-active"></a>

{% hint style="info" %}
**Auto-voting is active. Your vote and rewards will be handled automatically..**
{% endhint %}

* **What it means**: Auto-voting is fully active and working
* **What happens**: The service automatically votes and claims rewards for you every week
* **No action needed**: Sit back and relax. Everything is handled automatically

#### :red\_circle: Auto-Voting Is Disabled

{% hint style="info" %}
**Auto-voting is disabled. It takes effect from the next round.**
{% endhint %}

* **What it means**: Auto-voting is now disabled
* **Why**:
  * You just toggled-off the automation. It will be deactivated from the next round onwards
  * It's been toggled-off because you failed to maintain [eligibility](https://docs.vebetterdao.org/vebetter/automation#eligibility-requirements).

> 💡 **Tip**: Visit the DAO regularly to ensure automation remains active.

***

**Need Help?** If you have questions about auto-voting or encounter any issues, please contact our support team.


# Relayers

### Overview

Relayers are services that execute auto-voting actions on behalf of users who have enabled automation. They watch the blockchain, see who has opted in, submit votes, and claim rewards — all automatically. In return, relayers earn a share of the fee pool.

Anyone can become a relayer: apps, community members, developers. Registration is open — just call `registerRelayer()` on the RelayerRewardsPool contract.

### How Relayers Earn

Every user served pays 10% of their weekly rewards (max 100 B3TR per user) into a shared pool. At the end of the round, that pool gets split among all relayers based on how much work each one did.

#### Weighted Points

Work is measured in weighted points:

| Action                       | Points       | Why                |
| ---------------------------- | ------------ | ------------------ |
| Casting a vote for a user    | 3 points     | More gas-intensive |
| Claiming rewards for a user  | 1 point      | Less gas-intensive |
| **Full user (vote + claim)** | **4 points** |                    |

More points = bigger share of the pool.

**Example**: If the pool has 1,000 B3TR and a relayer completes 200 out of 800 total weighted points, they earn 250 B3TR.

#### All-or-Nothing Rule

Every user must be served. If even one user gets missed — no vote cast, no rewards claimed — nobody gets paid. The whole pool stays locked until every single user is taken care of.

**Safety net**: If registered relayers don't finish within 5 days after the round ends, anyone can step in and complete the remaining work. This ensures users always receive their rewards.

#### First-Come-First-Served

If another relayer handles a user before you, you get nothing for that user (and waste gas trying). Relayers compete to serve users as quickly as possible.

### Why Apps Should Be Relayers

If you're an app on VeBetterDAO, becoming a relayer is a strategic advantage:

* **Before**: You pay veDelegate to get votes directed your way
* **After**: Your users set you as a preference, you execute their votes (which go to your app), and you earn relayer fees on top

You go from **paying for votes** to **getting paid to handle them**.

> Important: Add your app to the user's preference list — don't replace their other choices.

### vs veDelegate

| Feature                   | veDelegate                        | VeBetterDAO Auto-Voting |
| ------------------------- | --------------------------------- | ----------------------- |
| X Allocation voting       | Yes                               | Yes                     |
| Governance voting         | Yes                               | No (manual only)        |
| Compounding (B3TR → VOT3) | Auto                              | Manual                  |
| Token custody             | Leaves wallet                     | Stays in wallet         |
| Centralization            | Single entity                     | Many relayers           |
| Cost to apps              | Apps may need to pay transactions | Apps earn fees          |


# Running a Relayer Node

There are three ways to run a relayer, from easiest to most advanced:

### Option 1: Run on the Web

The simplest way to get started. Use the [Relayer Dashboard](https://vechain.github.io/b3tr) to register and run a relayer directly from your browser — no installation, no server, no command line.

1. Connect your wallet
2. Register as a relayer
3. Start the relayer from the dashboard UI

Best for: trying it out, small-scale operation, non-technical users.

### Option 2: Run with Docker

Run the official relayer node image locally or on a server. Reliable, always-on, no code to manage.

```bash
docker run -d \
  -e MNEMONIC="your twelve word mnemonic phrase here" \
  -e RELAYER_NETWORK=mainnet \
  --restart unless-stopped \
  vechain/vebetterdao-relayer-node
```

Environment variables:

| Variable              | Required                       | Description                           |
| --------------------- | ------------------------------ | ------------------------------------- |
| `MNEMONIC`            | Yes (or `RELAYER_PRIVATE_KEY`) | Wallet mnemonic                       |
| `RELAYER_PRIVATE_KEY` | Yes (or `MNEMONIC`)            | Wallet private key                    |
| `RELAYER_NETWORK`     | Yes                            | `mainnet` or `testnet-staging`        |
| `RUN_ONCE`            | No                             | Run once then exit (useful for cron)  |
| `DRY_RUN`             | No                             | Simulate without sending transactions |

Best for: reliable 24/7 operation on a VPS or home server.

### Option 3: Fork and Optimize

Fork the [relayer node source code](https://github.com/vechain/vebetterdao-contracts/tree/main/relayer-node) and build your own optimized version.

```bash
git clone https://github.com/vechain/vebetterdao-contracts
cd relayer-node
yarn install
yarn start
```

The default node discovers users, batches votes and claims, and loops every 5 minutes. By forking you can:

* Optimize batching strategies and gas usage
* Implement custom user prioritization
* Add monitoring, alerting, and logging
* Run multiple instances with load balancing
* Integrate with your app's backend

Best for: competitive relayers, apps running relaying as a service, maximizing profitability.

### Gas Costs & Profitability

| Action                       | Gas       | VTHO Cost       | B3TR Equivalent |
| ---------------------------- | --------- | --------------- | --------------- |
| Vote (5-8 apps)              | \~441,000 | \~4.41 VTHO     | \~0.075 B3TR    |
| Claim                        | \~208,000 | \~2.08 VTHO     | \~0.035 B3TR    |
| **Total per user per round** |           | **\~6.49 VTHO** | **\~0.11 B3TR** |

Average user earns \~90-190 B3TR/round. At 10% fee: \~9-19 B3TR per user into the pool. Relayer cost per user: \~0.11 B3TR. **Margin: \~8.9-18.9 B3TR per user.**

***


# Smart Contracts

### Contract Addresses

| Contract           | Address                                      |
| ------------------ | -------------------------------------------- |
| RelayerRewardsPool | `0x34b56f892c9e977b9ba2e43ba64c27d368ab3c86` |
| XAllocationVoting  | `0x89A00Bb0947a30FF95BEeF77a66AEdE3842Fe5B7` |
| VoterRewards       | `0x838A33AF756a6366f93e201423E1425f67eC0Fa7` |

### RelayerRewardsPool

Manages relayer registration, action tracking, and reward distribution.

#### Registration

Anyone can register as a relayer by calling `registerRelayer()`. No admin approval needed.

```solidity
registerRelayer()           // Self-register as a relayer (open to anyone)
unregisterRelayer(address)  // Admin only (POOL_ADMIN_ROLE)
isRegisteredRelayer(address) -> bool
getRegisteredRelayers() -> address[]
```

#### Configuration

```
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
```

#### Reward Distribution

```
relayerShare = (relayerWeightedActions / completedWeightedActions) * totalRewards
```

Rewards are claimable when:

* The round has ended
* All work is done (`completedWeightedActions >= totalWeightedActions`)

#### Key Functions

```solidity
// 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)
```

### XAllocationVoting (Auto-Voting Functions)

Auto-voting was added in v8 via the `AutoVotingLogicUpgradeable` module.

#### User Functions

```solidity
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 status
```

#### Relayer Functions

```solidity
castVoteOnBehalfOf(address voter, uint256 roundId)
```

This function:

1. Validates early access (registered relayer during the 5-day window)
2. Gets user preferences, filters eligible apps
3. Splits voting power equally across eligible apps
4. Casts the vote
5. Registers a VOTE action on RelayerRewardsPool (3 weight points)

#### Snapshot Functions

```solidity
isUserAutoVotingEnabledForRound(address, uint256) -> bool
getTotalAutoVotingUsersAtRoundStart() -> uint256
getTotalAutoVotingUsersAtTimepoint(uint48) -> uint256
```

Auto-voting status is checkpointed: changes take effect from the next round, not the current one.

### VoterRewards (Fee Integration)

Fee deduction happens in `VoterRewards.claimReward()`:

1. Check user had auto-voting enabled at round start (checkpointed)
2. Calculate raw rewards (voting + GM reward)
3. If auto-voting: `fee = min(totalReward * 10/100, 100 B3TR)`
4. Fee approved + deposited to `RelayerRewardsPool.deposit(fee, cycle)`
5. Register CLAIM action for `msg.sender` (1 weight point)
6. Net reward transferred to voter wallet

`msg.sender` calling `claimReward()` IS the relayer credited for the CLAIM action.

### Early Access Windows

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 Lifecycle

```
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()
```

***

### Resources

* [Relayer Dashboard](https://vechain.github.io/b3tr)
* [Governance Proposal (full spec)](https://governance.vebetterdao.org/proposals/93450486232994296830196736391400835825360450263361422145364815974754963306849)
* [Discourse Proposal (design rationale)](https://vechain.discourse.group/t/vebetterdao-proposal-auto-voting-for-x-allocation-with-gasless-voting-and-relayer-rewards/559)
* [Contract Source Code](https://github.com/vechain/vebetterdao-contracts)
* [NPM Package: @vechain/vebetterdao-contracts](https://www.npmjs.com/package/@vechain/vebetterdao-contracts)


# VePassport

**VePassport** is a system that allows Apps on VeChain to determine whether a wallet belongs to a bot or a real person. The Apps using this technology include, first and foremost, **VeBetter**, which verifies the authenticity of wallets during voting. Other Apps within the VeBetter ecosystem, often facing issues with fake accounts and Sybil attacks, can also access this information.

This decentralized identification framework enables a secure, Sybil-resistant environment that drives participation and promotes a more transparent, sustainable ecosystem.

{% hint style="info" %}
Contracts can be found at the following repository: <https://github.com/vechain/vebetterdao-contracts>\
\
`Mainnet Address: 0x35a267671d8EDD607B2056A9a13E7ba7CF53c8b3`
{% endhint %}

## Proof of Personhood

There are several modules that VePassport uses to determine if a wallet is a bot or if it belongs to a real user:

* Proof of Participation in the VeBetter Ecosystem
* Proof of Investment
* Proof of Identity
* Whitelisting and Blacklisting
* Bot Signaling

<figure><img src="/files/icnTzVLiHH3a2FDyGf51" alt=""><figcaption><p>Long term VePassport</p></figcaption></figure>

In the current implementation to determine if a wallet is legitimate, several factors are considered: whether it is on the whitelist or blacklisted, and the number of actions performed within a specific time range, while Proof of Investment and Identity will be integrated with the next releases.

<figure><img src="/files/XrinquV3A5hmyEYSPHn0" alt=""><figcaption><p>Initial implementation</p></figcaption></figure>

Apps can interact with VePassport to check if a user is a person (now or in a specific block number) or can call each module separately to only get the participation score, or if the user is KYCed, or if it's whitelisted, blackilsted or signaled as a bot by other apps.

VePassport is designed to be expanded in the future with new modules.

## Proof of Participation

Users need to complete 3 Better actions within a 12-week period to be considered a person. This requirement encourages greater participation in the ecosystem and ensures users are active contributors to the DAO.

An action is defined as a reward that you receive from an app (e.g., receiving a reward for drinking coffee in a sustainable cup with Mugshot).

Every time a user engages with an app and receives a reward their passport accumulates points. The amount of points is determined by the security level of the app he interacted with. An app with a **low security** score is worth 100 points, **medium** is 200, **high** is 400, and **none** is 0.

## Proof of Investment

Another way to verify a wallet’s legitimacy is through the **GM NFT level** that the wallet holds.\
If the address holds a GM NFT with a level higher than 1 then it indicates that the owner has made a significant investment, since upgrading levels on that NFT is not free, suggesting that the wallet is more likely to be genuine.

<figure><img src="/files/3s3E3qfCg4iQgJkwBGQi" alt=""><figcaption><p>GM level 1</p></figcaption></figure>

## Whitelisting, Blacklisting, and Bot Signalling

X2earn apps can also flag a wallet as a bot or suspicious user. If a wallet receives enough signals to exceed a certain threshold, it will not be considered a real person.

Additionally, some authorized entities can **blacklist** or **whitelist** a wallet. Blacklisting might occur if a wallet is found to be part of a network of fake accounts. If a wallet is mistakenly blacklisted, it can request to be reinstated.

Similarly, a wallet can be added to the whitelist, especially if the user has completed a **KYC** (Know Your Customer) process, thereby ensuring that the account is legitimate.

## Proof of Identity

Various levels of KYC (Know Your Customer) can be applied in the future, ranging from linking social profiles to full identity verification. This feature will remain optional, and will instantly provide layers of security and trust for user identities.

{% hint style="danger" %}
This proof is not implemented yet.
{% endhint %}

## Delegation

To better increase the interoperability across the VeBetter and VeChain ecosystem, VePassport offers the possibility to delegate your passport to other addresses.

You can even customize your passport by attaching to it other accounts you own.


# Checks

Every person and contract can interact with VePassport to check if an address can be considered a person. Additionally, modules can be called separately, allowing a certain amount of flexibility to implement custom personhood checks.

In the following pages, you can browse each module's endpoints and learn how the VePassport personhood check is performed.

The up-to-date interface of the VePassport contract can be found [here](/).

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td>Personhood Check</td><td></td><td></td><td><a href="/pages/SFZjpTCRA5kSXCy8APQ5">/pages/SFZjpTCRA5kSXCy8APQ5</a></td></tr><tr><td>Proof of Participation</td><td></td><td></td><td><a href="/pages/1WHyxCOOkQ9jCSI3hNgG">/pages/1WHyxCOOkQ9jCSI3hNgG</a></td></tr><tr><td>Proof of Investment</td><td></td><td></td><td><a href="/pages/ndmujQX5RKs4D65uTIwT">/pages/ndmujQX5RKs4D65uTIwT</a></td></tr><tr><td>Bot Signaling</td><td></td><td></td><td><a href="/pages/9DhuOaFTBEahPrjkGyb6">/pages/9DhuOaFTBEahPrjkGyb6</a></td></tr><tr><td>Blacklisting and Whitelisting</td><td></td><td></td><td><a href="/pages/zB71e1ZUl5QQVJraINJS">/pages/zB71e1ZUl5QQVJraINJS</a></td></tr></tbody></table>


# Personhood Check

The **Personhood Check** refers to a function provided by the contract to determine whether a particular wallet belongs to a real person or not.

```solidity
interface IVeBetterPassport {
  ...
  function isPerson(address user) external view returns (bool person, string memory reason);
  function isPersonAtTimepoint(
    address user,
    uint48 timepoint
  ) external view returns (bool person, string memory reason)
  ...
}
```

The contracts currently calling this function are those related to governance voting in **VeBetter**, such as `XallocationVoting` and `B3TRGovernor`. When this function is called, the VePassport contract checks the following criteria:

* If the address (representing the user) has delegated their passport, their personhood is not considered, meaning they will not be regarded as a person;
* If the address is whitelisted, it will be considered a person;
* If the address is blacklisted, they will not be considered a person;
* If an address has been flagged multiple times by one or more apps as a bot or as an account involved in a Sybil attack, it will not be considered a person;
* If the address has used apps enough in previous rounds, or in the current one, to exceed the participation threshold, they will be considered a person;
* If the user holds a **GM NFT** with a level of 2 or higher, they will be considered a person;
* If none of the above happens, the user will not be considered a person.

## Enabled checks

Not all of the previously listed checks are enabled. Those checks can be enabled or disabled as desired, and currently, only the **delegation** and **Proof of Participation** checks are enabled.

At the moment the checks can be enabled by the VeBetter team, but in the future, this option will also be open to the DAO itself.

The rules governing how this method works can be adjusted over time.

## Check personhood in a specific block

In addition to determining whether a wallet is considered a person at the current moment, it is also possible to verify if a wallet is considered a person at a specific block in the past. This function is particularly used by the governance contracts of **VeBetter** during voting, where it checks if a user was considered a person at the start of the round.

Not all checks support this functionality though. Currently only the Delegation and Proof of Investment support this. All other checks, such as whitelisting, blacklisting, bot signaling, and participation, are analyzed based on the current block.


# Proof of Participation

**Proof of Participation** is a module of VePassport that allows tracking the amount of times an address has used the apps of VeBetter. For every action, a score (from 0 to 400 based on the app security level) is attributed to the user interacting with the X2Earn App.

The points are then summed, generating a cumulative score for the user and if it exceeds a certain threshold, the wallet can be considered a person.

{% hint style="danger" %}
Only the X2EarnRewardsPool contract can call the `registerAction` function, this means that if an app is not using the X2EarnRewardsPool contract to distribute their rewards then that action is never taken into account.
{% endhint %}

## Apps security levels

When an action is registered a score is being assigned to the user based on the security level of the app. The VeBetter team will be responsible for initially analyzing apps and setting the security score for each app and will open this power to the entire DAO in the future.

There are 4 security levels:

* NONE = 0 points
* LOW = 100 points
* MEDIUM = 200 points
* HIGH = 400 points

**Currently, all apps are assigned a security score of type "LOW",** therefore, for any app used, a user will receive 100 points for each action.

## Cumulative score

Per each account, a score is calculated based on the points he gathered until now.

The formula to calculate the score takes into account 2 arguments:

* **Amount of rounds to use**: currently set to 12, which means that the contract will sum all the points gathered during the last 12 weeks;
* **Decay percentage**: currently set to 0, which reduces the points of previous rounds (eg: if set to 20%, the score calculated until the previous round will be reduced by 20% in the next, in a linear fashion).

This approach ensures that a person must continue to participate in the VeBetter ecosystem and use the apps to maintain eligibility for voting.

The following is the current implemented formula to calculate the cumulative score of the user in the last `t` amount of rounds:

<figure><img src="/files/OQD6aybdgp3EfBuztuMz" alt=""><figcaption><p>(<code>a</code> is the total scores, <code>r</code> is the rate of decay, <code>t</code> is number of rounds)</p></figcaption></figure>

## Threshold

The threshold an address must meet to be considered a person is **300 points accumulated during the last 12 rounds**.

## Endpoints

Other apps or contracts can interact with the Proof of Participation module through the following functions of the VePassport contract:

```solidity
interface IVeBetterPassport {
  ...
  function getCumulativeScoreWithDecay(address user, uint256 lastRound) external view returns (uint256);
  
  function userRoundScore(address user, uint256 round) external view returns (uint256);
  function userTotalScore(address user) external view returns (uint256);
  function userAppTotalScore(address user, bytes32 appId) external view returns (uint256);
  
  function thresholdPoPScore() external view returns (uint256);
  function roundsForCumulativeScore() external view returns (uint256);
  function securityMultiplier(PassportTypes.APP_SECURITY security) external view returns (uint256);
  function appSecurity(bytes32 appId) external view returns (PassportTypes.APP_SECURITY);
  ...
}
```


# Proof of investment

Ownership of a GM NFT with a **level above Earth** should be sufficient to prove personhood. The capital outlay to achieve these NFTs should be enough to discourage their usage in Sybil attacks and prove the investment deployed for better action to VeBetter.

{% hint style="warning" %}
The GM ownership is snapshotted at the beginning of each round to prevent potential attacks.
{% endhint %}


# Bot Signaling

Authorised apps can flag suspicious addresses such as bots, and scammers to help the VeBetter and other apps identify and protect against bad actors.

If a user is flagged incorrectly, **VeBetter** or selected apps can **reset their signal count** to clear their record.

* **Community Dashboard**: [Signal Admin Dashboard](https://vechain-energy.github.io/vebetterdao-signal-admin/)

## Endpoints

* **VeBetterPassport (Mainnet Address)**: `0x35a267671d8EDD607B2056A9a13E7ba7CF53c8b3`

Other apps and smart contracts can interact with the **Bot Signaling** module through these key functions in the `VeBetterPassport` contract:

```solidity
  interface IVeBetterPassport {
    ...
    function signalingThreshold() external view returns (uint256);
    function signaledCounter(address _user) external view returns (uint256);
    function appSignalsCounter(bytes32 _app, address _user) external view returns (uint256);
    function appTotalSignalsCounter(bytes32 app) external view returns (uint256);
    function signalUserWithReason(address _user, string memory reason) external;
    function resetUserSignalsByAppWithReason(address user, string memory reason) external;
    ...
  }
```

## How Bot Signaling Works

* **Checking Signals**:
  * You can query signal counts for users through the following methods:
    * `signaledCounter`: Returns the total number of times a user has been signaled across all applications
    * `appSignalsCounter`: Returns the number of times a user has been signaled by a specific application
  * Apps are free to decide how they interpret this number.
* **Threshold for Personhood**:
  * When using the `isPerson` function, a user's flagged count is compared to a set **threshold**.
  * If an address has been flagged **more than** the threshold amount, it will **fail** the personhood check.
    * You can check the current threshold amount by calling `signalingThreshold`

## Snippet

The following is a snippet of how to signal addresses by using the VeChain SDK.

```typescript
import {
  ThorClient,
  ProviderInternalBaseWallet,
  VeChainProvider,
} from '@vechain/sdk-network';
import { ErrorDecoder } from 'ethers-decode-error';
import passportAbi from './passport.json' assert { type: 'json' };

// get passport contract with signer from a helper function
const passport = await getPassportContract();

// what to signal
const addressToSignal = '0x0000000000000000000000000000000000000000';
const reason = 'test';
console.log('Address to signal is', addressToSignal, 'for', reason);

// log current signal count
const [counter] = await passport.read.signaledCounter(addressToSignal);
console.log('Signals received for address are', counter);

// send a signal
const tx = await passport.transact.signalUserWithReason(
  addressToSignal,
  reason
);

console.log('Signal sent in tx', tx.id);

async function getPassportContract() {
  // config sender
  const privateKey =
    '0x09b76a9e3c0f154ca2c6f9b9580ad5f6771493866553df98b10c38ddce987847';
  const address = '0x00351f449190a9C2A41e6989c98fe5fC5eB50000';
  const wallet = new ProviderInternalBaseWallet([
    { privateKey: Buffer.from(privateKey.slice(2), 'hex'), address },
  ]);

  // connect to network
  const thor = ThorClient.at('https://mainnet.vechain.org');

  const provider = new VeChainProvider(
    // Thor client used by the provider
    thor,

    // Internal wallet used by the provider (needed to call the getSigner() method)
    wallet,

    // Enable fee delegation
    false
  );

  const signer = await provider.getSigner(address);

  // contract config
  const passport = thor.contracts.load(
    // VePassport address
    '0x35a267671d8EDD607B2056A9a13E7ba7CF53c8b3',

    // the interface definition
    passportAbi,

    // origin signing transactions
    signer
  );

  return passport;
}
```

## Permission Request

If you need access to bot signaling functions, please **reach out to us.**

If you are the app admin&#x73;**,** you can **self-assign the required roles** using the following functions:

* **Granting or revoking `SIGNALER_ROLE`**:

```solidity
assignSignalerToAppByAppAdmin(bytes32 app, address user)
removeSignalerFromAppByAppAdmin(bytes32 app, address user)
```

**Note:** App admins are responsible for managing their team's permissions correctly.


# Blacklisting and Whitelisting

The black-and-white list functions provide the DAO, or other trusted projects, a mechanism to blacklist or whitelist certain accounts. For example, certain accounts may not have a way to prove they are legitimate other than being whitelisted. On the flip side we can use the blacklist to block all known Sybil accounts providing a strong deterrent for this type of behavior.

## Endpoints

Other apps or contracts can interact with this module through the following functions of the VePassport contract:

```solidity
  interface IVeBetterPassport {
    ...
    function whitelist(address _user) external;
    function isWhitelisted(address _user) external view returns (bool);
    function removeFromWhitelist(address _user) external;
  
    function blacklist(address _user) external;
    function isBlacklisted(address _user) external view returns (bool);
    function removeFromBlacklist(address _user) external;
    ...
  }
```


# Passport Delegation

Delegation allows a user to **delegate their passport personhood** to another address to allow more versatility and app interoperability. A delegator can have only one delegatee, and a delegatee can have only one delegator.

When delegating your passport, the delegatee must accept the delegation first. When a delegatee accepts the delegation his passport will become unused, giving priority to the delegated passport, regardless of the personhood check outcome.

Since by delegating the passport, the personhood check will not work anymore for the original wallet, the delegator will also lose the eligibility to vote. However, he will still need to use X2Earn apps, upgrade his GM NFT, or do whatever is needed in order for his passport to be considered a person, allowing the delegatee to vote.

An example use case for using the delegation is VeDelegate: you can have your VeWorld that you use to interact with apps with a valid Passport, that you delegate to the TBA created by VeDelegate where you deposit your B3TR tokens and automatize voting.

{% hint style="info" %}
When calling the isPerson function for a given address the contract will automatically check for delegated passports.
{% endhint %}

{% hint style="danger" %}
To avoid users misusing this feature when voting in the VeBetterDAO governance contracts the delegation will be checked upon the block number when the round starts, so new delegations will be taken into account by the B3TR governance system only after the next round starts.
{% endhint %}

## Endpoints

<pre class="language-solidity"><code class="lang-solidity">interface IVeBetterPassport {
<strong>  ...
</strong><strong>  function delegateWithSignature(address delegator, uint256 deadline, bytes memory signature) external;
</strong>  
  function delegatePassport(address delegatee) external;
  function acceptDelegation(address delegator) external;
  function denyIncomingPendingDelegation(address delegator) external;
  function cancelOutgoingPendingDelegation() external;
  
  function revokeDelegation() external;
  
  function getDelegatee(address delegator) external view returns (address);
  function getDelegator(address delegatee) external view returns (address);
  
  function isDelegator(address user) external view returns (bool);  
  function isDelegatee(address user) external view returns (bool);
  function isDelegatorInTimepoint(address user, uint256 timepoint) external view returns (bool);
  function isDelegateeInTimepoint(address user, uint256 timepoint) external view returns (bool);
  ...
}
</code></pre>


# Accounts Linking

To better increase the interoperability across the VeBetter ecosystem VePassport offers the possibility to link multiple addresses under a single passport. All sustainable actions performed with the linked accounts will help increment the score of the passport and better represent your onchain identity.

A **passport** is the primary identity of the user (often a user's main VeWorld Wallet), and **entities** are additional wallet addresses that a user can attach to their passport. Users can link multiple entities (e.g., hardware wallets, account abstraction wallets, regular wallets) to a single passport. Once an entity is attached, its interactions, scores, and other attributes (e.g. whitelisted, bot signals etc.) are aggregated into the passport, reflecting the combined activity.

Currently, there is a limitation of a maximum of 5 entities per passport.

When linking a wallet, the scores are not immediately transferred. Instead, once the link is established, all of the linker’s scores, from the time of the link, are credited to the linked account. After the wallet addresses are linked, only the main account — the passport address — retains the right to vote.

## Endpoints

```solidity
  interface IVeBetterPassport {
  ...
    function linkEntityToPassportWithSignature(address entity, uint256 deadline, bytes memory signature) external;
    function linkEntityToPassport(address passport) external;
    function acceptEntityLink(address entity) external;
    function removeEntityLink(address entity) external;
    function denyIncomingPendingEntityLink(address entity) external;
    function cancelOutgoingPendingEntityLink() external;
    
    function isPassport(address user) external view returns (bool);
    function isPassportInTimepoint(address user, uint256 timepoint) external view returns (bool);
    
    function isEntity(address user) external view returns (bool);
    function isEntityInTimepoint(address user, uint256 timepoint) external view returns (bool);
  ...
  }
```


# Roles

The following are the roles available in the VePassport contract, with their functionality and current assignees.

<table data-header-hidden data-full-width="false"><thead><tr><th width="219"></th><th width="341"></th><th></th></tr></thead><tbody><tr><td>Role Name</td><td>Function Descriptions</td><td>Initial Assignees</td></tr><tr><td>DEFAULT_ADMIN_ROLE</td><td>Grants or revokes roles;<br><br>Set decay rates for proof of participation and thresholds.</td><td>Admin Wallet</td></tr><tr><td>UPGRADER_ROLE</td><td>Update the contract implementation address</td><td>Admin Wallet</td></tr><tr><td>ROLE_GRANTER</td><td>Allow an address to signal users on behalf of an app.<br><br>Grants or revokes roles;</td><td>Admin Wallet</td></tr><tr><td>SETTINGS_MANAGER_ROLE</td><td>Toggle personhood checks, update thresholds, and other personhood parameters.</td><td>Admin Wallet</td></tr><tr><td>WHITELISTER_ROLE</td><td>Whitelist or blacklist addresses</td><td>Admin Wallet</td></tr><tr><td>ACTION_REGISTRAR_ROLE</td><td>Register that a user performed an action</td><td>X2EarnRewardsPool contract</td></tr><tr><td>ACTION_SCORE_MANAGER_ROLE</td><td>Administrates the proof of participation settings</td><td>Admin Wallet</td></tr><tr><td>SIGNALER_ROLE</td><td>Signal users</td><td>Admin Wallet</td></tr></tbody></table>


# FAQs


# Legacy Nodes to StarGate

An overview of how VeChain moved from legacy nodes to StarGate including what migration means for participation and VeBetterDAO.

### Overview

VeChain previously used a node-based system to enable network participation, rewards, and governance-related functions. This system has now been replaced by **StarGate**, VeChain’s current staking and participation framework.

This page explains what changed, what legacy node holders need to do, and how this affects participation within VeBetterDAO.

### Legacy Nodes

Before StarGate, participation in the VeChain ecosystem was based on holding a legacy node.\
These nodes provided benefits such as VTHO generation, participation rights, and eligibility for certain ecosystem features.

This system is now deprecated and is no longer the active participation mechanism on VeChain.

Legacy node documentation is still available in this section for historical reference, but it does not apply to the current network.

### StarGate

StarGate is VeChain’s active staking system.

Instead of nodes, users now participate by staking VET to mint a **staking NFT**.\
This staking NFT represents the user’s participation and can be delegated within the StarGate system.

All rewards, participation rights, and future governance mechanisms are based on staking NFTs rather than legacy nodes.

{% hint style="success" %}

#### **For a full explanation of how StarGate works, refer to the official documentation:**

<https://docs.stargate.vechain.org/>
{% endhint %}

### Migration to StarGate

Legacy VeChain nodes must be migrated to StarGate to remain active. Migration converts a legacy node into a StarGate staking NFT, which is required for continued participation and rewards.

{% hint style="info" %}

#### **Learn how to migrate your legacy node:**

[https://docs.stargate.vechain.org/overview/legacy-nodes-migration](https://docs.stargate.vechain.org/overview/legacy-nodes-migration?utm_source=chatgpt.com)
{% endhint %}


# Legacy VeChain Node Guides (Pre-StarGate)

### Legacy System

This page documents the **legacy VeChain node system** which was used **before the StarGate upgrade**. Legacy nodes are no longer the active participation mechanism and have been replaced by **StarGate** staking NFTs.

**If you still hold a legacy node, you must migrate to continue earning rewards and participating:**

* **StarGate Migration Guide:** [https://docs.stargate.vechain.org/overview/legacy-nodes-migration](https://docs.stargate.vechain.org/overview/legacy-nodes-migration?utm_source=chatgpt.com)


# Endorsement Guide for VeChain Node Holders

{% hint style="danger" %}
**Legacy System (Pre-StarGate)**

This page documents the **legacy VeChain node endorsement system** which was used **before the StarGate upgrade**. Legacy node endorsements are no longer active and have been replaced by **StarGate staking NFTs**.

👉 **Learn how participation works after StarGate:**

<https://docs.stargate.vechain.org/>
{% endhint %}

As a VeChain node holder within the VeBetter ecosystem, you play a vital role in selecting and supporting new XApps. Your endorsement not only enables promising applications to join the ecosystem but also allows you to influence the distribution of B3TR tokens through weekly allocation rounds. This guide will help you understand how endorsement works, the influence of your node type, and how you can manage endorsements effectively.

## **What is an Endorsement?**

Endorsement is the process by which VeChain node holders support XApps (applications within the VeBetter ecosystem) for inclusion and funding eligibility. Each node holder can endorse one XApp at a time, and each endorsement carries a score based on the type of node held. Once an XApp accumulates enough endorsement points, it qualifies to join the VeBetter ecosystem and participate in weekly allocation rounds for B3TR tokens.

## **Endorsement Scores by Node Type**

The influence of your endorsement depends on the type of VeChain node you hold. Each node type has a unique endorsement score, which contributes to an XApp’s cumulative endorsement score. Here is a breakdown of endorsement scores by node type:

| **VeChain Node Type** | **Endorsement Score** |
| --------------------- | --------------------- |
| Strength              | 2                     |
| Thunder               | 13                    |
| Mjolnir               | 50                    |
| VeThorX               | 3                     |
| StrengthX             | 9                     |
| ThunderX              | 35                    |
| MjolnirX              | 100                   |

**Note**: These scores determine the weight of your endorsement. For example, a MjolnirX node endorsement contributes 100 points towards an XApp’s endorsement total, while a Strength node contributes 2 points.

## **How Endorsement Works**

1. **Choose an XApp**: Review the list of submitted XApps within the VeBetter platform. These XApps are seeking endorsements to qualify for entry into the ecosystem.
2. **Endorse with Your Node**: Select one XApp to endorse. Your endorsement adds the score of your node to the XApp’s cumulative endorsement score.
3. **Qualification for Allocation Rounds**: Once an XApp reaches a cumulative endorsement score of 100, it qualifies to join the VeBetter ecosystem and participate in weekly allocation rounds. This threshold ensures that only well-supported XApps gain access to ecosystem resources.
4. **Node Cooldown Period:**\
   From **Round 26,** after endorsing an XApp, your VeChain node will enter a **cooldown period** during which you cannot change or withdraw your endorsement.
   * For mainnet, the cooldown period is set to **1 round**. For example, if you endorse an XApp in **Round 23**, you will only be able to change your endorsement in **Round 24**.
5. **Weekly Allocation Rounds**: Endorsed XApps can participate in weekly allocation rounds, where they compete to receive B3TR tokens based on community voting. As an endorser, your influence supports the XApp’s eligibility for these rewards.

## **Managing Your Endorsements**

Using the VeBetter’s UI, you can easily manage your endorsements:

* **View Current Endorsements**: Check which XApp you are currently endorsing and its current endorsement score.
* **Switch Endorsements**: If you wish to change your endorsement, you can do so through the UI. Simply withdraw your current endorsement and select a new XApp to support.
* **Monitor XApp Progress**: Track the cumulative endorsement scores of different XApps to see how close they are to reaching the 100-point threshold.
* **Track Cooldown Status:**\
  Monitor the cooldown status of your node through the UI to see when you will be eligible to make a new endorsement.

## **Key Points to Remember**

* **Single Endorsement Limit**: Each node can endorse only one XApp at a time. If you wish to support another XApp, you must first remove your current endorsement.
* **Influence of Node Type**: The endorsement score of your node directly impacts the XApp’s ability to qualify for the ecosystem. Higher-level nodes like MjolnirX provide more influence.
* **Endorsement Lock**: Once an XApp reaches the 100-point threshold and joins the ecosystem, it cannot.
* **Node Cooldown Period:**\
  After endorsing an XApp, your node enters a cooldown period (1 round on mainnet). You cannot change or withdraw endorsements during this time. Within the cooldown period, app creators retain the ability to remove any node's endorsement from their XApp.

***

{% hint style="danger" %}
**Important Update:**

Legacy node mechanics have been replaced by **StarGate staking NFTs**.

Learn how staking, delegation, and participation work now:

<https://docs.stargate.vechain.org/>
{% endhint %}


# Node Management

{% hint style="danger" %}
**Legacy System (Pre-StarGate)**

This page describes **legacy VeChain node management** which applied **before the StarGate upgrade**. Legacy nodes have been deprecated and replaced by **StarGate staking NFTs**.

Node management, delegation, and rewards now occur through StarGate.

👉 **If you still hold a legacy node, you must migrate to continue participating:**

<https://docs.stargate.vechain.org/overview/legacy-nodes-migration>
{% endhint %}

The Node Management feature within VeBetter empowers VeChain node holders with greater flexibility and control over their participation in the ecosystem. As a node holder, you can manage your nodes, delegate your endorsement rights to others, and even consolidate multiple nodes within a single account—all through an intuitive UI.

## **Key Features for VeChain Node Holders**

1. **Delegation of Endorsement Rights**\
   As a VeChain node holder, you have the option to delegate your endorsement rights to another individual within VeBetter. By doing so, you allow this delegatee to manage the endorsement of XApps on your behalf.
   * **Control**: You remain in control of your node’s delegation status and can revoke or assign endorsement rights as needed.
   * **Flexibility**: Delegation allows you to have someone else manage your endorsement activities if you are unavailable or prefer a more hands-off approach.
2. **Managing Multiple Nodes**\
   If you hold more than one VeChain node, the Node Management feature allows you to manage all your nodes in one place. This simplifies the process of endorsing XApps, as you can easily allocate endorsements across multiple nodes without needing separate accounts.
   * **Streamlined Management**: Control multiple nodes through a single interface, allowing you to maximize your influence within the VeBetter ecosystem.
   * **Unified Dashboard**: View and manage all nodes and endorsements from a centralized dashboard for easy oversight.
3. **Revoking Delegation**\
   If you delegate your endorsement rights, you can revoke them at any time. This option allows you to reassert control over your node’s endorsement activities or reassign delegation to someone else as your needs change.
   * **Immediate Control**: Take back management rights instantly through the UI whenever you decide.
   * **Adaptable Partnerships**: Adjust delegation to fit your preferred level of involvement in VeBetter at any time.
4. **Transfer and Reassignment Protocol**\
   Should you decide to sell or transfer your VeChain node, the Node Management system makes the transition seamless. If your node is currently delegated, the new owner will need to revoke the existing delegation through the UI to assume full endorsement rights.
   * **Clear Reassignment**: Ensure the new owner can take full control, maintaining alignment with VeBetter’s endorsement policies.
   * **Transparent Process**: The UI provides clear instructions for both the current owner and the new owner to manage the transition smoothly.

***

{% hint style="danger" %}
**Important Update:**

Legacy node mechanics have been replaced by **StarGate staking NFTs**.

Learn how staking, delegation, and participation work now:

<https://docs.stargate.vechain.org/>
{% endhint %}


# VeChain Nodes X GM NFTs: Maximising Benefits within VeBetter

{% hint style="danger" %}
**Legacy System (Pre-StarGate)**

This page explains how **legacy VeChain nodes** previously interacted with **GM NFTs** before the StarGate upgrade. Legacy node mechanics have been replaced by **StarGate staking NFTs**.

GM NFT interactions are no longer based on legacy nodes.

👉 **Learn how staking NFTs work in StarGate:**

<https://docs.stargate.vechain.org/overview/nft-tiers>
{% endhint %}

As a VeChain Node holder, you have unique opportunities to enhance your participation in the ecosystem. By linking your VeChain Node to a Galaxy Member (GM) NFT, you can unlock additional rewards, boost your GM NFT level, and significantly increase your influence in governance.

This guide explains how VeChain Node holders can link their nodes to GM NFTs, the benefits of doing so, and the steps to get started.

Following the [April 2025 governance proposal](https://governance.vebetterdao.org/proposals/29105190577567483236613349157882547619640909716326747339146460525546041993191), major changes were made to strengthen the GM system and incentivize voter participation.

***

## Why Link Your VeChain Node to a GM NFT?

Linking your VeChain Node to a GM NFT provides multiple advantages:

1. **Unlock Free Level Upgrades**:
   * Your node's type determines the **free upgrade level** of your GM NFT.
   * Higher levels increase your voter rewards which in return increases your influence in governance.
2. **Boost Voter Rewards**:
   * Higher GM NFT levels provide **multipliers** for voter rewards.
   * Multiplier percentages increase with GM NFT levels, enhancing the value of your votes.
3. **Dynamic Benefits**:
   * If your node level is upgraded, the GM NFT's level is also upgraded dynamically.
   * Nodes can be detached and reassigned as needed.

***

## VeChain Nodes and Free Upgrade Levels

When you link a VeChain Node to a GM NFT, the NFT receives a free upgrade based on the node type:

| VeChain Node Type | Free Upgrade Level |
| ----------------- | ------------------ |
| **None**          | 1                  |
| **Strength**      | 2                  |
| **Thunder**       | 4                  |
| **Mjolnir**       | 6                  |
| **VeThorX**       | 2                  |
| **StrengthX**     | 4                  |
| **ThunderX**      | 6                  |
| **MjolnirX**      | 7                  |

> **Note**: If the free upgrade level exceeds the NFT's current maximum unlocked level, the level is capped.

***

## Step-by-Step Guide: Linking Your Node

1. **Check Node Ownership**:
   * Ensure you own the VeChain Node or it has been delegated to you.
2. **Select a GM NFT**:
   * Choose an NFT to link to your node. Use the VeBetter interface to view your GM NFTs.
3. **Link Your Node**:
   * Use the **Node Management** feature in the VeBetter platform to attach your node to the selected GM NFT.
4. **Monitor Your GM NFT Level**:
   * Check the NFT’s level after linking. Free upgrades are applied automatically.
5. **Participate in Governance**:
   * Use the linked GM NFT for voting in VeBetter proposals and XApp allocation to maximize rewards.

***

## Rules for Linking Nodes

* **Single Linkage**:
  * A node can only be linked to one GM NFT at a time.
* **Non-Transferable**:
  * GM NFTs with attached nodes cannot be transferred or sold.
* **Ownership Alignment**:
  * Free upgrades apply only if the GM NFT owner and the node owner (or delegatee) are the same.
* **Dynamic Adjustments**:
  * Upgrading or downgrading a node updates the GM NFT’s level dynamically.

***

## Reward Multipliers and Governance Influence

Higher GM NFT levels significantly increase your rewards during governance and x-allocatin voting participation. Here’s how the multiplier system works:

| Level  | Name    | Multiplier Percentage | Reward Weight |
| ------ | ------- | --------------------- | ------------- |
| **2**  | Moon    | 10%                   | 1.1           |
| **3**  | Mercury | 20%                   | 1.2           |
| **4**  | Venus   | 50%                   | 1.5           |
| **5**  | Mars    | 100%                  | 2             |
| **6**  | Jupiter | 150%                  | 2.5           |
| **7**  | Saturn  | 200%                  | 3             |
| **8**  | Uranus  | 400%                  | 5             |
| **9**  | Neptune | 900%                  | 10            |
| **10** | Galaxy  | 2400%                 | 25            |

***

## Detaching and Reassigning Nodes

* **Detachment Rules**:
  * Only the node owner, delegatee, or GM NFT owner can detach the node.
  * Detaching a node resets the GM NFT’s level unless it was paid for using B3TR.
* **Reassigning Nodes**:
  * After detaching, the node can be linked to another GM NFT for additional upgrades or governance participation.

***

## Examples

### **Example 1: Free Upgrade with a Node**

* **Node Type**: **Thunder**
* **GM NFT Initial Level**: **1**
* **Free Upgrade Level**: **4 (Venus)**

**Outcome**:\
The GM NFT is upgraded to **Level 4 (Venus)** for free.

* **GM Rewards Weight**: **1.5**
* If the total GM voter reward weight that cycle is 300, the user's share is:
  * $$\frac{1.5}{300} = 0.5%$$ of the GM Rewards Pool

### **Example 2: Combining Free and Paid Upgrades**

* **Node Type**: **MjolnirX**
* **GM NFT Initial Level**: **5 (Mars)**
* **Free Upgrade Level**: **7 (Saturn)**

**Outcome**:\
The GM NFT is upgraded to **Level 7 (Saturn)** for free. To reach **Level 8 (Uranus)**, donate **2,500,000 B3TR**.

Given total GM voter reward weight that cycle is 300

* **At Level 7**: **Wote Weight = 3**
  * $$\frac{3}{300} = 1.0%$$ of the GM Rewards Pool
* **At Level 8**: **Vote Weight = 5**
  * $$\frac{5}{300} = 1.66%$$ of the GM Rewards Pool

***

{% hint style="danger" %}
**Important Update:**

Legacy node mechanics have been replaced by **StarGate staking NFTs**.

Learn how staking, delegation, and participation work now:

<https://docs.stargate.vechain.org/>
{% endhint %}


