swap_basket
Call v464 → current #150Rebalances 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 chainCall Workflow
Click items to navigate. Pan and zoom to explore.
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
| # | Name | Type | Description |
|---|---|---|---|
| 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
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
Storage Modified
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