feat: net TAO flow for emission allocation#2634
Merged
Merged
Conversation
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>
JohnReedV
approved these changes
May 4, 2026
sam0x17
approved these changes
May 4, 2026
gztensor
reviewed
May 5, 2026
| ); | ||
|
|
||
| // Reset per-block root sell counters from the previous block. | ||
| // Root sells (step 8 in block_step) happen after coinbase, so their |
Contributor
There was a problem hiding this comment.
Step numbers in ai generated comments are fragile, I suggest we do not refer to them.
| SubnetProtocolFlow::<T>::remove(netuid); | ||
| } | ||
|
|
||
| fn get_ema_protocol_flow(netuid: NetUid) -> I64F64 { |
Contributor
There was a problem hiding this comment.
This method is a getter, it should not modify state
| .iter() | ||
| .map(|netuid| (*netuid, Self::get_ema_flow(*netuid))) | ||
| .map(|netuid| { | ||
| let user_ema = Self::get_ema_flow(*netuid); |
Contributor
There was a problem hiding this comment.
Do not call get_ema_flow if net_flow_enabled is false, it adds unnecessary state reads.
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replace gross user flow
ema(buys - sells)with net flowema(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):
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 changes the emission allocator to maximize subnet TAO inflow net of protocol subsidy.
The net protocol cost to a subnet per block is:
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)
stake_into_subnet→record_tao_inflowunstake_from_subnet→record_tao_outflowadjust_protocol_liquidity(direct)swap_tao_for_alpha(direct, not via stake)swap_alpha_for_tao(direct, not via unstake)Changes (7 files, +130 lines)
New per-block storage (auditable base values):
SubnetExcessTao— actual excess TAO from swap result (recorded inside success path)SubnetRootSellTao— TAO from root dividend sells per blockProtocol cost EMA:
SubnetProtocolFlow— per-block accumulator (emit + chain_buys − root_sells)SubnetEmaProtocolFlow— EMA with same smoothing factor as user EMAShare computation:
net_ema = ema(user_flow) - ema(protocol_cost)when toggle is onSudo toggle:
NetTaoFlowEnabled(default: on) —sudo_set_net_tao_flow_enabled(call_index 91)falseto instantly revert to gross flow behaviorCleanup: all new storage items removed on subnet deregistration.
Test plan
get_ema_protocol_flowwith known inputsget_shares_flowproduces correct net shares when protocol EMA > 0SubnetEmaTaoFlowbehavior🤖 Generated with Claude Code