Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 36 additions & 11 deletions docs/learn/emissions.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ title: "Emission"
import ThemedImage from '@theme/ThemedImage';
import useBaseUrl from '@docusaurus/useBaseUrl';


Emission is the economic heartbeat of Bittensor—the process that continuously distributes newly created [TAO](../resources/glossary.md#tao-tau) and subnet-specific alpha tokens to network participants who contribute value through [mining](../resources/glossary.md#subnet-miner), [validation](../resources/glossary.md#subnet-validator), [staking](../resources/glossary.md#staking), and [subnet creation](../resources/glossary.md#subnet-creator).

:::tip Price-Based Emissions Now Active
**As of June 2026**: Bittensor has reverted to a **price-based model** for determining how TAO emissions are distributed across subnets. Each subnet's share of block emissions is proportional to its EMA (Exponential Moving Average) token price, normalized over all subnets with emissions enabled.
:::tip Price-Based Emissions with Emission Gate
**As of June 2026**: Bittensor uses a **price-based model** for determining how TAO emissions are distributed across subnets. Subnet price shares now pass through a **Hill gate function** before normalization, concentrating emission toward subnets with above-average demand, while reducing emission allocation to idle or low-demand subnets.

See:

- [How price-based injection works](#tao-reserve-injection)
- [How the emission gate works](#tao-reserve-injection)
:::

## Injection and Distribution: Two-Stages of the Emissions Process
Expand Down Expand Up @@ -46,7 +45,7 @@ Each block:

#### Distribution across Subnets

TAO emissions across subnets are determined by a price-based model. Each subnet's emission share is proportional to its EMA price (`SubnetMovingPrice`), normalized over all emission-enabled subnets — so subnets with higher EMA prices attract a greater share of block emissions. Emission-disabled subnets receive zero and their share is redistributed proportionally to enabled subnets.
TAO emissions across subnets are determined by a price-based model with an emission gate. Each subnet's raw share is proportional to its EMA price (`SubnetMovingPrice`) weighted by its miner-burn penalty. The raw share is then passed through a Hill gate function centered on the demand distribution. Subnets above the threshold retain nearly their full share, while those below it receive progressively smaller allocations, with the lowest-demand subnets receiving only 1–5%. Emission-disabled subnets receive zero regardless of gate position, and their share is redistributed to enabled subnets.

:::info Deprecated: Flow-Based Emissions

Expand All @@ -61,26 +60,52 @@ A subnet's TAO reserve injection is determined by its **emission share**, calcul
<details>
<summary><strong>How it's calculated</strong></summary>

Each subnet's share of the fixed block emission is weighted by three factors, then normalized over all emission-enabled subnets:
Emission shares are computed in four steps:

**Step 1 — Raw share** (price × miner-burn penalty):

$$
s_i = p_i \cdot (1 - b_i)
$$

**Step 2 — Demand bar** (recomputed each tempo from the same EMA prices):

$$
\theta = \text{quantile}_q\bigl(\{s_i\}_{i \in \mathbb{S}}\bigr)
$$

where $q$ = `EmissionBarQuantile` (default 0.61, landing around rank 32 on current mainnet).

**Step 3 — Hill gate**:

$$
\text{gate}(s_i) = \frac{s_i^h}{s_i^h + \theta^h}
$$

where $h$ = `EmissionGateExponent` (default 3). At $s_i = \theta$ the gate passes exactly $\frac{1}{2}$; well above the bar it approaches 1; deep below it approaches 0.

**Step 4 — Normalized emission share**:

$$
\text{share}_i = \frac{p_i \cdot (1 - b_i)}{\sum_{j \in \mathbb{S}} p_j \cdot (1 - b_j)}
\text{share}_i = \frac{s_i \cdot \text{gate}(s_i)}{\sum_{j \in \mathbb{S}} s_j \cdot \text{gate}(s_j)}
$$

where:

- $p_i$ = `SubnetMovingPrice` — the subnet's EMA price (not the live spot price)
- $b_i$ = `MinerBurned` — the proportion (0–1) of the most recent tempo's miner incentive that was withheld because the recipient hotkey is owned by the subnet owner. Penalizes subnets that withhold miner emission, regardless of whether that emission is recycled or burned
- $b_i$ = `MinerBurned` — the proportion (0–1) of the most recent tempo's miner incentive withheld because the recipient hotkey is owned by the subnet owner, regardless of whether that emission is recycled or burned
- $\theta$ = demand bar; recomputed once per tempo
- $h$ = gate sharpness; at $h = 3$ a subnet near the bar gains ~26% more emission for a 10% demand increase

TAO injected into subnet $i$ per block is then:
TAO injected into subnet $i$ per block:

$$
\Delta\tau_i = \Delta\bar{\tau} \times \text{share}_i
$$

**Fallback**: if the combined weight is zero across all subnets (e.g. all subnets are withholding all miner emission), `get_shares` falls back to unweighted price shares — $p_i / \sum p_j$ — so block emission is never stranded.
**Fallback**: if the combined gate-weighted sum is zero (e.g. all subnets withholding all miner emission), `get_shares` falls back to unweighted price shares — $p_i / \sum p_j$ — so block emission is never stranded.

**Implementation**: Share calculation: [`get_shares()`](<https://github.com/RaoFoundation/subtensor/blob/main/pallets/subtensor/src/coinbase/subnet_emissions.rs#:~:text=pub(crate)%20fn%20get_shares>) → `get_shares_price_ema()` in `subnet_emission.rs`
**Implementation**: [`get_shares()`](https://github.com/opentensor/subtensor/blob/main/pallets/subtensor/src/coinbase/subnet_emissions.rs) → `get_shares_price_ema()` in `subnet_emissions.rs`

</details>

Expand Down
33 changes: 28 additions & 5 deletions docs/navigating-subtensor/emissions-coinbase.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,22 +66,44 @@ The moving price for each subnet is calculated using a custom [EMA](../learn/ema
**Price-Based Distribution:**
The system uses an EMA of each subnet's token price (`SubnetMovingPrice`) to determine emission shares, rather than the live spot price. Each subnet's share of the fixed block emission is weighted by EMA price, and a miner-burn penalty, then normalized over all emission-enabled subnets:

**Step 1** — Raw share:

$$
s_i = p_i \cdot (1 - b_i)
$$

**Step 2** — Demand bar (per-tempo):

$$
\theta = \text{quantile}_q\bigl(\{s_i\}\bigr), \quad q = \texttt{EmissionBarQuantile}\ (\text{default } 0.61)
$$

**Step 3** — Hill gate:

$$
\text{gate}(s_i) = \frac{s_i^h}{s_i^h + \theta^h}, \quad h = \texttt{EmissionGateExponent}\ (\text{default } 3)
$$

**Step 4** — Final share:

$$
\text{share}_i = \frac{p_i \cdot (1 - b_i)}{\sum_{j \in \mathbb{S}} p_j \cdot (1 - b_j)}
\text{share}_i = \frac{s_i \cdot \text{gate}(s_i)}{\sum_{j \in \mathbb{S}} s_j \cdot \text{gate}(s_j)}
$$

where:

- $p_i$ = `SubnetMovingPrice`
- $b_i$ = `MinerBurned` — proportion of miner (incentive) emission withheld this tempo due to an owner/immune hotkey (0 = none withheld, 1 = all withheld)
- $p_i$ = `SubnetMovingPrice` (EMA price, dynamic smoothing factor, ~30-day half-life)
- $b_i$ = `MinerBurned` — proportion of miner emission withheld this tempo (0 = none withheld, 1 = all withheld)
- $\theta$ = demand bar; at $s_i = \theta$ the gate passes exactly ½; recomputed once per tempo
- $h$ = gate sharpness; higher h = sharper cliff at the bar

TAO allocated to subnet $i$ per block:

$$
\text{tao\_allocation}_i = \text{block\_emission} \times \text{share}_i
$$

**Fallback**: if every subnet's combined weight is zero, `get_shares` falls back to unweighted price shares ($p_i / \sum p_j$) so block emission is never stranded.
**Fallback**: if every subnet's combined gate-weighted sum is zero, `get_shares` falls back to unweighted price shares ($p_i / \sum p_j$) so block emission is never stranded.

**Implementation:**

Expand All @@ -91,7 +113,8 @@ $$
**Key Characteristics:**

- Emission shares are slow to respond to price changes due to the ~92.6 day effective EMA window
- Emission-enabled subnets receive a non-zero share determined by their EMA price and miner-burn penalty; emission-disabled subnets receive zero emissions
- The Hill gate concentrates emission toward above-bar subnets; at defaults (q = 0.61, h = 3), the 94 below-bar subnets on current mainnet collectively receive ~12.5% of emission
- Emission-enabled subnets receive a non-zero share determined by their gated emission weight; emission-disabled subnets receive zero
- De-registration remains price-based and is intentionally decoupled from emission share
- `MinerBurned` is cleared on subnet removal — no stale values after deregistration

Expand Down
79 changes: 79 additions & 0 deletions docs/subnets/subnet-hyperparameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -1080,3 +1080,82 @@ The ratio of all subnet alpha emissions that is given to subnet owner as stake.
**Description**:

The minimum stake required for validating. Currently 1000

### EmissionBarQuantile

**Type**: U64F64

**Default**: 0.61

**`btcli` setter**: none

**Setter extrinsic**: `sudo_set_emission_bar_quantile`

**Permissions required to set**: Root

**Bounds**: strictly `(0, 1)` exclusive — values of 0 or 1 are rejected

**Description**:

The quantile $q$ of the demand-share distribution used to compute the emission bar $\theta$ each tempo. With the default of 0.61, the bar is set at the level where 61% of total demand is carried by subnets above it — landing around rank 32 on the current mainnet distribution.

:::info Interaction with EmissionBarRank
When `EmissionBarRank` is set to a non-zero value, it overrides `EmissionBarQuantile` entirely. The quantile is only active when `EmissionBarRank = 0` (the default).
:::

See [Emission: TAO reserve injection](../learn/emissions.md#tao-reserve-injection) for the full gate formula.

### EmissionBarRank

**Type**: u16

**Default**: 0 (quantile mode active)

**`btcli` setter**: none

**Setter extrinsic**: `sudo_set_emission_bar_rank`

**Permissions required to set**: Root

**Description**:

An alternative bar-positioning mode for the emission gate. When set to a non-zero value `N`, the demand bar $\theta$ is **pinned to the Nth-largest demand share** across all emission-enabled subnets, rather than being computed from `EmissionBarQuantile`. This makes the eligible set track a fixed rank position as the demand distribution shifts over time.

Setting `EmissionBarRank = 0` restores the default **quantile mode**, where $\theta$ is computed from `EmissionBarQuantile`. A bar recompute is forced on the next block whenever this value changes.

`EmissionBarRank` takes precedence over `EmissionBarQuantile` when non-zero — the two parameters are mutually exclusive.

See [Emission: TAO reserve injection](../learn/emissions.md#tao-reserve-injection) for the full gate formula.

### EmissionGateExponent

**Type**: U64F64

**Default**: 3

**`btcli` setter**: none

**Setter extrinsic**: `sudo_set_emission_gate_exponent`

**Permissions required to set**: Root

**Bounds**: `[1, 8]` — values outside this range are rejected

**Description**:

The Hill exponent $h$ controlling the sharpness of the emission gate at the demand bar $\theta$:

$$
\text{gate}(s) = \frac{s^h}{s^h + \theta^h}
$$

At $h = 1$ the gate is a gentle sigmoid. At $h = 3$ (the default) the cliff is decisive:

- A subnet well above the bar retains close to 100% of its linear emission share
- A subnet exactly at the bar retains 50%
- A subnet at half the bar's demand retains ~11%
- Deep-tail subnets retain 1–5%

Higher $h$ (up to the maximum of 8) sharpens the boundary further and strengthens leverage near it. Values are bounded to `[1, 8]`; values outside this range are rejected with `InvalidValue`.

See [Emission: TAO reserve injection](../learn/emissions.md#tao-reserve-injection) for the full gate formula.