Skip to content

feat: net TAO flow for emission allocation#4

Open
igoraxz wants to merge 1 commit intodevnet-readyfrom
feat/net-tao-flow
Open

feat: net TAO flow for emission allocation#4
igoraxz wants to merge 1 commit intodevnet-readyfrom
feat/net-tao-flow

Conversation

@igoraxz
Copy link
Copy Markdown
Owner

@igoraxz igoraxz commented May 3, 2026

Summary

Replace gross user flow ema(buys - sells) with net flow ema(buys - sells) - ema(emission + chain_buys - root_sells) for emission share computation.

Subnets only receive emissions when they generate positive net TAO inflow for the network.

Simulation results (30-day backtest):

  • Current gross flow: 55 subnets EMA > 0 → aggregate profit = −362 τ/day (network losing TAO)
  • Net flow: 33 subnets EMA > 0 → aggregate profit = +571 τ/day (network gaining TAO)

Rationale

Currently the network subsidizes subnets for gross TAO flow (buys − sells). This heavily misallocates incentives to subnets with negative net TAO flow for the network: e.g. a subnet gets 1 TAO in user buys → receives 4 TAO in protocol subsidy → net TAO flow ("subnet profit") is −3 TAO.

The fix is to change the emission allocator to maximize subnet TAO inflow net of protocol subsidy.

The net protocol cost to a subnet per block is:

net_subsidy = (emission_injected + chain_buys) - root_sells
  • Emission injects TAO into pool → network gives
  • Chain buys (excess TAO swapped for alpha) inject TAO → network gives
  • Root sells (root validators claiming dividends as TAO) remove TAO → network takes back

A subnet that receives 10 TAO emission but returns 3 TAO via root sells has an actual protocol cost of 7 TAO. It should only need to attract 7 TAO in user buys to be net-positive, not 10.

This update also addresses the runaway effect of chain buys — runaway emission cannot be sustained unless a subnet continuously attracts MORE external TAO than the protocol gives it in emission + chain buys.

Flow separation (no cross-contamination)

User flows and protocol flows are tracked in completely independent accumulators:

Flow Code path SubnetTaoFlow (user) SubnetProtocolFlow (protocol)
User buy (stake) stake_into_subnetrecord_tao_inflow ✅ (+)
User sell (unstake) unstake_from_subnetrecord_tao_outflow ✅ (−)
Emission injection adjust_protocol_liquidity (direct) ✅ (+)
Chain buys (excess) swap_tao_for_alpha (direct, not via stake) ✅ (+)
Root sells swap_alpha_for_tao (direct, not via unstake) ✅ (−)

Root sells are only recorded on the swap path (root validator claims TAO). If a root validator keeps alpha instead of swapping (Keep mode), no TAO leaves the pool and nothing is recorded. The recorded amount is amount_paid_out — the actual TAO that left the pool via AMM, not a theoretical value.

Block-level sequencing

Block N:
  User extrinsics → SubnetTaoFlow accumulates
  Step 4: run_coinbase
    ├─ SubnetRootSellTao::clear()           ← reset audit counter from N-1
    ├─ get_shares_flow()
    │   ├─ get_ema_flow()                   ← fold SubnetTaoFlow (from N-1), reset
    │   └─ get_ema_protocol_flow()          ← fold SubnetProtocolFlow (from N-1), reset
    │   └─ net_ema = user_ema - protocol_ema (if toggle on)
    └─ inject_and_maybe_swap()
        ├─ SubnetProtocolFlow += emission
        └─ SubnetProtocolFlow += excess
  Step 8: run_auto_claim_root_divs
    └─ SubnetProtocolFlow -= root_sell_tao
    └─ SubnetRootSellTao += root_sell_tao

→ Block N's accumulated protocol cost folded into EMA at block N+1
  (same one-block delay as user flows — consistent timing)

Changes (7 files, +127 lines)

New per-block storage (auditable base values):

  • SubnetExcessTao — excess TAO swapped (chain buys) per block
  • SubnetRootSellTao — TAO from root dividend sells per block

Protocol cost EMA:

  • SubnetProtocolFlow — per-block accumulator (emit + chain_buys − root_sells)
  • SubnetEmaProtocolFlow — EMA with same smoothing factor as user EMA

Share computation:

  • net_ema = ema(user_flow) - ema(protocol_cost) when toggle is on
  • Protocol EMA always computed regardless of toggle (stays warm for instant switching)

Sudo toggle:

  • NetTaoFlowEnabled (default: on) — sudo_set_net_tao_flow_enabled (call_index 91)
  • Set to false to instantly revert to gross flow behavior

Cleanup: all new storage items removed on subnet deregistration.

Test plan

  • Unit tests for get_ema_protocol_flow with known inputs
  • Verify get_shares_flow produces correct net shares when protocol EMA > 0
  • Verify toggle off reverts to gross flow behavior
  • Verify new storage items cleaned up on deregistration
  • Integration test: simulate emission + chain buys + root sells over multiple blocks, verify protocol EMA converges
  • Verify no regression on existing SubnetEmaTaoFlow behavior

🤖 Generated with Claude Code

// Record protocol costs for net-tao-flow EMA.
SubnetExcessTao::<T>::insert(*netuid_i, tao_to_swap_with);
Self::record_protocol_inflow(*netuid_i, injected_tao);
Self::record_protocol_inflow(*netuid_i, tao_to_swap_with);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this be more accurate as
Self::record_protocol_inflow(*netuid_i, buy_swap_result_ok.amount_paid_in); instead?

@igoraxz igoraxz force-pushed the feat/net-tao-flow branch 2 times, most recently from 0e16e0e to f8f89f6 Compare May 4, 2026 20:03
Replace gross user flow (buys - sells) with net flow (user flow - protocol cost)
for emission share computation. This ensures subnets only receive emissions when
they generate positive net TAO inflow for the network, preventing subsidized
extraction where a subnet receives more in protocol emissions than it attracts
in external capital.

New per-block storage (auditable base values):
- SubnetExcessTao: excess TAO swapped (chain buys) per block
- SubnetRootSellTao: TAO from root dividend sells per block

New protocol cost tracking:
- SubnetProtocolFlow: per-block accumulator (emit + chain_buys - root_sells)
- SubnetEmaProtocolFlow: EMA of protocol cost, same smoothing as user flow EMA

Emission share computation:
- net_ema = ema(user_flow) - ema(protocol_cost)
- Protocol EMA starts from zero and scales in over ~30 days
- Sudo toggle NetTaoFlowEnabled (default: on) to switch between net and gross flow

Sudo call: sudo_set_net_tao_flow_enabled (call_index 91)

Cleanup: all new storage items removed on subnet deregistration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@igoraxz igoraxz force-pushed the feat/net-tao-flow branch from f8f89f6 to ea465d0 Compare May 4, 2026 20:07
@igoraxz igoraxz changed the base branch from main to devnet-ready May 4, 2026 20:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants