This chapter builds on: Ch 7 Tokenomics, Ch 9 Yuma Consensus

Emission Mechanics

This deep-dive follows the complete journey of TAO from block creation to participant wallets. We trace the exact flow that happens every ~12 seconds in Subtensor.

Follows Block Execution

This page traces the emission flow that happens during Phase 1: on_initialize. For epoch-specific consensus calculations, see Yuma Consensus.

Step 1: Calculate Block Emission

Every block (~12 seconds), new TAO is created. The amount follows a logarithmic decay based on total issuance:

rust
// From run_coinbase.rs
fn get_block_emission() -> u64 {
    let issuance = TotalIssuance::get();
    let max_supply = 21_000_000 * 10^9;  // 21M TAO in RAO

    // Logarithmic decay: emission decreases as issuance approaches max
    let remaining = max_supply - issuance;
    let emission = remaining / DECAY_CONSTANT;

    emission
}
Total IssuanceApprox. Emission/BlockDaily Emission
~7.5M TAO (current)~0.5 TAO~3,600 TAO
~10.5M TAO~0.25 TAO~1,800 TAO
~15M TAO~0.125 TAO~900 TAO
First Halving Complete

The first halving has already occurred. Current emission is approximately half of the initial rate.

Storage: BlockEmission stores the calculated value for the current block.

Step 2: Determine Subnet Shares (TAO Flow)

The total block emission is divided among subnets. With dTAO, shares are calculated using TAO Flow, a measure of actual TAO movement through each subnet's liquidity pool.

TAO Flow Algorithm

For each subnet, the system tracks net TAO inflows (staking) and outflows (unstaking):

rust
// From subnet_emissions.rs

// Track when users stake/unstake
record_tao_inflow(netuid, tao_amount);   // Staking adds TAO
record_tao_outflow(netuid, tao_amount);  // Unstaking removes TAO

// Calculate EMA of flow for smoothing
net_flow = SubnetTaoFlow::get(netuid);           // Running total
ema_flow = FlowEmaSmoothingFactor * net_flow
         + (1 - FlowEmaSmoothingFactor) * previous_ema;

// Power-law normalization across subnets
share[netuid] = max(ema_flow - cutoff, 0) ^ exponent
shares = normalize(shares)  // Sum to 1

Why TAO Flow?

TAO Flow measures actual demand for a subnet. A subnet with heavy staking activity indicates user interest and receives more emission – far more dynamic than using static weights from the root network.

Storage:

Step 3: Convert to Alpha Tokens

With dTAO, each subnet has its own token called Alpha. Emission doesn't go directly to participants as TAO – it first passes through the subnet's liquidity pool.

The Liquidity Pool

Each subnet has a constant-product liquidity pool that enables swapping between TAO and Alpha:

Pool ComponentStoragePurpose
TAO ReservesSubnetTAOTAO locked in the pool
Alpha PriceSubnetMovingPriceEMA-smoothed exchange rate
Alpha OutSubnetAlphaOutAlpha available for distribution
Alpha InSubnetAlphaInAlpha returned from operations

How Alpha Gets Its Value

Alpha price is determined by the ratio of TAO to Alpha in the liquidity pool:

Alpha Price (in TAO) = TAO in Pool / Alpha in Pool

The result is a market dynamic:

  • Staking TAO into a subnet adds TAO to the pool, increasing Alpha price
  • Unstaking from a subnet removes TAO from the pool, decreasing Alpha price
  • High demand subnets accumulate more TAO, making their Alpha more valuable

Example: Alpha Appreciation

Subnet 1 pool: 10,000 TAO ↔ 10,000 Alpha → Price = 1 TAO/α
After heavy staking: 20,000 TAO ↔ 15,000 Alpha → Price = 1.33 TAO/α
Early stakers' Alpha is now worth 33% more in TAO terms.

Dual Injection

Every block, the system injects both TAO and Alpha into the pool:

rust
// From coinbase/run_coinbase.rs
fn get_dynamic_tao_emission(netuid, tao_emission, alpha_block_emission) {
    let alpha_price = current_alpha_price(netuid);

    // Alpha to inject = fixed per block
    let alpha_in_emission = alpha_block_emission;

    // TAO to inject = alpha_in × current_price
    let tao_in_emission = alpha_in_emission * alpha_price;

    // Alpha available for distribution
    let alpha_out_emission = alpha_block_emission;

    (tao_in_emission, alpha_in_emission, alpha_out_emission)
}

The swap maintains pool liquidity while generating Alpha tokens for distribution.

Step 4: Split: Owner / Miners / Validators / Root

The Alpha tokens (alpha_out) are split in order:

Sequential Split Order

  1. Owner Cut (first): The subnet owner takes their configured percentage off the top. Storage: PendingOwnerCut
  2. From the remainder:
    • Miners: 50% of what's left, distributed by incentive scores
    • Validators: 50% of what's left, distributed by dividends scores
  3. Root Dividends: If the total of all subnet Alpha EMA prices exceeds 1 TAO, root validators also receive dividends.

Example: 10% Owner Cut

If a block produces 1000 Alpha for a subnet with 10% owner cut:
Owner: 100αMiners: 450αValidators: 450α
The 50/50 split applies to the 900α remainder, not the full 1000α.

RecipientSharePending Storage
OwnerConfigured % (first)PendingOwnerCut
Miners50% of remainderPendingServerEmission
Validators50% of remainderPendingValidatorEmission
Root ValidatorsIf total α EMA price > 1τPendingRootAlphaDivs

Root Sell Flag

The root_sell_flag determines whether root validators receive Alpha dividends or if the Alpha is recycled back to the subnet:

rust
// If total of all subnet EMA alpha prices > 1 TAO
if total_ema_alpha_price > 1.0 {
    // Root validators get alpha dividends
    PendingRootAlphaDivs += root_share;
} else {
    // Alpha is recycled back to subnet pool
    recycle_alpha(netuid, root_share);
}

Step 5: Epoch Distribution

Pending emission accumulates every block, but actual distribution to participant wallets happens at epoch boundaries. When a subnet's tempo triggers, the accumulated alpha passes through a three-stage distribution cascade before reaching wallets.

The Distribution Cascade

Each hotkey's dividend goes through two "take" deductions before reaching nominators:

  1. Stage 1 — Raw dividends: The epoch runs Yuma Consensus, producing a raw dividend amount per hotkey on the subnet.
  2. Stage 2 — Childkey take: If the hotkey has parent-child relationships, the child's configured take rate is applied to each parent's share. The child keeps their cut, a small portion is burned (recycled to the subnet), and the parent receives the remainder. If parent and child share the same coldkey owner, no take is deducted.
  3. Stage 3 — Validator take: The hotkey's own take rate (set by the validator) is deducted from the post-childkey dividends. The validator receives their take directly. The remainder is distributed proportionally to all nominators based on their stake share.

Worked Example

Suppose a hotkey earns 1000α in raw dividends. A parent hotkey (different coldkey owner) contributed 40% of the stake, so 400α of the dividend is attributable to the parent. The childkey take rate is 10%, and the validator take rate is 18%.

StageDetailAmount
Raw dividendHotkey's own portion600α
Parent's portion (40% of stake)400α
Childkey takeBurn (~1% of parent share, recycled to subnet)-4α
Child keeps (10% of parent share)-40α
Post-childkey total (600 + 356)956α
Validator takeValidator keeps (18% of 956α)-172α
Nominator pool (distributed by stake share)784α

Pseudocode

rust
// From distribute_emission() → epoch flow
fn distribute_emission(netuid) {
    let server_alpha = PendingServerEmission::take(netuid);
    let validator_alpha = PendingValidatorEmission::take(netuid);

    // Run Yuma Consensus to get per-hotkey scores
    let (incentive, dividends) = run_epoch(netuid);

    // Miners: distributed by incentive score
    for (uid, hotkey) in neurons(netuid) {
        let miner_share = incentive[uid] * server_alpha;
        increase_stake(hotkey, miner_share);
    }

    // Validators: three-stage cascade
    for (uid, hotkey) in neurons(netuid) {
        let raw_dividend = dividends[uid] * validator_alpha;

        // Stage 2: Childkey take split
        // For each parent relationship, deduct burn + child take
        let post_childkey = get_parent_child_dividends_distribution(
            hotkey, netuid, raw_dividend
        );

        // Stage 3: Validator/delegate take
        let take_rate = get_hotkey_take(hotkey);
        let validator_take = post_childkey * take_rate;
        let nominator_pool = post_childkey - validator_take;

        // Validator gets their take
        increase_stake(hotkey, owner_coldkey, validator_take);
        // Nominators get the rest, split by stake share
        increase_stake_for_all_nominators(hotkey, nominator_pool);

        // Record what nominators received (cleared each epoch)
        AlphaDividendsPerSubnet::insert(netuid, hotkey, nominator_pool);
    }
}

After distribution, the chain records the final nominator amounts in AlphaDividendsPerSubnet. This value reflects the nominator portion only — after both childkey take and validator take have been deducted. It is cleared and rewritten each epoch, so it always reflects the most recent distribution. The equivalent for root validator dividends is RootAlphaDividendsPerSubnet (v361+).

Events emitted:

Storage:

Staking: Where TAO Flow Comes From

TAO Flow (Step 2) comes from user staking and unstaking operations:

Staking TAO → Alpha

rust
// User calls add_stake(hotkey, netuid, amount)
fn stake_into_subnet(coldkey, hotkey, netuid, tao_amount) {
    // 1. Deduct TAO from coldkey balance
    Balances::transfer(coldkey, pool, tao_amount);

    // 2. Swap TAO for Alpha through liquidity pool
    let alpha = swap_tao_for_alpha(netuid, tao_amount);

    // 3. Add alpha stake for this hotkey
    Stake::insert((hotkey, coldkey, netuid), alpha);

    // 4. Record the TAO inflow (affects subnet share)
    record_tao_inflow(netuid, tao_amount);

    // 5. Emit event
    emit StakeAdded { coldkey, hotkey, netuid, tao: tao_amount, alpha };
}

Unstaking Alpha → TAO

rust
// User calls remove_stake(hotkey, netuid, alpha_amount)
fn unstake_from_subnet(coldkey, hotkey, netuid, alpha_amount) {
    // 1. Remove alpha stake
    Stake::decrease((hotkey, coldkey, netuid), alpha_amount);

    // 2. Swap Alpha for TAO through liquidity pool
    let tao = swap_alpha_for_tao(netuid, alpha_amount);

    // 3. Credit TAO to coldkey balance
    Balances::transfer(pool, coldkey, tao);

    // 4. Record the TAO outflow (affects subnet share)
    record_tao_outflow(netuid, tao);

    // 5. Emit event
    emit StakeRemoved { coldkey, hotkey, netuid, tao, alpha: alpha_amount };
}

Related calls:

Worked Example: Following 0.5 TAO Through the System

Let's trace exactly how one block's emission gets distributed across a simplified network with 3 subnets. This shows the actual numbers at each step.

Setup

  • Block emission: 0.5 TAO (500,000,000 RAO)
  • 3 subnets with different TAO Flow shares
  • Subnet 1: 50% TAO Flow, 10% owner cut, Alpha price = 1.2 TAO
  • Subnet 2: 30% TAO Flow, 5% owner cut, Alpha price = 0.8 TAO
  • Subnet 3: 20% TAO Flow, 0% owner cut, Alpha price = 1.0 TAO

Step-by-Step Distribution

StepSubnet 1Subnet 2Subnet 3
TAO Share0.25 TAO (50%)0.15 TAO (30%)0.10 TAO (20%)
Alpha Minted0.208α (0.25÷1.2)0.188α (0.15÷0.8)0.100α (0.10÷1.0)
Owner Cut0.021α (10%)0.009α (5%)0α (0%)
Remainder0.187α0.179α0.100α
Miners (50%)0.094α0.089α0.050α
Validators (50%)0.094α0.089α0.050α

Final Distribution (per block)

RecipientAlpha ReceivedTAO Value (approx)
Subnet 1 Owner0.021α~0.025 TAO
Subnet 2 Owner0.009α~0.007 TAO
All Miners (total)0.233α~0.232 TAO
All Validators (total)0.233α~0.232 TAO

Note: Within each subnet, individual miner/validator shares are determined by their Incentive and Dividend scores from Yuma Consensus.

Interactive Calculator

Experiment with the emission parameters. Configure subnet TAO Flow shares, owner cuts, and pool sizes, then see how much emission reaches each participant type. Set your own position to calculate your personal earnings.

Emission Calculator

See how block emission flows through subnets to participants

= 500,000,000 RAO

Subnet Configuration

SubnetTAO Flow %Owner Cut %Pool TAOPool Alphaα PriceActions
SN11.200τ
SN20.800τ
SN31.000τ

α Price auto-calculates from Pool TAO / Pool Alpha

Emission Breakdown (per block)

SubnetTAO Inα MintedOwnerMinersValidators
SN10.2500τ0.2083α0.0208α (0.0250τ)0.0938α (0.1125τ)0.0938α (0.1125τ)
SN20.1500τ0.1875α0.009375α (0.007500τ)0.0891α (0.0712τ)0.0891α (0.0712τ)
SN30.1000τ0.1000α0.00e+0α (0.00e+0τ)0.0500α (0.0500τ)0.0500α (0.0500τ)
Total0.5000τ~0.0325τ~0.2337τ~0.2337τ

Your Position

Your emission per block
0.009375α
≈ 0.0112 TAO value
Per hour (~300 blocks)
3.3750 TAO
Per day (~7,200 blocks)
81.0000 TAO

Flow: Block emission → divided by TAO Flow % → converted to Alpha at pool price → owner cut taken first → remainder split 50/50 between miners/validators.

Try: Change pool TAO to see how Alpha price affects the TAO-equivalent value. Higher-priced Alpha means each token is worth more TAO.

Legacy Subnets (Non-dTAO)

Not all subnets have migrated to dTAO – legacy subnets work differently:

AspectdTAO SubnetsLegacy Subnets
Emission ShareTAO Flow (stake activity)Root network weights
Staking TokenAlpha (subnet-specific)TAO (direct)
Liquidity PoolYes (TAO ↔ Alpha)No
Token AppreciationAlpha price varies with demandN/A (just TAO)

For legacy subnets, emission is distributed as TAO directly to participants based on Yuma Consensus scores, without the intermediary Alpha token step.

Summary: Complete Flow

  1. 1 Block starts: Calculate BlockEmission from logarithmic decay (~0.5 TAO)
  2. 2 Subnet shares: Weight by TAO Flow EMA (dTAO) or root weights (legacy)
  3. 3 Pool injection: Inject TAO + mint Alpha (dTAO subnets only)
  4. 4 Split: Owner cut first, then 50/50 to miners/validators
  5. 5 Epoch triggers: Run Yuma Consensus, distribute pending to wallets

Track real-time emission flows and subnet alpha prices on the bittensor.ai dTAO dashboard.

Source Code Reference

Emission mechanics are implemented in:

  • pallets/subtensor/src/coinbase/run_coinbase.rs: Main emission orchestration
  • pallets/subtensor/src/coinbase/subnet_emissions.rs: TAO Flow and share calculation
  • pallets/subtensor/src/staking/stake_utils.rs: TAO↔Alpha swap functions
  • pallets/swap/src/pallet/: V3 liquidity pool implementation

Key functions:

  • run_coinbase(): Orchestrates per-block emission
  • get_block_emission(): Calculate emission amount
  • get_shares_flow(): TAO Flow-based share calculation
  • get_dynamic_tao_emission(): Calculate TAO/Alpha injection amounts
  • emit_to_subnets(): Inject liquidity and split to pending
  • distribute_emission(): Drain pending and distribute at epoch