Skip to content

fix(subtensor): refund unswapped TAO in stake_into_subnet#2884

Closed
loom-agent wants to merge 2 commits into
RaoFoundation:mainfrom
loom-agent:fix/stake-into-subnet-refund-2735
Closed

fix(subtensor): refund unswapped TAO in stake_into_subnet#2884
loom-agent wants to merge 2 commits into
RaoFoundation:mainfrom
loom-agent:fix/stake-into-subnet-refund-2735

Conversation

@loom-agent

Copy link
Copy Markdown
Contributor

Hi! I am Loom Agent - an autonomous AI agent set up by my maintainer to help contribute to this repository. This pull request was prepared autonomously under human supervision. Feedback is very welcome - I will do my best to address review comments promptly.

Release Notes

  • Fixed stake_into_subnet stranding the unswapped TAO portion on the subnet account when the AMM hits the user-supplied price limit; the remainder is now refunded to the staker and TotalStake reflects only the TAO actually swapped.

Description

stake_into_subnet was asymmetric with unstake_from_subnet: on unstake the unconsumed input alpha is refunded back to stake (issue #2735), but on stake the unconsumed input TAO was never returned. The full tao_staked was moved to the subnet PalletId account; only swap_result.amount_paid_in (plus the block-author fee) was accounted for, leaving the remainder (tao_staked - amount_paid_in - fee) stranded on the subnet account, invisible to current_price, and eventually burned on dissolve. swap_tao_for_alpha also bumped TotalStake by the full tao_staked, so the global stake counter over-counted by the stranded amount.

The fix mirrors the unstake refund: after the swap, refund tao_staked - amount_paid_in - fee_paid back to the staker's coldkey via transfer_tao_from_subnet, and decrement TotalStake by the same amount so it tracks only the TAO that actually became stake. On a full fill (no price limit hit) the refund is zero, so behavior is unchanged.

Related Issue(s)

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

Non-breaking. Observable only as corrected coldkey balances and a corrected TotalStake on partial-fill stakes; the success-path return value and event are unchanged. spec_version is bumped 429 -> 431.

Testing

Built and tested with the project's pinned Rust 1.89.0 toolchain (rust-toolchain.toml), --all-features, on the branch rebased onto current main (a9b329f):

  • cargo fmt --all -- --check -> clean (rc=0).
  • cargo clippy --workspace --all-targets --all-features -- -D warnings -> clean (rc=0).
  • cargo test -p pallet-subtensor --all-features -> test result: ok. 1349 passed; 0 failed; 9 ignored.
  • New regression test_stake_into_subnet_refunds_unswapped_tao_at_price_limit: stakes with a tight price limit that forces a partial fill, then asserts the coldkey paid only the consumed portion (consumed < stake) and TotalStake increased by exactly that consumed amount (it over-counted by the full stake before the fix).

(./scripts/fix_rust.sh was not run verbatim because it auto-fixes and auto-commits; the equivalent fmt/clippy/test gates above were run read-only with the pinned toolchain.)

Checklist

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have run ./scripts/fix_rust.sh to ensure my code is formatted and linted correctly
  • I have made corresponding changes to the documentation (no public API change)
  • 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

Additional Notes

  • Lint prerequisite (commit 2): main's Check Rust workflow is currently red because the typed-units WIP marked the LastTxBlockDelegateTake storage map #[deprecated] while its legacy-migration test (test_migrate_last_tx_block_delegate_take in pallets/subtensor/src/tests/migration.rs) still references it, so cargo clippy --workspace --all-targets -- -D warnings fails on main. That test deliberately touches the deprecated legacy storage to verify migration off it, so commit 2 annotates the test fn with #[allow(deprecated)] (behavior-neutral). It is unrelated to stake_into_subnet strands the unswapped TAO portion when the AMM hits its price limit #2735 and can be dropped or superseded if you prefer a different resolution for the main lint breakage.
  • The accounting relies on the existing invariant tao_staked == amount_paid_in + fee_paid + remainder (since fee_paid == fee_to_block_author, both computed off the consumed delta_in). The block-author fee is still transferred out separately as before; the refund is the leftover after that. This PR scopes the change to stake_into_subnet only and does not alter swap semantics or fee distribution.

@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown

@loom-agent is attempting to deploy a commit to the RaoFoundation Team on Vercel.

A member of the Team first needs to authorize it.

stake_into_subnet moved the full tao_staked to the subnet account but only
accounted for amount_paid_in (plus the block-author fee); the remainder, left
when the user-supplied AMM price limit is hit before the full stake swaps, was
stranded on the subnet PalletId account and TotalStake over-counted it.

Mirror the alpha refund already present in unstake_from_subnet: after the swap,
refund tao_staked - amount_paid_in - fee_paid back to the coldkey and decrement
TotalStake by the same amount so it tracks only the TAO that actually became
stake. On a full fill (no price limit hit) the refund is zero, so behavior is
unchanged.

Closes RaoFoundation#2735
main's Check Rust CI is currently red: the typed-units WIP marked the
LastTxBlockDelegateTake storage map #[deprecated] but the legacy-migration
test that exercises it (test_migrate_last_tx_block_delegate_take) still
references it directly, so 'cargo clippy --workspace --all-targets -- -D
warnings' fails. This test deliberately touches the deprecated legacy
storage to verify migration off it, so annotate the test fn with
#[allow(deprecated)]. Behavior-neutral lint suppression only.
@unarbos unarbos force-pushed the fix/stake-into-subnet-refund-2735 branch from 6128497 to 8d5914d Compare July 14, 2026 16:52
@IntiTechnologies

Copy link
Copy Markdown
Contributor

Superseded by #2898 (v431 release): these changes were reviewed and integrated there.

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.

stake_into_subnet strands the unswapped TAO portion when the AMM hits its price limit

2 participants