swap_basket

Call v464 → current #150

Rebalances a root validator 's beta basket: sells alpha of one holding for TAO and buys another holding with it, inside protocol price, turnover, liquidity and concentration bounds.

View calls on chain

Click items to navigate. Pan and zoom to explore.

Used by: validatorsdevelopersanalytics

The Big Picture

From v464 a beta basket composition changes only through this call. set_root_weights and RootWeightsCap were removed in the same runtime. The guardrails are independent of each other: the 200 basis point band bounds each leg against a same-block price move, the turnover bucket bounds how much of NAV can move per day, the liquidity cap bounds exposure to one pool, the concentration cap bounds exposure to one holding, and min_amount_out is the trader own floor on top. Source: pallets/subtensor/src/staking/basket_trade.rs (do_swap_basket, try_swap_basket) and the dispatch at macros/dispatches.rs call index 150, at v467.

Why This Matters

Stakers hold shares of the fund, not of any one subnet. This is the lever that changes what those shares are backed by. The bounds exist so one call cannot turn a diversified fund into a bet on a single pool or move a thin pool against the holders.

Example Scenario

A validator sells 1,000 alpha of subnet 3 for TAO and buys subnet 7 with it, passing min_amount_out = 900. The sell leg realizes 40 TAO, the buy leg credits 950 alpha, and BasketSwapped reports alpha_sold = 1000, tao_mid = 40 TAO and alpha_bought = 950. Had the buy leg credited 880, the whole call would have rolled back with BasketMinOutNotMet.

Common Questions

What does netuid 0 mean on either side?
The fund TAO cash slot. Selling into root parks TAO; buying from root deploys it. When origin is root, amount is TAO at 1:1.
The trade fits every cap. Why SlippageTooHigh?
Each leg must fill entirely within 200 basis points of the strictest of three references: the slow moving price, SubnetFastMovingPrice and spot. After a recent move the fast price lags spot, so the bound binds before the leg fills. Trade less or wait.
Does this change who owns what?
No. Shares and BasketClaimed watermarks are untouched. Only the composition behind the shares changes.

Use Cases

  • Rotate a fund out of one subnet and into another without touching any staker position
  • Park a holding in the TAO cash slot, or deploy idle TAO from it
  • Explain a change in fund composition that no deposit or claim accounts for

From Chain Metadata

Rebalances a root validator's beta basket: sells `amount` of the fund's `origin_netuid` holding for TAO and buys `destination_netuid` with it. Either side may be root (netuid 0), the fund's TAO cash slot. Fund shares and staker entitlements are unchanged; only the fund's composition moves. Guardrails: each AMM leg must fill fully within 2% of the subnet's moving price; the TAO through the middle is taken from the fund's turnover bucket (`BasketDailyTurnoverCap` of NAV, refilling over 7200 blocks); the destination holding may not end above `BasketLiquidityCap` of the destination pool's alpha reserve, nor above `BasketConcentrationCap` of NAV. Trading must be enabled network-wide and not frozen for the hotkey by governance. On top of the protocol band the caller may set its own floor: the buy leg must credit at least `min_amount_out` or the trade rolls back.

Input Parameters

#NameTypeDescription
0
hotkey
AccountId hotkey: Account address (32 bytes, SS58-encoded) (hex -> SS58)
1
origin_netuid
NetUid origin_netuid: Subnet ID (u16, 0-65535)
2
destination_netuid
NetUid destination_netuid: Subnet ID (u16, 0-65535)
3
amount
AlphaBalance amount: Alpha amount in alpha-RAO (÷10⁹ for alpha)
4
min_amount_out
u64 min_amount_out (u64) (RAO -> TAO (/ 10^9))

Permissions

Origin
Signed
Required Role

Permission data inferred from metadata. May be incomplete.

Requirements

  • BasketTradingEnabled is true (otherwise BasketTradingDisabled)
  • hotkey is not in BasketTradingFrozen (otherwise BasketTradingFrozen)
  • Beta basket seed migration is idle (otherwise BetaBasketSeedInProgress)
  • origin_netuid differs from destination_netuid (otherwise BasketSameSubnet)
  • Signed by the coldkey that owns hotkey, or by its BasketTrading proxy (otherwise NonAssociatedColdKey)
  • hotkey is registered on root, netuid 0 (otherwise HotKeyNotRegisteredInSubNet)
  • Both subnets exist (otherwise SubnetNotExists)
  • SubtokenEnabled is true on each non-root side: the destination from v464, the origin from v466 (otherwise SubtokenDisabled)
  • amount is above zero and no more than the fund holds on origin_netuid (otherwise AmountTooLow or NotEnoughStakeToWithdraw)
  • The sell leg yields at least InitialMinStake of TAO (otherwise AmountTooLow)
  • Each AMM leg fills completely within 200 basis points of the strictest of the subnet moving price, SubnetFastMovingPrice and spot (otherwise SlippageTooHigh)
  • The buy leg credits at least min_amount_out; 0 sets no floor (otherwise BasketMinOutNotMet)
  • The TAO through the middle fits the fund turnover bucket (otherwise BasketTurnoverBudgetExceeded)
  • After the buy the destination holding is within BasketLiquidityCap of that pool alpha reserve and within BasketConcentrationCap of fund NAV (otherwise BasketLiquidityCapExceeded or BasketConcentrationCapExceeded)

Effects

Events Emitted

Postconditions

  • The fund holds amount less alpha on origin_netuid and alpha_bought more on destination_netuid. Root is the TAO cash slot, valued 1:1
  • BasketTradeBucket for hotkey is debited by the TAO through the middle
  • From v466, BasketLiquidityUsed for (hotkey, destination_netuid) is credited with alpha_bought
  • Fund shares, staker entitlements and BasketClaimed watermarks are unchanged

Side Effects

  • Emits BasketSwapped with alpha_sold, tao_mid and alpha_bought
  • Both legs pay the ordinary AMM swap fees and move the pool prices
  • Declared weight is sized for 256 holdings and refunded to the real holding count after dispatch
  • Runs the flat pending-deposit flush every flushing extrinsic performs

Code Examples

import { createClient, Binary } from "polkadot-api";
import { getWsProvider } from "polkadot-api/ws";
import { sub } from "@polkadot-api/descriptors"; // generated by: npx papi add sub -w wss://entrypoint-finney.opentensor.ai:443

const client = createClient(getWsProvider("wss://entrypoint-finney.opentensor.ai:443"));
const api = client.getTypedApi(sub);

// Build swap_basket call (typed, named args)
const hotkey = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY";
const origin_netuid = 1;
const destination_netuid = 1;
const amount = 1_000_000_000n;
const min_amount_out = 1_000_000_000n;

const tx = api.tx.SubtensorModule.swap_basket({
  hotkey,
  origin_netuid,
  destination_netuid,
  amount,
  min_amount_out,
});

Runtime Info

View Source
Pallet Index
7
Call Index
150
First Version
v464
Current Version
v472