f648349e82
* Diatixisify! * First pass at Typedoc generation for TS SDK * Remove overview pages * Fix typos and remove codebase references from docs Fix typos across network and developer docs: Quorum, available, cryptosystem, transaction, proportional, Standalone. Remove TODO placeholder from dVPN protocol page. Strip GitHub source links from network docs to decouple documentation from repo structure. * Expand thin landing pages across network and developer docs - Add intro content to network overview, infrastructure, and reference landing pages - Expand developer index with "where to start" guide - Add usage instructions and explanations to all five TS playground pages - Expand WebSocket client page with setup and message format examples * Restructure Rust SDK developer docs - Delete redundant mixnet example, message-helpers, and message-types subpages - Delete client-pool architecture and example subpages (content folded into landing) - Delete tcpproxy troubleshooting (folded into landing page) - Add deprecation notices to TcpProxy pages, pointing to Stream module - Add stream module docs: landing page, architecture, tutorial, and 4 example pages - Add mixnet and client-pool tutorials - Add SDK tour page - Update navigation and landing pages with docs.rs links * Restructure TS SDK developer docs - Merge overview, installation, and getting started into TS SDK landing page - Fold FAQ content into bundling/troubleshooting section - Delete redundant overview, installation, start, and FAQ pages - Update internal links in browsers.mdx and native.mdx - Update navigation and example page imports * Flatten and expand APIs section - Collapse nested API subpages into single pages with inline Redoc embeds - Rewrite introduction as landing page with decision table - Add endpoint categories, quick curl examples to each API page - Mark Explorer API as deprecated - Move NS API deployment guide to operators/performance-and-testing - Fix dangling /apis/nym-api/mainnet link in network-components - Remove sandbox endpoints from all API pages * Add redirects for moved and deleted pages - Add 25 redirects covering TS SDK, Rust SDK, APIs, and network sections - Fix dangling /developers/typescript/start link in operators changelog * Replace individual example doc pages with GitHub-linked tables, expand tutorials - replace individual example doc pages with GitHub-linked tables - expand mixnet tutorial with persistent identity and split_sender sections - add tcpproxy tutorial - rename "API Reference" to "TypeDoc Reference" in TS SDK sidebar - rename "Misc" to "Extras" in developer sidebar, move VPN CLI up - remove echo server from tools - update message-queue callout to reference actual modules - fix mixnet/examples redirect collision * Add SEO frontmatter, validate encryption standards, clean up URLs - add title/description/schemaType/section/lastUpdated frontmatter to 48 pages across developers, network, and APIs sections - remove network/.archive/ directory (compare against develop instead) - update nymtech.net → nym.com for website/blog links (keep infra URLs) - add native proxy "in progress" callout for Rust/C/Go * API-scraper update (#6598) * read nodes and locations * update python-prebuild.sh * Address PR #6494 review feedback - Use "mode" consistently instead of "role" on nym-nodes page - Replace "staking" with "bonding" for NYM token collateral - Wire up auto-scraped node counts via TimeNow + nodes-count.json - Fix broken licensing images: download CC icons locally, replace inline HTML - Fix 9 stale redirects pointing through deleted /network/architecture path * Fix linkcheck errors - Fix stale cross-links: /network/concepts/ → /network/mixnet-mode/ - Replace README.md references with globals.md in TypeDoc output - Add entryFileName: globals to typedoc.json configs to prevent recurrence * Fix remaining stale /network/architecture links - zk-nym-overview: architecture/nyx#nym-api → /network/infrastructure/nyx#nym-api - setup: network/architecture → /network/overview * Remove accidentally re-included architecture.md file from rebase * Standardize tutorials, document examples, add llms.txt, apply tone fixes - Expand Rust SDK tutorials with step-by-step structure; document all SDK examples across mixnet, client-pool, and tcpproxy pages - Add llms.txt generation script, wire into build and CI workflows - Apply tone/style fixes: deduplicate callouts, vary sentence structure, standardize voice consistency across changed pages * Consolidate redundant network overview docs * Trim dev docs: git-first imports, stream notice, collapse TcpProxy * Update tutorial * Refresh auto-generated API and command outputs * Update network section docs * Update developer and API docs: reusable components, stream protocol, conventions, tutorial fixes * Fix Rust SDK tutorial bugs: setup_env, port conflicts, logging, open_stream race condition * Update stream.mdx * Remove docs.rs link from Stream overview for the moment * add llms.txt and llms-full.txt note to readme --------- Co-authored-by: import this <97586125+serinko@users.noreply.github.com>
562 lines
33 KiB
Plaintext
562 lines
33 KiB
Plaintext
import { Callout } from 'nextra/components';
|
||
import { Tabs } from 'nextra/components';
|
||
import { MyTab } from 'components/generic-tabs.tsx';
|
||
import { RunTabs } from 'components/operators/nodes/node-run-command-tabs';
|
||
import { VarInfo } from 'components/variable-info.tsx';
|
||
import { MigrateTabs } from 'components/operators/nodes/node-migrate-command-tabs';
|
||
import NyxPercentStake from 'components/outputs/nyx-outputs/nyx-percent-stake.md';
|
||
import NyxTotalStake from 'components/outputs/nyx-outputs/nyx-total-stake.md';
|
||
import EpochRewardBudget from 'components/outputs/api-scraping-outputs/nyx-outputs/epoch-reward-budget.md';
|
||
import StakeSaturation from 'components/outputs/api-scraping-outputs/nyx-outputs/stake-saturation.md';
|
||
import StakeSaturationSnippet from 'components/operators/snippets/stake-saturation.mdx';
|
||
import CirculatingSupply from 'components/outputs/api-scraping-outputs/nyx-outputs/circulating-supply.md';
|
||
import StakingTarget from 'components/outputs/api-scraping-outputs/nyx-outputs/staking-target.md';
|
||
import NodePerfMixnet from 'components/operators/snippets/node-perf-mixnet.mdx';
|
||
import { TimeNow } from 'components/time-now.tsx';
|
||
import { AccordionTemplate } from 'components/accordion-template.tsx';
|
||
import { Clt } from 'components/callout-custom/CalloutCustom.jsx';
|
||
import React, { useState, useEffect } from 'react';
|
||
import RewardsCalculator from 'components/operators/interactive/calculators/reward-calculator.jsx';
|
||
|
||
# Nym Operators Rewards
|
||
|
||
<Callout type="warning">
|
||
**Nym Network Rewarded set selection had been upgraded recently. Make sure to read the chapter *[Rewarded Set Selection](#rewarded-set-selection)* below carefully to fully understand all requirements to be rewarded!**
|
||
</Callout>
|
||
|
||
<TimeNow />
|
||
|
||
* Nym tokenomics are based on the research paper [*Reward Sharing for Mixnets*](https://nym.com/nym-cryptoecon-paper.pdf)
|
||
* For a more comprehensive overview, live data and supply graphs, visit [*explorer.nym.spectredao.net/token*](https://explorer.nym.spectredao.net/token)
|
||
|
||
We are working on the final architecture of [*Fair Mixnet*](#fair-mixnet) tokenomics implementation and its detailed documentation. **The current design is called [*Naive rewarding*](#naive-rewarding).** It is an intermediate step, allowing operators to migrate to `nym-node` in Mixnet smart contract and for the first time receive delegations and earn rewards for any `nym-node` [functionality](../nodes/nym-node/setup#functionality-mode), in opposite to the past system, where only Mixnodes were able to receive delegations and rewards.
|
||
|
||
**Please read the [roadmap section below](#roadmap) to see the planned development.**
|
||
|
||
{/*
|
||
|
||
**Formulas and Examples Annotation**
|
||
|
||
To make it easier for the reader, we use a highlighting line on the left side, with a specific color:
|
||
|
||
<Clt borderColor='#008080' backgroundColor='#20b2aa' pointPosition='right' pointOffset='3rem' pointAlignment='center'>
|
||
> **Turquoise with red pin for formulas.**
|
||
</Clt>
|
||
|
||
<Callout borderColor="#966fd6" backgroundColor="#b19cd9" emoji="">
|
||
<AccordionTemplate name="Example">
|
||
> Purple collapsible for examples.
|
||
</AccordionTemplate>
|
||
</Callout>
|
||
*/}
|
||
|
||
|
||
<Callout type="info" emoji="ℹ️">
|
||
Nodes bonded with vesting tokens are [not allowed to join rewarded set](https://github.com/nymtech/nym/pull/5129) - read more on [Nym operators forum](https://forum.nymtech.net/t/vesting-accounts-are-no-longer-supported/827).
|
||
</Callout>
|
||
|
||
|
||
## Rewards Logic & Overview
|
||
|
||
This is a quick summary, to understand the logic behind fundamentals like [rewarded set selection](#rewarded-set-selection), [node performance](#mixnet-node-performance-calculation), [stake saturation](#stake-saturation), or [rewards calculation](#rewards-calculation), please read the chapters below.
|
||
|
||
* **The current reward system is called [*Naive rewarding*](#naive-rewarding) - an intermediate step - where the operators of `nym-node` get rewarded from [Mixmining pool](https://validator.nymtech.net/api/v1/epoch/reward_params), which emits <span style={{display: 'inline-block'}}><EpochRewardBudget /></span> NYM per hour**
|
||
* **Only nodes selected to [rewarded set](../tokenomics#rewarded-set) of Mixnet receive rewards**
|
||
* The [rewarded set](../tokenomics#rewarded-set) of the Mixnet is currently **240 nodes in total and it's selected for each new epoch (60 min)**, from all the nodes registered (bonded) in the network
|
||
* Each node gets the same proportion of work factor because of the *naive* distribution of work
|
||
* In the [final model](#roadmap), nodes will get rewarded based on their layer position and the work they do (collected user tickets), where the work factor distribution per layer will be according to a [decision made by the operators](https://forum.nymtech.net/t/poll-what-should-be-the-split-of-mixmining-rewards-among-the-layers-of-the-nym-mixnet/407) as [listed below](#nym-network-rewarded-set-distribution)
|
||
* If a node is selected to the rewarded set, it will be rewarded in the end of the epoch, based on this reward calculation formula:
|
||
|
||
<Callout type="info" emoji="📌">
|
||
> **node_epoch_rewards = [total_epoch_reward_budget](https://validator.nymtech.net/api/v1/epoch/reward_params) \* <abbr title="In Naive rewarding the node work fraction is same for all nodes in the active set">node_work_fraction</abbr> \* [node_stake_saturation](#stake-saturation) \* [node_performance](#mixnet-node-performance-calculation)**
|
||
>
|
||
> We know that: <br/>
|
||
> **[total_epoch_reward_budget](https://validator.nymtech.net/api/v1/epoch/reward_params) = <span style={{display: 'inline-block'}}><EpochRewardBudget /></span>** <br/>
|
||
> **<abbr title="In Naive rewarding the node work fraction is same for all nodes in the active set">node_work_fraction</abbr> = 1 / active_set_size** <br/>
|
||
> **[active_set_size](https://validator.nymtech.net/api/v1/epoch/reward_params) = 240**
|
||
>
|
||
> Therefore: <br/>
|
||
> **node_epoch_rewards = <span style={{display: 'inline-block'}}><EpochRewardBudget /></span> \* 1 / 240 \* [node_stake_saturation](#stake-saturation) \* [node_performance](#mixnet-node-performance-calculation)**
|
||
</Callout>
|
||
|
||
In reality there is a an additional value called **α**, giving a premium to nodes with a higher self bond. And additionally an operator gets more rewards based on [*Operators cost*](#rewards-distribution) and [*Profit margin*](#rewards-distribution) size. **Read chapter [Rewards calculation](#rewards-calculation) to be able to navigate in all the details relevant for operators and delegators.**
|
||
|
||
<Callout type="info" emoji="ℹ️">
|
||
**In the current intermediate model we use one active set to reward all nodes and they are assigned same work factor of 1 / 240**, whether they work as Mixnode or Gateway of any kind, in both 2-hop and 5-hop mode (hence *naive rewarding*).
|
||
|
||
**In reality it means that all nodes are rewarded within the [Mixnet (5-hop) reward set](#rewarded-set-selection) only.**
|
||
|
||
**However NymVPN client can choose any `nym-node` with `--wireguard-enabled true` flag (which passed [wireguard probing test](https://harbourmaster.nymtech.net)) to route as dVPN Gateway, both entry and exit.**
|
||
</Callout>
|
||
|
||
{/*
|
||
|
||
### Nym Network rewarded set distribution
|
||
|
||
<div>
|
||
<Tabs items={[
|
||
<strong>Mixnet mode (5-hop)</strong>,
|
||
<strong>dVPN mode (2-hop)</strong>,
|
||
]} defaultIndex="0">
|
||
<MyTab>
|
||
|
||
```ascii
|
||
|
||
Network
|
||
layer: 1. 2. 3. 4. 5.
|
||
|
||
--------
|
||
┌► mixnode ─┐ mixnode mixnode
|
||
│ │
|
||
Node entry │ │ exit
|
||
type: gateway ──┘ mixnode │ mixnode ┌─► mixnode ───► gateway
|
||
│ │
|
||
│ │
|
||
mixnode └─► mixnode ─┘ mixnode
|
||
|
||
```
|
||
|
||
|
||
|
||
| **Network layer** | **1** | **2** | **3** | **4** | **5** |
|
||
| :-- | :---: | :---: | :---: | :---: | :---: |
|
||
| Node functionality in layer | Entry Gateway | Mixnode | Mixnode | Mixnode | Exit Gateway |
|
||
| Nodes in [active set](#rewarded-set-selection) | 50 | 40 | 40 | 40 | 70 |
|
||
| Naive rewarding \*: Maximum work fraction per node | 1 / 240 | 1 / 240 | 1 / 240 | 1 / 240 | 1 / 240 |
|
||
| Final model \*\*: Layer multiplier | 0.16 | 0.16 | 0.16 | 0.16 | 0.36 |
|
||
|
||
> \* Only nodes chosen to the [rewarded set](#rewarded-set-selection) will be rewarded in Mixnet mode (5-hop).<br/>
|
||
> \*\* In the final model the nodes routing as Exit Gateway get premium rewards due to the complexity and legal challenges coming along operating this type of node. Read [roadmap section](#roadmap) in the bottom of the page to get a detailed breakdown of the final implementation.
|
||
</MyTab>
|
||
<MyTab>
|
||
|
||
|
||
```ascii
|
||
|
||
Network
|
||
layer: 1. 2.
|
||
|
||
--------
|
||
|
||
Node entry exit
|
||
type: gateway ──────────────────────────────────────────► gateway
|
||
|
||
```
|
||
|
||
| **Network layer** | **1** | **2** |
|
||
| :-- | :---: | :---: |
|
||
| Node functionality in layer | Entry Gateway | Exit Gateway |
|
||
| Naive rewarding: Nodes in [active set](../tokenomics#rewarded-set) | only Mixnet mode | only Mixnet mode |
|
||
| Naive rewarding\*: Maximum work fraction per node | only Mixnet mode | only Mixnet mode |
|
||
| Final model\*\*: Layer multiplier | 0.33 | 0.67 |
|
||
|
||
> \* In the current state called [*Naive rewarding*](#naive-rewarding) only nodes in the Mixnet [rewarded set](#rewarded-set-selection) get rewarded.<br/>
|
||
> \*\* In the final model the nodes routing as Exit Gateway get premium rewards due to the complexity and legal challenges coming along operating this type of node. Read [roadmap section](#roadmap) in the bottom of the page to get a detailed breakdown of the final implementation.
|
||
</MyTab>
|
||
</Tabs>
|
||
</div>
|
||
|
||
*/}
|
||
|
||
## Rewarded Set Selection
|
||
|
||
For a node to be rewarded, the node must be part of a [Rewarded set](https://validator.nymtech.net/api/v1/epoch/reward_params) (which currently = active set) in the first place. The Rewarded set is freshly selected at the start of each epoch (every 60 min), and it consists of 240 Nym nodes that are probabilistically chosen from all the available nodes. These 240 nodes are composed of 120 gateways (50 entry and 70 exit) and 120 mixnodes (40 for each of 3 mixnet layers).
|
||
|
||
Nodes selected into the rewarded set are chosen probabilisticaly, and their selection chances increase the larger nodes weight is. Weight value is always between `0` and `1` and it's calculated by multiplying these parameters, each of them also having a value between `0` and `1` (some are floats, some are binary):
|
||
|
||
**1. [Performance](#mixnet-node-performance-calculation):** This value consists of:
|
||
- [Config score](#config-score-calculation): highest (`1`) when the node is running the latest version of the software, has [T&C's accepted](../nodes/nym-node/setup.mdx#terms--conditions) and self described API endpoint available
|
||
- [Routing ](#routing-score-calculation): highest (`1`) when the node is consistently online and correctly processes all the received traffic (100% of time)
|
||
|
||
**2. [Stake saturation](#stake-saturation):** combining bond and delegated stake (a float number between `0` and `1` representing percentage)
|
||
|
||
**Node weight is calculated with this formula:**
|
||
|
||
<Callout type="info" emoji="📌">
|
||
> **active_set_selection_weight = stake_saturation \* ( node_performance ^ 20 )**
|
||
</Callout>
|
||
|
||
For the rewarded set selection weight, good [performance](#mixnet-node-performance-calculation) is much more essential than [stake saturation](#stake-saturation), because it's lifted to 20th power in the selection algorhitm.
|
||
|
||
For a comparison we made an example with 5 nodes, where first number is node performance and second stake saturation (assuming all of them [`config_score`](#config-score-calculation) = `1` for simplification):
|
||
|
||
<br />
|
||
<AccordionTemplate name="✏️ Calculation examples: performance ^ 20 * node_stake_saturation">
|
||
> node_1 = 1.00 ^ 20 \* 1.0 = **1** <br />
|
||
> node_2 = 1.00 ^ 20 \* 0.5 = **0.5** <br />
|
||
> node_3 = 0.99 ^ 20 \* 1.0 = **0.818** <br />
|
||
> node_4 = 0.95 ^ 20 \* 1.0 = **0.358** <br />
|
||
> node_5 = 0.90 ^ 20 \* 1.0 = **0.122** <br />
|
||
</AccordionTemplate>
|
||
|
||
As you can see the performance is much more important during the Rewarded set selection. A node with 100% performance but only 50% stake saturation has much bigger chance to be chosen than a node with 95% performance and 100% stake saturation and incomparably bigger chance than 90% performing node with 100% stake saturation.
|
||
|
||
The nodes are chosen probababilistically in each epoch (60 min), so even nodes with lower performance will eventually be chosen, just much less often, as their chances decrease.
|
||
Note that the score helps prioritize some nodes over others. If all available nodes have the same score, then the selection is done uniformly at random. By raising the node performance to 20, values of these parameters that are below one incur a heavy penalization for the node’s selection chances.
|
||
|
||
<br />
|
||
<AccordionTemplate name="✏️ Explanation & Example: Rewarded set probabilistic selection">
|
||
**Explanation**
|
||
|
||
The nodes are selected probabilistically, that means that even nodes with lower weight have a small chace to get slected. The probabilistic alorithm follows this logic:
|
||
|
||
1. Summarize all nodes weight together
|
||
2. Make a random selection roll for the first slot in the active set
|
||
3. If a node is selected, take all its weight away from the draft queue
|
||
4. Repeat points 1. - 3. for each slot in the active set
|
||
|
||
**Example**
|
||
|
||
We know that nodes weight is a float between 0 and 1. For simplification we will use integers in this example and much smaller set.
|
||
|
||
- Total nodes: 8
|
||
- Rewarded set: 4
|
||
- Nodes weight:
|
||
- node1 = 5
|
||
- node2 = 5
|
||
- node3 = 10
|
||
- node4 = 10
|
||
- node5 = 20
|
||
- node6 = 40
|
||
- node7 = 50
|
||
- node8 = 60
|
||
|
||
1. Summarize all nodes weight together:
|
||
```
|
||
weight_total = 5 + 5 + 10 + 10 + 20 + 40 + 50 + 60
|
||
weight_total = 200
|
||
```
|
||
2. Roll a dice from 1 to 200:
|
||
- Imagine the nodes are in line each representing the weight like index:
|
||
- node1 = 1-5
|
||
- node2 = 6-10
|
||
- node3 = 11-20
|
||
- node4 = 21-30
|
||
- node5 = 31-50
|
||
- node6 = 51-90
|
||
- node7 = 91-150
|
||
- node8 = 151-200
|
||
- Say the function resulted in number 170
|
||
3. Add node8 to the rewarded set and take it out of the lottery, summarize all the weights again:
|
||
```
|
||
weight_total = 5 + 5 + 10 + 10 + 20 + 40 + 50
|
||
weight_total = 140
|
||
```
|
||
4. Roll a dice from 1 to 140:
|
||
- Say the function resulted in number 4
|
||
5. Add node1 to the rewarded set and take it out of the lottery, summarize all the weights again:
|
||
```
|
||
weight_total = 5 + 10 + 10 + 20 + 40 + 50
|
||
weight_total = 135
|
||
```
|
||
6. Roll a dice from 1 to 135:
|
||
- Say the function resulted in number 72
|
||
7. Add node6 to the rewarded set and take it out of the lottery, summarize all the weights again:
|
||
```
|
||
weight_total = 5 + 10 + 10 + 20 + 50
|
||
weight_total = 95
|
||
```
|
||
8. Roll a dice from 1 to 95:
|
||
- Say the function resulted in number 21
|
||
9. Add node4 to the rewarded set
|
||
10. Rewarded set of 4 nodes is selected with these nodes to be chosen:
|
||
1. node8
|
||
2. node1
|
||
3. node6
|
||
4. node4
|
||
11. After an epoch - 60 minutes - pull all bonded nodes and repeat the exact same process with their current weights
|
||
|
||
In reality we have mixing nodes selected into 3 layers. To increase security, there is an additional function in place where a node cannot be assigned to the same layer in two following epochs.
|
||
</AccordionTemplate>
|
||
|
||
Below we break down [performance calculation](#mixnet-node-performance-calculation) and show examples.
|
||
|
||
|
||
<NodePerfMixnet />
|
||
|
||
## Stake Saturation
|
||
|
||
> If you want to understand more about NYM supply, read [tokenomics page](../tokenomics#tokenomics) first.
|
||
|
||
<StakeSaturationSnippet />
|
||
|
||
|
||
## Rewards Calculation
|
||
|
||
Once the [rewarded set](https://validator.nymtech.net/api/v1/epoch/reward_params) (currently 120 Mixnodes and 120 Gateways) is selected, the nodes can start to route and mix packets in the Nym Network. Each hour a total of <span style={{display: 'inline-block'}}><EpochRewardBudget /></span> NYM is distributed between the layers from Mixmining pool. Currently in our *Naive rewarding* intermediate design, all layers get a same portion, therefore each node is *naively* assigned same working factor and therefore earns 1/240 of the rewards per epoch.
|
||
|
||
If a node is active in the rewarded set, it will receive rewards in the end of the epoch, the size is dependant on [stake saturation](../tokenomics.mdx#stake-saturation) and [performance](#performance-calculation). This is how rewards get distributed between nodes in the rewarded set.
|
||
|
||
**Node rewards calculation formula:**
|
||
|
||
<Callout type="info" emoji="📌">
|
||
> **node_epoch_rewards = [total_epoch_reward_budget](https://validator.nymtech.net/api/v1/epoch/reward_params) \* [node_performance](#mixnet-node-performance-calculation) \* [node_stake_saturation](#stake-saturation) \* ( <abbr title="In Naive rewarding the node work fraction is same for all nodes in the active set">node_work_fraction</abbr> + <abbr title="α is a constant (0.3) working as a premium for nodes with higher self bond">α</abbr> \* ( ( <abbr title="The actual number of tokens in the bond. Node bond size is capped at stake saturation level.">node_bond_size</abbr> / [stake_saturation_level](https://validator.nymtech.net/api/v1/epoch/reward_params) ) / rewarded_set_size ) ) \* 1 / ( 1 + <abbr title="α is a constant (0.3) working as a premium for nodes with higher self bond">α</abbr> )**
|
||
>
|
||
> Where: <br/>
|
||
> **[total_epoch_reward_budget](https://validator.nymtech.net/api/v1/epoch/reward_params) = <span style={{display: 'inline-block'}}><EpochRewardBudget /></span>** <br/>
|
||
> **<abbr title="In Naive rewarding the node work fraction is same for all nodes in the active set">node_work_fraction</abbr> = 1 / rewarded_set_size** <br/>
|
||
> **[rewarded_set_size](https://validator.nymtech.net/api/v1/epoch/reward_params) = 240** <br/>
|
||
> **[stake_saturation_level](https://validator.nymtech.net/api/v1/epoch/reward_params) = <span style={{display: 'inline-block'}}><StakeSaturation /></span>** <br/>
|
||
> **α = <abbr title="α is a constant (0.3) working as a premium for nodes with higher self bond">0.3</abbr>**
|
||
>
|
||
> Therefore: <br/>
|
||
> **node_epoch_rewards = <span style={{display: 'inline-block'}}><EpochRewardBudget /></span> \* [node_performance](#mixnet-node-performance-calculation) \* [node_stake_saturation](#stake-saturation) \* ( <abbr title="In Naive rewarding the node work fraction is same for all nodes in the active set">( 1 / 240 )</abbr> + <abbr title="α is a constant (0.3) working as a premium for nodes with higher self bond">0.3</abbr> \* ( ( <abbr title="The actual number of tokens in the bond. Node bond size is capped at stake saturation level.">node_bond_size</abbr> / <span style={{display: 'inline-block'}}><StakeSaturation /></span> ) / 240 ) ) \* 1 / ( 1 + <abbr title="α is a constant (0.3) working as a premium for nodes with higher self bond">0.3</abbr> )**
|
||
</Callout>
|
||
|
||
Performance and stake saturation (both are a float between `0` and `1` representing percentage) play an equally decisive role in the size of rewards earned after the epoch. The closer a node is to maximum value (`1`) of each of these parameters, the more rewards it will get.
|
||
|
||
<br />
|
||
<AccordionTemplate name="✏️ Explanation & Example: Functionality of α constant">
|
||
Operators aim to get [stake saturation](#stake-saturation) on their nodes as close to maximum value `1` as possible. The value of node stake is composed of **delegations** (stake from others or self) and **bond** (tokens locked by the operator on top of the node when registering it to the network).
|
||
|
||
Constant **α** is a in place to increase rewards for nodes with higher bond. Minimum value of bond is 100 NYM. The higher bond an operator locks, the more skin in the game they have and therefore they receive a small premium.
|
||
|
||
Let's compare 3 nodes to see their rewards, for simplicity all of them having maximum performance and stake saturation, being active in the same epoch with reward budget of 5_000 NYM, stake saturation level is 1_000_000_000 NYM and node work fraction 1 / 240. The only variable is then the size of their bond. The formula will look like this:
|
||
|
||
```
|
||
node_epoch_rewards = 5_000 * 1 * 1 * ( ( 1 / 240 ) + 0.3 * ( ( node_bond_size / 1_000_000 ) / 240 ) ) * 1 / ( 1 + 0.3 )
|
||
```
|
||
|
||
Bond size of our 3 example nodes:
|
||
|
||
```
|
||
node1_bond_size = 100 NYM
|
||
node2_bond_size = 250_000 NYM
|
||
node3_bond_size = 1_000_000 NYM
|
||
```
|
||
Rewards calculation:
|
||
|
||
```
|
||
node1_epoch_rewards = 5_000 * 1 * 1 * ( ( 1 / 240 ) + 0.3 * ( ( 100 / 1_000_000 ) / 240 ) ) * 1 / ( 1 + 0.3 )
|
||
node2_epoch_rewards = 5_000 * 1 * 1 * ( ( 1 / 240 ) + 0.3 * ( ( 250_000 / 1_000_000 ) / 240 ) ) * 1 / ( 1 + 0.3 )
|
||
node3_epoch_rewards = 5_000 * 1 * 1 * ( ( 1 / 240 ) + 0.3 * ( ( 1_000_000 / 1_000_000 ) / 240 ) ) * 1 / ( 1 + 0.3 )
|
||
```
|
||
|
||
The result:
|
||
```
|
||
node1_epoch_rewards = 16.0261 NYM
|
||
node2_epoch_rewards = 17.2275 NYM
|
||
node3_epoch_rewards = 20.8333 NYM
|
||
```
|
||
|
||
Difference between the smallest possible bond 100 NYM and a maximum bond 1mm NYM (equal full stake saturation point) is about 23% of increase in epoch rewards.
|
||
</ AccordionTemplate>
|
||
|
||
**Try to calculate rewards yourself**
|
||
|
||
<RewardsCalculator />
|
||
|
||
> Nym documentation pages are rendered statically (like in Nextra or Next.js static export mode), that's why we don't fetch from APIs at runtime, therefore on chain data must be filled by the user at the moment to ensure they are up to date.
|
||
|
||
**Rewards are sent to the Nyx account used for bonding the node and each delegator automatically by the end of an epoch in which the node was part of the rewarded set,** following the logic [described below](#rewards-distribution).
|
||
|
||
Given that there is a highly unlikely chance of all nodes having maximum stake saturation and performance, in majority of cases there will be some part of the reward budget left undistributed. This "change" is then kept in the [Mixmining reserve](../tokenomics#tokenomics).
|
||
|
||
<Callout>
|
||
All parameters regarding node performance score can be browsed or pull live from:
|
||
|
||
`https://validator.nymtech.net/api/v1/nym-nodes/annotation/<NODE_ID>`
|
||
|
||
In case you don't know your nodes `NODE_ID`, it's easy to find as long as your node is bonded. Visit [validator.nymtech.net/api/v1/nym-nodes/bonded](https://validator.nymtech.net/api/v1/nym-nodes/bonded) and search your node using `identity_key` or bonding Nyx account address (denoted as `owner`).
|
||
</Callout>
|
||
|
||
|
||
### Rewards Distribution
|
||
|
||
Once the [rewards are assigned per each node](#rewards-calculation) they need to be distributed between the operator of the node and delegators (people who staked their NYM on that node). The distribution is pretty straightforward and it happens in the following order:
|
||
|
||
1. **Operators Cost (O.C.)**: How many NYM the operator requests to cover their costs per month, [divided by `720`](#nyx-epoch-vs-interval) (this value is set by the operator in the bonding wallet node settings)
|
||
2. **Profit Margin (P.M.)**: The extra % cut that the operator requests (this value is set by the operator in the bonding wallet node settings, smallest value is 20% to prevent race to bottom)
|
||
3. **Bond & Stake proportionally**: The remaining rewards are distributed proportionally to the weight of every stake (including self bond, self delegation and each delegation).
|
||
|
||
#### Nyx Epoch vs Interval
|
||
|
||
<Callout type="info" emoji="📌">
|
||
> **1 epoch = 60 min** <br />
|
||
> **1 interval = 720 epochs**
|
||
>
|
||
> The logic is that interval is 30 days: <br />
|
||
> 24 epochs * 30 days = 720
|
||
</ Callout>
|
||
|
||
The Operators Cost (O.C). is a value denominated in NYM, that a node operator requires to get paid before the rewards get distributed. The cost is estimated per one month. However, it's paid only in epochs when the node is active. To calculate how O.C. works, we use a value called `interval` which represents 30 days (approximate month), or more precisely 720 epochs. To get covered a full O.C, the node would have to be active for the entire month.
|
||
|
||
**O.C. real revenue formula**
|
||
|
||
Therefore every epoch a node is active, the operator gets:
|
||
<Callout type="info" emoji="📌">
|
||
> **epoch_operator_cost_revenue = operators_cost / epochs_per_interval**
|
||
>
|
||
> that is:
|
||
>
|
||
> **epoch_operator_cost_revenue = operators_cost / 720**
|
||
</ Callout>
|
||
|
||
To calculate O.C. per month, multiply it by number of active epochs:
|
||
<Callout type="info" emoji="📌">
|
||
> **monthly_operator_cost_revenue = ( operator_cost / 720 ) * active_epochs**
|
||
</Callout>
|
||
|
||
{/*
|
||
#### Final Layer Distribution (under development)
|
||
|
||
We are working on the final design with the ratio implementing a [decision made by the operators](https://forum.nymtech.net/t/poll-what-should-be-the-split-of-mixmining-rewards-among-the-layers-of-the-nym-mixnet/407) as follows:
|
||
|
||
<Callout type="info" borderColor="#008080" backgroundColor="#20b2aa" emoji="📌">
|
||
>5-hop mixnet mode: <br />
|
||
> 16%; 16%; 16%; 16%; 36% <br/>
|
||
> <br/>
|
||
> 2-hop dVPN mode: <br />
|
||
> 33%; 67%
|
||
</Callout>
|
||
|
||
In real numbers: If hourly revenue to all 240 nodes is 6000 NYM, the layer compartmentalisation is 960 NYM for Entry Gateway layer and each Mixnode layer and 2160 NYM for Exit Gateway layer. The calculation is in the example below:
|
||
|
||
<Callout borderColor="#966fd6" backgroundColor="#b19cd9" emoji="">
|
||
<AccordionTemplate name="Example">
|
||
> Purple collapsible for examples.
|
||
5-hop mixnet mode:
|
||
$0.16 * 6000 = 960; 0.16 * 6000 = 960; 0.16 * 6000 = 960; 0.16 * 6000 = 960; 0.36 * 6000 2160$
|
||
2-hop wireguard mode:
|
||
$33\% - 67\%$
|
||
</AccordionTemplate>
|
||
</Callout>
|
||
|
||
### Node Rewards within Same Layer
|
||
|
||
|
||
### Operation Cost, Profit Margin & Delegation
|
||
|
||
### APR Calculation
|
||
*/}
|
||
|
||
## Roadmap
|
||
|
||
We are working on the final architecture of [*Fair Mixnet*](#fair-mixnet) tokenomics implementation, following the [decision made by the node operators](https://forum.nymtech.net/t/poll-what-should-be-the-split-of-mixmining-rewards-among-the-layers-of-the-nym-mixnet/407). The current design is called [*Naive rewarding*](#naive-rewarding). This is an intermediate step, expecting operators to migrate to `nym-node` in Mixnet smart contract and be able to recieve delegations and earn rewards for any `nym-node` functionality, in opposite to the past system, where only Mixnodes were able to recieve delegations and rewards.
|
||
|
||
On November 5th 2024, we presented a release roadmap in live [Operators Townhall](https://www.youtube.com/watch?v=3G1pJqvO2VM) where we explained in detail the steps of Nym node and tokenomics development and the effect it will have on node operators and put it into a rough timeline.
|
||
|
||
### Naive Rewarding
|
||
|
||
***Naive rewarding* is the current tokenomics design.** The table below lists features and logic of this design.
|
||
|
||

|
||
|
||
### Fair Mixnet
|
||
|
||
***Fair Mixnet* is the final architecture model that we work towards.** The table below lists features and logic of the design once implemented.
|
||
|
||

|
||
|
||
|
||
{/*
|
||
## Stats
|
||
|
||
NYM token is capped at 1b. Below is a table with actual\* token supply distribution.
|
||
|
||
mdrun cd ../../../scripts/cdmrun && ./api_targets.py s --api mainnet --endpoint circulating-supply --format
|
||
|
||
|
||
ADD MIXNET STATS GRAPHS
|
||
|
||
|
||
DROPPING THIS FROM THE MAINTENANCE PAGE - NEEDS REWORK
|
||
|
||
## Mix Node Reward Estimation API endpoint
|
||
|
||
THIS NEEDS REDO
|
||
|
||
The Reward Estimation API endpoint allows Mix Node operators to estimate the rewards they could earn for running a Nym Mix Node with a specific `MIX_ID`.
|
||
|
||
> The `<MIX_ID>` can be found in the "Mix ID" column of the [Harbourmaster](https://harbourmaster/nymtech.net).
|
||
|
||
The endpoint is a particularly common for Mix Node operators as it can provide an estimate of potential earnings based on factors such as the amount of traffic routed through the Mix Node, the quality of the Mix Node's performance, and the overall demand for Mix Nodes in the network. This information can be useful for Mix Node operators in deciding whether or not to run a Mix Node and in optimizing its operations for maximum profitability.
|
||
|
||
|
||
|
||
We have available API endpoints which can be accessed via [Swagger UI page](https://validator.nymtech.net/api/swagger/index.html). Or by querying the endpoints directly:
|
||
|
||
```sh
|
||
curl -X 'GET' \
|
||
'https://validator.nymtech.net/api/v1/status/mixnode/<MIX_ID>/reward-estimation' \
|
||
-H 'accept: application/json'sh
|
||
```
|
||
|
||
Query response will look like this:
|
||
|
||
```sh
|
||
"estimation": {
|
||
"total_node_reward": "942035.916721770541325331",
|
||
"operator": "161666.263307386408152071",
|
||
"delegates": "780369.65341438413317326",
|
||
"operating_cost": "54444.444444444444444443"
|
||
},
|
||
```
|
||
|
||
> The unit of value is measured in `uNYM`.
|
||
|
||
<Callout borderColor="#008080" backgroundColor="#20b2aa" emoji="📌">
|
||
$1 \ NYM = 1 \_ 000 \_ 000 \ uNYM$
|
||
</Callout>
|
||
|
||
- `estimated_total_node_reward` - An estimate of the total amount of rewards that a particular Mix Node can expect to receive during the current epoch. This value is calculated by the Nym Validator based on a number of factors, including the current state of the network, the number of Mix Nodes currently active in the network, and the amount of network traffic being processed by the Mix Node.
|
||
|
||
- `estimated_operator_reward` - An estimate of the amount of rewards that a particular Mix Node operator can expect to receive. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the Mix Node, the quality of service provided by the Mix Node, and the operator's stake in the network.
|
||
|
||
- `estimated_delegators_reward` - An estimate of the amount of rewards that Mix Node delegators can expect to receive individually. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the Mix Node, the quality of service provided by the Mix Node, and the delegator's stake in the network.
|
||
|
||
- `estimated_node_profit` - An estimate of the profit that a particular Mix node operator can expect to earn. This value is calculated by subtracting the Mix Node operator's `operating_costs` from their `estimated_operator_reward` for the current epoch.
|
||
|
||
- `estimated_operator_cost` - An estimate of the total cost that a particular Mix Node operator can expect to incur for their participation. This value is calculated by the Nym Validator based on a number of factors, including the cost of running a Mix Node, such as server hosting fees, and other expenses associated with operating the Mix Node.
|
||
*/}
|
||
|
||
|
||
|
||
{/*
|
||
?DROPPING THIS FROM THE OLD MAINTENANCE PAGE
|
||
|
||
### Mix Node Reward Estimation API endpoint
|
||
|
||
The Reward Estimation API endpoint allows Mix Node operators to estimate the rewards they could earn for running a Nym Mix Node with a specific `MIX_ID`.
|
||
|
||
> The `<MIX_ID>` can be found in the "Mix ID" column of the [Network Explorer](https://nym.com/explorer).
|
||
|
||
The endpoint is a particularly common for Mix Node operators as it can provide an estimate of potential earnings based on factors such as the amount of traffic routed through the Mix Node, the quality of the Mix Node's performance, and the overall demand for Mix Nodes in the network. This information can be useful for Mix Node operators in deciding whether or not to run a Mix Node and in optimizing its operations for maximum profitability.
|
||
|
||
Using this API endpoint returns information about the Reward Estimation:
|
||
|
||
```sh
|
||
/status/mixnode/<MIX_ID>/reward-estimation
|
||
```
|
||
|
||
Query Response:
|
||
|
||
```sh
|
||
"estimation": {
|
||
"total_node_reward": "942035.916721770541325331",
|
||
"operator": "161666.263307386408152071",
|
||
"delegates": "780369.65341438413317326",
|
||
"operating_cost": "54444.444444444444444443"
|
||
},
|
||
```
|
||
|
||
> The unit of value is measured in `uNYM`.
|
||
|
||
- `estimated_total_node_reward` - An estimate of the total amount of rewards that a particular Mix Node can expect to receive during the current epoch. This value is calculated by the Nym Validator based on a number of factors, including the current state of the network, the number of Mix Nodes currently active in the network, and the amount of network traffic being processed by the Mix Node.
|
||
|
||
- `estimated_operator_reward` - An estimate of the amount of rewards that a particular Mix Node operator can expect to receive. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the Mix Node, the quality of service provided by the Mix Node, and the operator's stake in the network.
|
||
|
||
- `estimated_delegators_reward` - An estimate of the amount of rewards that Mix Node delegators can expect to receive individually. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the Mix Node, the quality of service provided by the Mix Node, and the delegator's stake in the network.
|
||
|
||
- `estimated_node_profit` - An estimate of the profit that a particular Mix node operator can expect to earn. This value is calculated by subtracting the Mix Node operator's `operating_costs` from their `estimated_operator_reward` for the current epoch.
|
||
|
||
- `estimated_operator_cost` - An estimate of the total cost that a particular Mix Node operator can expect to incur for their participation. This value is calculated by the Nym Validator based on a number of factors, including the cost of running a Mix Node, such as server hosting fees, and other expenses associated with operating the Mix Node.
|
||
|
||
### Validator: Installing and configuring nginx for HTTPS
|
||
#### Setup
|
||
[Nginx](https://www.nginx.com/resources/glossary/nginx) is an open source software used for operating high-performance web servers. It allows us to set up reverse proxying on our validator server to improve performance and security.
|
||
|
||
Install `nginx` and allow the 'Nginx Full' rule in your firewall:
|
||
|
||
*/}
|