# swap-basket (/docs/tx/swap-basket)

Sells `amount` of the fund's `origin_netuid` holding for TAO and buys
`dest_netuid` with it. Either side may be netuid 0, the fund's TAO cash
slot. Fund shares and staker entitlements do not change; only the fund's
composition moves. Signed by the coldkey that owns `hotkey_ss58` or by
a `BasketTrading` proxy of it (the intended setup for a trader
multisig).

Guardrails enforced on chain: each AMM leg must fill fully within 2% of
the strictest of the subnet's slow moving price, its fast moving price
(a two-hour EMA of spot written each block from the previous block's
close, so a price someone just moved cannot be traded at) and its spot
price (`SlippageTooHigh` otherwise); the TAO through the middle is
taken from the fund's turnover bucket, which holds
`BasketDailyTurnoverCap` of the fund's guarded NAV (each holding at
the lower of its realizable value and its slow-moving-price value) and
refills over 7200 blocks (`BasketTurnoverBudgetExceeded`); the
destination holding may not end above the `BasketLiquidityCap` share
of the destination pool's alpha reserve (`BasketLiquidityCapExceeded`)
nor above the `BasketConcentrationCap` share of the guarded NAV
(`BasketConcentrationCapExceeded`). Trading
must be enabled network-wide and not frozen for the hotkey. Query
`basket_trading_status` for the remaining budget and
`validator_basket` for current holdings before trading. Pass `all`
to sell the fund's whole origin holding (e.g. to clear a small balance).

`min_amount_out` is your own floor on top of the protocol band: the
buy leg must credit at least this much destination alpha (TAO when the
destination is netuid 0), after fees, or the whole trade rolls back with
`BasketMinOutNotMet`. The default `0` sets no floor. `btcli root
swap` derives it from a quote and `--max-slippage`.

| Signer    | Origin                                 | Pallet          | Wraps                                                                                         |
| --------- | -------------------------------------- | --------------- | --------------------------------------------------------------------------------------------- |
| `coldkey` | signed account (pallet role may apply) | SubtensorModule | [`SubtensorModule.swap_basket`](/code/pallets/subtensor/src/macros/dispatches.rs#L2098-L2123) |

## Parameters [#parameters]

| Parameter        | Type              | Required | Description                                                                                                                                                                                                                                              |
| ---------------- | ----------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `hotkey_ss58`    | string            | yes      | Root-registered validator whose basket to rebalance.                                                                                                                                                                                                     |
| `origin_netuid`  | integer           | yes      | Subnet to sell out of (0 = the fund's TAO cash slot).                                                                                                                                                                                                    |
| `dest_netuid`    | integer           | yes      | Subnet to buy into (0 = the fund's TAO cash slot).                                                                                                                                                                                                       |
| `amount`         | number \| `"all"` | yes      | How much of the origin holding to sell, in the origin subnet's alpha (TAO when the origin is netuid 0), or `all` for the whole holding.                                                                                                                  |
| `min_amount_out` | number \| `"all"` | no       | Least amount the buy leg must credit, in the destination subnet's alpha (TAO when the destination is netuid 0), after fees; the trade rolls back with `BasketMinOutNotMet` below it. 0 (default) sets no floor. The 2% protocol band applies regardless. |

Address parameters (`--hotkey`, `--coldkey`, `--dest`, ...) accept a raw ss58
address, an address-book or proxy-book name, or a local wallet/hotkey name.

## CLI [#cli]

Preview with `--dry-run` (shows fee, effects, and policy result without
submitting), then submit:

```bash
btcli tx swap-basket \
  --hotkey <ss58|name> \
  --origin-netuid <int> \
  --dest-netuid <int> \
  --amount <amount|all> --dry-run
btcli tx swap-basket \
  --hotkey <ss58|name> \
  --origin-netuid <int> \
  --dest-netuid <int> \
  --amount <amount|all> -w my_coldkey
```

## Python [#python]

```python
import bittensor as bt
from bittensor.wallet import Wallet

wallet = Wallet(name="my_coldkey", hotkey="my_hotkey")
intent = bt.SwapBasket(hotkey_ss58="5F...", origin_netuid=1, dest_netuid=2, amount=1.0)

sub = bt.Subtensor()
plan = sub.plan(intent, wallet)   # fee, effects, policy — no submission
result = sub.execute(intent, wallet)
if not result.success:
    print(result.error.code, result.error.remediation)
```

(`bt.Subtensor` is also the async client — `async with bt.Subtensor() as client:`
— see [The client](/docs/concepts/client).) Or build the intent by op name, as
an agent would:

```python
result = sub.execute_tool("swap_basket", {...}, wallet)
```

## On-chain implementation [#on-chain-implementation]

`SubtensorModule.swap_basket` — [`pallets/subtensor/src/macros/dispatches.rs#L2105`](/code/pallets/subtensor/src/macros/dispatches.rs#L2098-L2123):

```rust
#[pallet::call_index(150)]
// Declared weight is a cap sized for 256 holdings (one NAV sim-swap sweep, two
// post-trade re-quotes, and two AMM legs) plus the flat pending-deposit flush
// allowance every flushing extrinsic declares; the actual weight is computed in
// `do_swap_basket` from the real holding count and flush work and refunded
// post-dispatch, mirroring `stake_into_basket` / `claim_root`.
#[pallet::weight((Pallet::<T>::swap_basket_declared_weight(), DispatchClass::Normal, Pays::Yes))]
pub fn swap_basket(
    origin: OriginFor<T>,
    hotkey: T::AccountId,
    origin_netuid: NetUid,
    destination_netuid: NetUid,
    amount: AlphaBalance,
    min_amount_out: u64,
) -> DispatchResultWithPostInfo {
    let coldkey: T::AccountId = ensure_signed(origin)?;
    let weight = Self::do_swap_basket(
        coldkey,
        hotkey,
        origin_netuid,
        destination_netuid,
        amount.to_u64(),
        min_amount_out,
    )?;
    Ok((Some(weight), Pays::Yes).into())
}
```

Delegates to [`do_swap_basket`](/code/pallets/subtensor/src/staking/basket_trade.rs#L66).

Every file is browsable under [/code](/code) exactly as built into the runtime, or as plain text under `/code/raw/<path>` (index: [`/code/index.json`](/code/index.json)).
