Skip to content

feat: matured TaoFlow EMA to reduce capital recycling attacks#2704

Open
igoraxz wants to merge 1 commit into
opentensor:devnet-readyfrom
igoraxz:feat/matured-ema-recycling
Open

feat: matured TaoFlow EMA to reduce capital recycling attacks#2704
igoraxz wants to merge 1 commit into
opentensor:devnet-readyfrom
igoraxz:feat/matured-ema-recycling

Conversation

@igoraxz
Copy link
Copy Markdown
Contributor

@igoraxz igoraxz commented Jun 1, 2026

Problem

The user-flow EMA that drives emission allocation reacts symmetrically to inflows and outflows. That symmetry lets a participant temporarily inflate a subnet's emission share with capital that is later withdrawn, rather than rewarding durable demand.

Change

Add a second EMA on top of the existing user-flow EMA, and use the lower of the two as the signal:

raw     = flow EMA of (buys - sells)     [existing]
slow    = flow EMA of raw                [new]
matured = min(raw, slow)                 [used in the share calc instead of raw]

Because slow lags raw, the clamp is asymmetric:

  • Inflow spike -> raw jumps above slow -> matured = slow: credit accrues slowly.
  • Outflow -> raw drops below slow -> matured = raw: the decrease applies immediately.
  • Steady genuine flow -> raw ~= slow -> matured ~= raw: no penalty for real demand.

So transient inflows are credited only at the slow EMA's pace, while withdrawals take effect immediately. Durable, sustained inflow still converges to the full signal.

Design notes

  • No new parameter -- slow reuses FlowEmaSmoothingFactor. A sweep of the maturity half-life against both manipulation resistance and honest-subnet bootstrap time put the optimum at the same half-life as the main flow EMA: it is the knee of the trade-off (shorter weakens the clamp, longer barely improves resistance while slowing new-subnet onboarding). Equal factors also make slow a clean double-EMA of the flow.
  • SubnetEmaSlowTaoFlow stores the unclamped EMA(raw), not min(raw, slow) -- the clamp is applied only at read time, so the slow EMA keeps tracking the true long-run signal and can recover.
  • First access seeds slow = raw so existing subnets see no emission cliff at deployment.
  • Protocol EMA is not matured -- only user demand is delayed.

Test plan

  • Slow EMA persists and smooths; seeds at raw on first access (no cliff)
  • Inflow spike -> matured < raw; outflow -> matured = raw; steady flow -> matured = raw
  • SubnetEmaSlowTaoFlow cleaned up on deregistration

Builds on #2675 (normalized protocol cost), already merged to devnet-ready.

@igoraxz igoraxz force-pushed the feat/matured-ema-recycling branch 4 times, most recently from bc69263 to 8c8b229 Compare June 1, 2026 10:33
The user-flow EMA driving emission allocation reacts symmetrically to
inflows and outflows, letting transient capital inflate a subnet's
emission share before it is withdrawn. This adds a second EMA on top of
the user-flow EMA and uses the lower of the two as the signal:

  raw     = flow EMA of (buys - sells)     [existing]
  slow    = flow EMA of raw                [new]
  matured = min(raw, slow)                 [used in the share calc]

Because slow lags raw, the clamp is asymmetric:
  Inflow spike: raw rises above slow -> matured = slow (credit accrues slowly)
  Outflow:      raw drops below slow -> matured = raw  (applies immediately)
  Steady flow:  raw ~= slow           -> matured ~= raw (no penalty)

Transient inflows are credited only at the slow EMA's pace while
withdrawals take effect immediately; durable sustained inflow still
converges to the full signal.

Design notes:
- No new parameter: slow reuses FlowEmaSmoothingFactor. A sweep of the
  maturity half-life against both manipulation resistance and
  honest-subnet bootstrap time put the optimum at the same half-life as
  the main flow EMA (the knee of the trade-off); equal factors make slow
  a clean double-EMA of the flow.
- SubnetEmaSlowTaoFlow stores the unclamped EMA(raw), not min(raw, slow),
  so the slow EMA tracks the true long-run signal and can recover; the
  clamp is applied only at read time.
- On first access the slow EMA seeds at the current raw EMA (no emission
  cliff at deployment) with last_block = 0, so the update branch runs and
  persists; the first update is a no-op (slow = raw).
- Protocol EMA is not matured -- only user demand is delayed.

Builds on the normalized protocol cost change (opentensor#2675).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@igoraxz igoraxz force-pushed the feat/matured-ema-recycling branch from 8c8b229 to 4d5725e Compare June 1, 2026 10:52
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.

1 participant