Skip to content

migrate_cleanup_swap_v3 is never wired, so dropping the *Provided reserve addend shrinks every affected subnet's reserves at upgrade #2793

Description

@Maksandre

Describe the bug

The PR removes the SubnetTaoProvided / SubnetAlphaInProvided addends from the AMM reserve read and relies on a migration to fold those residuals into the main reserves first. The migration is never run.

reserve() now returns the bare reserve, with no + *Provided term:

fn reserve(netuid: NetUid) -> TaoBalance {
    SubnetTAO::<T>::get(netuid)        // was SubnetTAO + SubnetTaoProvided pre-PR
}

(lib.rs:2782 for TAO, lib.rs:2800 for alpha.) Continuity relies on migrate_cleanup_swap_v3 folding the residuals before readers stop counting them. That migration is absent from the pallet on_runtime_upgrade chain (last entry is migrate_fix_subnet_hotkey_lock_swaps, hooks.rs:180) and from the runtime Migrations tuple, which contains only two unrelated migrations:

type Migrations = (
    pallet_subtensor::migrations::migrate_init_total_issuance::initialise_total_issuance::Migration<Runtime>,
    migrations::PalletRegistryCleanupMigration,
);

(runtime/src/lib.rs:1665.) The migration is declared and unit-tested but wired nowhere, so it never runs. On every subnet holding a non-zero residual, the upgrade drops reserve() by exactly that residual, jumping the AMM spot price and slippage discontinuously. current_alpha_price feeds every add_stake / remove_stake / move_stake / dividend / limit-order quote, so the dislocation is consensus- and money-affecting. The residual liquidity is permanently excluded from the AMM and, on dissolution, recycled to the registration pool instead of distributed to that subnet's stakers; post-PR no setter writes the *Provided maps, so any pre-existing residual persists untouched.

To Reproduce

  1. Start from a subnet holding a non-zero SubnetTaoProvided / SubnetAlphaInProvided residual (carried forward from the swap-v3 liquidity era).
  2. Apply the PR mainnet deploy June 24th, 2026 #2769 runtime upgrade and run on_runtime_upgrade.
  3. Observe HasMigrationRun("migrate_cleanup_swap_v3") is still false and the residual is never folded into SubnetTAO / SubnetAlphaIn.
  4. Read reserve() / current_alpha_price before vs after the upgrade: the reserve drops by exactly the residual and the spot price jumps discontinuously.
  5. Stake an identical amount before vs after: the alpha credited differs (proof of concept measured a 19% spot-price jump and a 16.9% per-stake alpha error on a realistic one-sided residual).

Expected behavior

The *Provided residual is folded into the main reserves in the same upgrade that drops the addend from reserve(), so reserves and spot price stay continuous. Wire migrate_cleanup_swap_v3 into on_runtime_upgrade (or the runtime Migrations tuple); its HasMigrationRun guard already makes it idempotent.

Screenshots

No response

Environment

testnet@0c774f00

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions