Skip to content

Re-add Swap::AlphaSqrtPrice for backwards compatibility; bump spec to…#2799

Open
sam0x17 wants to merge 3 commits into
mainfrom
re-add-back-compat-things
Open

Re-add Swap::AlphaSqrtPrice for backwards compatibility; bump spec to…#2799
sam0x17 wants to merge 3 commits into
mainfrom
re-add-back-compat-things

Conversation

@sam0x17

@sam0x17 sam0x17 commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Description

The balancer migration shipped in v3.4.8-423 deleted the Swap::AlphaSqrtPrice storage map. It was removed as collateral of the Uniswap-V3 → balancer engine rewrite: under V3, AlphaSqrtPrice was the primary price state variable, but under the balancer price became a derived quantity (computed on the fly from reserves + weights in current_price), so the stored variable was dropped along with the rest of the V3 machinery (ticks, positions, liquidity, fee-growth accumulators).

That map is a de-facto public interface: external consumers (indexers, dashboards, wallets, SDKs) read Swap.AlphaSqrtPrice directly via state_getStorage to obtain the subnet price, exactly as they did under V3. Removing it without a deprecation path broke them.

This PR re-adds it as a backwards-compatibility shim:

  • Re-introduces the storage map with its exact prior definition (StorageMap<_, Twox64Concat, NetUid, U64F64, ValueQuery>), so consumers get the same key/hasher/value/units as before.
  • Maintains it as a read-only mirror of the derived balancer price (sqrt(current_price)), refreshed at every price-change point: subnet init, swap, and protocol-liquidity adjustment; removed on dissolve.
  • The migrate_swapv3_to_balancer migration now retains the old V3 values as the initial seed (the remove_prefix("Swap", "AlphaSqrtPrice", …) line is dropped) instead of clearing them, so there is no gap at upgrade.

No V3 engine logic is reintroduced — the map is purely a price mirror for back-compat. The other removed V3 maps (Ticks, Positions, CurrentTick, CurrentLiquidity, TickIndexBitmapWords, FeeGlobalTao/Alpha, LastPositionId, EnabledUserLiquidity, SwapV3Initialized) are intentionally left removed — they have no balancer equivalent and restoring them would mean fabricating meaningless values.

Also bumps spec_version 423 → 424.

Related Issue(s)

N/A — addresses downstream reports of Swap.AlphaSqrtPrice reads returning empty after the balancer upgrade.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Other (please describe):

Breaking Change

None. This restores a previously-broken interface and adds no new constraints. The storage layout is identical to v3.4.7-422.

Notes for reviewers

Why storage and not just the runtime API? A supported price API already exists — current_alpha_price(netuid) (since v3.1.6) and current_alpha_price_all() (since v3.3.10-380). Consumers should migrate to those, and the restored map is documented as back-compat-only. But the convenient bulk _all variant is only a few months old, so a lot of existing tooling still reads raw storage; this shim unbreaks them now. If the map is ever dropped again it should go through an explicit deprecation notice rather than a silent removal.

State bloat? Bounded and self-cleaning: one U64F64 (16 bytes) per subnet, capped by SubnetLimit (default 128) → ~2 KB of values. Same cardinality as existing per-subnet maps written every block (SubnetMovingPrice, RootProp). Created on init, removed on dissolve — does not grow with swaps, accounts, or time. None of the genuinely bloaty V3 structures are reintroduced.

Consistency: refresh_alpha_sqrt_price runs inside the swap's transactional scope, so it is correctly rolled back on simulated swaps. For emitting subnets it is refreshed every block via adjust_protocol_liquidity; for idle subnets the value stays correct because price only moves via swaps/emission.

Checklist

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • cargo fmt + cargo clippy --all-targets --all-features run clean on the affected crate (no new warnings)
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Testing

  • cargo test -p pallet-subtensor-swap --lib — 44 passed. The two migrate_swapv3_to_balancer tests were updated to assert AlphaSqrtPrice is retained (seeded) across the migration rather than cleared.
  • Full runtime Rust integration verified via SKIP_WASM_BUILD=1 cargo check -p node-subtensor-runtime (clean). The WASM build itself is left to CI (local clang here can't target wasm32 for the zstd-sys C dependency — an environment issue, not a code issue).

… 424

The balancer migration (v3.4.8-423) deleted the Swap::AlphaSqrtPrice
storage map as collateral of the Uniswap-V3 -> balancer engine rewrite,
where price became a derived quantity instead of stored state. External
consumers (indexers, dashboards, wallets, SDKs) read that map directly to
obtain the subnet price and broke.

Re-add the storage map with its exact prior definition and maintain it as
a read-only mirror of the derived balancer price (sqrt of current_price),
refreshed on every price change (init, swap, protocol-liquidity adjust)
and removed on dissolve. The migration now retains the V3 values as the
initial seed instead of clearing them, so there is no gap at upgrade.

No V3 engine logic is reintroduced; the map is purely for back-compat.
@github-actions

Copy link
Copy Markdown
Contributor

🚨🚨🚨 HOTFIX DETECTED 🚨🚨🚨

It looks like you are trying to merge a hotfix PR into main. If this isn't what you wanted to do, and you just wanted to make a regular PR, please close this PR, base your changes off the devnet-ready branch and open a new PR into devnet ready.

If you are trying to merge a hotfix PR, please complete the following essential steps:

  1. go ahead and get this PR into main merged, so we can get the change in as quickly as possible!
  2. merge main into testnet, bumping spec_version
  3. deploy testnet
  4. merge testnet into devnet, bumping spec_version
  5. deploy devnet
  6. merge devnet into devnet-ready

If you do not complete these steps, your hotfix may be inadvertently removed in the future when branches are promoted to main, so it is essential that you do so.

@github-actions github-actions Bot added the hotfix This PR needs to be merged very quickly and will likely skip testing on devnet and testnet label Jun 25, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI review — see the sticky summary comment for the verdict and the inline comments below for specific findings.

let epsilon =
U64F64::saturating_from_num(1).safe_div(U64F64::saturating_from_num(1_000_000_000_u64));
let sqrt_price = price.checked_sqrt(epsilon).unwrap_or_default();
AlphaSqrtPrice::<T>::insert(netuid, sqrt_price);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[MEDIUM] New price-mirror storage write is not reflected in weights

refresh_alpha_sqrt_price performs a persistent storage write and is now called from hot paths including adjust_protocol_liquidity and swap_inner, but this PR does not update the affected runtime weights. Those paths are reachable from per-block emission handling and user-facing swap/stake extrinsics, so blocks can now do at least one extra storage write, plus the helper's price reads, beyond what the declared weights account for. Regenerate or manually update the affected weights and block-emission accounting before merging.

@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

🛡️ AI Review — Skeptic (security review)

VERDICT: VULNERABLE

BASELINE scrutiny: author is a repo admin with long merged history; branch targets main but has a hotfix label and explicit hotfix rationale.

No .github/ai-review/* or .github/copilot-instructions.md changes are present, and the diff has no dependency or build-script changes.

Findings

Sev File Finding
MEDIUM pallets/swap/src/pallet/impls.rs:50 New price-mirror storage write is not reflected in weights inline

Prior-comment reconciliation

  • 4a5680f4: not addressed — The price mirror was changed to use the swap step's final price, but the added AlphaSqrtPrice write/sqrt still runs on swap and emission paths without corresponding weight updates.

Conclusion

VULNERABLE because the PR still adds a storage-mutating fixed-point price mirror on swap/emission paths without updating the runtime weight accounting. I found no malicious indicators.


📜 Previous run (superseded)
Sev File Finding Status
MEDIUM pallets/swap/src/pallet/impls.rs:48 New price-mirror storage write is not reflected in weights ➡️ Carried forward to current findings
The price mirror was changed to use the swap step's final price, but the added AlphaSqrtPrice write/sqrt still runs on swap and emission paths without corresponding weight updates.

# 🔍 AI Review — Auditor (domain review) has not yet run on this PR.

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: VULNERABLE

The swap-path refresh previously derived the price from reserves inside
swap_inner, but a swap's reserve deltas are applied by the caller
(stake_utils), outside this pallet — so it read pre-swap reserves and
mirrored a stale price. Surface the swap step's computed final price and
store that instead, which is the correct post-swap price without needing
committed reserves.

Init and emission (adjust_protocol_liquidity) still derive from
current_price, where reserves are already up to date. Add a dedicated
test covering init seeding, post-swap tracking, simulated-swap rollback,
and clear-on-dissolve.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI review — see the sticky summary comment for the verdict and the inline comments below for specific findings.

Comment on lines +45 to +50
pub(crate) fn store_alpha_sqrt_price(netuid: NetUid, price: U64F64) {
// Epsilon for the bisection sqrt: 1e-9 is well below the price precision consumers need.
let epsilon =
U64F64::saturating_from_num(1).safe_div(U64F64::saturating_from_num(1_000_000_000_u64));
let sqrt_price = price.checked_sqrt(epsilon).unwrap_or_default();
AlphaSqrtPrice::<T>::insert(netuid, sqrt_price);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[MEDIUM] New price-mirror storage write is not reflected in weights

store_alpha_sqrt_price now performs a fixed-point sqrt and writes Swap::AlphaSqrtPrice from initialization, adjust_protocol_liquidity, and the real/simulated swap path, but this PR does not update the benchmarked weights for the Subtensor extrinsics and block paths that call SwapInterface::swap or protocol-liquidity adjustment. That undercharges repeated swaps/emission for both CPU and an additional storage write, which is a runtime resource-accounting issue. Rerun/update the affected benchmarks or otherwise add the extra DB write and computation cost to the relevant weights before merging.

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: VULNERABLE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

hotfix This PR needs to be merged very quickly and will likely skip testing on devnet and testnet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant