# Gamma (/docs/guides/gamma)

Gamma is a credit a subnet can accept as payment for its service, valued in US
dollars. Once gamma is enabled network-wide and on a subnet, a coldkey mints
that subnet's gamma by burning its alpha, bought with TAO or taken from stake.
One gamma is minted for each dollar the burned alpha is worth.

Gamma is held in **deposits**. Each deposit belongs to a coldkey and is keyed by
a hotkey, which signs the customer's requests to the service, so the hotkey
works as an API key. The deposit's **spender** spends it as it serves those
requests.

Before opening a deposit, associate the API-key hotkey with the minting coldkey
using `try_associate_hotkey` (or register the hotkey). Only that coldkey can open
a deposit at the hotkey, including by moving gamma into a new deposit.

Gamma cannot be transferred to another coldkey or converted back into alpha or
TAO. Amounts are in gamma, with 10^9 units per gamma.

| Role                             | Can                                                                                                                                                                                                                           |
| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Coldkey                          | mint into its deposits, move gamma between them, set each deposit's spender and daily spend cap, close empty deposits                                                                                                         |
| Hotkey                           | nothing on chain; it signs requests to the service                                                                                                                                                                            |
| Validator or subnet owner hotkey | publish a [service](/docs/guides/services) and its spender on its subnet, signed by its coldkey                                                                                                                               |
| Spender                          | spend the deposits that name it, directly or through a `GammaSpend` proxy                                                                                                                                                     |
| Subnet owner                     | enable gamma on its subnet with [`gamma_enabled`](/docs/hyperparameters/gamma-enabled); spender of the deposits a mint opens while it owns the subnet, unless its hotkey's service names another or a lease owns it           |
| Lease beneficiary                | enable gamma through its `SubnetLeaseBeneficiary` proxy; spender of the deposits a mint opens while its lease owns the subnet, unless the subnet owner hotkey's service, which it publishes through that proxy, names another |
| Root                             | enable gamma network-wide and on any subnet but root, and set the TAO/USD price oracle                                                                                                                                        |
| Oracle                           | feed the TAO/USD price                                                                                                                                                                                                        |

## Minting [#minting]

Minting needs gamma enabled on the subnet and a fresh
[TAO/USD price](#the-taousd-price). Mint with TAO into a deposit at a fresh
hotkey, for a service the subnet lists with [`services`](/docs/query/services):

```bash
btcli wallet new-hotkey -H API_KEY
btcli wallet associate-hotkey --hotkey API_KEY
btcli query services --netuid 51
btcli gamma mint --netuid 51 --hotkey API_KEY --amount-tao 10 --service-hotkey SERVICE_HOTKEY
```

```python
quote = await client.gamma.quote_mint_gamma(netuid=51, amount_tao=10)
await client.execute(bt.AssociateHotkey(hotkey_ss58=api_key), wallet)
await client.execute(
    bt.MintGamma(netuid=51, hotkey_ss58=api_key, amount_tao=10, service_hotkey_ss58=service), wallet
)
```

`--service-hotkey` names the spender the service publishes, so the service can
spend the deposit.

[`mint-gamma`](/docs/tx/mint-gamma) buys alpha with the TAO and burns it, with
the same pool and flow accounting as [`stake-burn`](/docs/tx/stake-burn), and
creates no stake position.
[`mint-gamma-with-stake`](/docs/tx/mint-gamma-with-stake) burns stake you
already hold instead:

```bash
btcli gamma mint-with-stake --netuid 51 --hotkey API_KEY --origin-hotkey VALIDATOR --amount-alpha 100 --service-hotkey SERVICE_HOTKEY
```

`--amount-alpha all` burns the whole stake.

The burned alpha is valued at the lower of two prices:

```
TAO value = alpha × min(gamma price, spot price)
gamma     = TAO value × TAO/USD price
```

Every subnet but root keeps a gamma price, whether or not gamma is enabled.
Registration sets it to the median subnet alpha price, which the new pool is
created at; a subnet registered before gamma starts at its spot price. Each
block it falls to the spot price at once and rises toward it by ln 2 / 600 of
the gap, so the gap halves every 600 blocks, about 2 hours. A rise is at most ln
2 / 600 of the gamma price itself, so however far spot jumps, the gamma price at
most doubles every 600 blocks. The spot price is read before the mint trades.
Alpha is valued at these prices, not at what selling it would return, so a burn
that is large for the pool is worth more than its sale.

The SDK quotes the mint first and fails it if the minted gamma would fall more
than `rate_tolerance` (5% by default) below the quote. The with-stake quote
assumes the whole amount is burned; the SDK quotes no more than the stake you
hold. Once the mint runs, `result.data["minted"]` holds the deposit's
`hotkey_ss58`, `spender_ss58` and `daily_spend_cap_gamma`, and the
`alpha_burned`, `tao_value` and `gamma` minted, as exact decimal strings.

A mint fails with [`GammaDisabled`](/docs/errors/chain/GammaDisabled) while
gamma is off network-wide or on the subnet. No other call checks these
switches, so turning one off stops new mints only, and existing deposits can
still be spent, moved and closed. A mint also fails with
[`AmountTooLow`](/docs/errors/chain/AmountTooLow) below 0.1 gamma, with
[`SubtokenDisabled`](/docs/errors/chain/SubtokenDisabled) on a subnet whose
subtoken is not enabled, and with
[`SlippageTooHigh`](/docs/errors/chain/SlippageTooHigh) below its minimum. A TAO
mint above the add-stake swap input limit fails with
[`InsufficientLiquidity`](/docs/errors/chain/InsufficientLiquidity). Minting or
moving into a hotkey whose deposit belongs to another coldkey fails with
[`NonAssociatedColdKey`](/docs/errors/chain/NonAssociatedColdKey).

Through a proxy, minting and moving need an `Any` or `NonCritical` proxy.
Setting a deposit's spender or daily spend cap and closing it also take a
`NonTransfer` proxy.

## Deposits and API keys [#deposits-and-api-keys]

Any account can be a deposit's hotkey, and it needs no registration or funds. A
hotkey holds at most one deposit per subnet, owned by the coldkey that opened
it, so create a fresh hotkey for each deposit. Requests signed with it are paid
from the deposit, so never use a staking hotkey or a coldkey. A coldkey holds at
most 64 deposits per subnet.

```bash
btcli gamma list
btcli gamma show --netuid 51 --hotkey API_KEY
```

To give someone gamma, open a deposit with their hotkey. The deposit stays
yours: move the gamma back at any time.

```bash
btcli gamma move --netuid 51 --origin-hotkey THEIR_KEY --destination-hotkey API_KEY --amount-gamma all
```

[`move-gamma`](/docs/tx/move-gamma) to a hotkey with no deposit opens one with
the origin's spender and daily spend cap. A move that empties the origin closes
it. A deposit spent to zero stays open with its terms, so it can be refilled,
until it is closed with [`close-gamma-deposit`](/docs/tx/close-gamma-deposit):

```bash
btcli gamma close --netuid 51 --hotkey API_KEY
```

## Spenders and daily spend caps [#spenders-and-daily-spend-caps]

The spender stays the same if the subnet changes hands. Name another account
with [`set-gamma-deposit-spender`](/docs/tx/set-gamma-deposit-spender) and
`--spender SPENDER`, a service's spender with `--service-hotkey SERVICE_HOTKEY`,
or `--default-spender` for the spender of the subnet owner's service, otherwise
the subnet's current owner, or its lease's beneficiary:

```bash
btcli gamma set-spender --netuid 51 --hotkey API_KEY --service-hotkey SERVICE_HOTKEY
```

A daily spend cap, set with
[`set-gamma-deposit-daily-spend-cap`](/docs/tx/set-gamma-deposit-daily-spend-cap),
bounds what the spender can take. What it allows refills linearly at the cap
per 7200 blocks, up to the cap. A cap set where there was none starts full, and
a changed cap keeps what it allows now, up to the new cap, so ending a pause
refills from nothing. A cap of zero pauses the deposit, and `--remove-cap`
removes the cap.

While a deposit has a cap, a spender takes at most the highest cap plus its
refill over any period. A deposit opened with a cap starts full.

```bash
btcli gamma set-cap --netuid 51 --hotkey API_KEY --daily-spend-cap-gamma 20
```

A mint can name a new deposit's terms with `--spender SPENDER` or
`--service-hotkey SERVICE_HOTKEY`, and `--daily-spend-cap-gamma 20`, so the
deposit never opens on others. A deposit that already has other terms fails the
mint with
[`GammaDepositSpenderMismatch`](/docs/errors/chain/GammaDepositSpenderMismatch)
or
[`GammaDepositDailySpendCapMismatch`](/docs/errors/chain/GammaDepositDailySpendCapMismatch).

## Spending [#spending]

The spender spends many deposits in one [`spend-gamma`](/docs/tx/spend-gamma)
call, up to 512 entries of a hotkey, an amount and a reference:

```bash
btcli gamma spend --netuid 51 --spend API_KEY=0.25:0xREFERENCE --spend OTHER_KEY=1.5
```

```python
result = await client.execute(
    bt.SpendGamma(
        netuid=51,
        spends=[{"hotkey_ss58": api_key, "amount_gamma": 0.25, "reference": reference}],
    ),
    spender,
)
```

Each entry spends its whole amount, and the spent gamma is destroyed. Entries
whose hotkey has no deposit, whose deposit names another spender, or whose
amount is zero or above the deposit's balance or what its daily spend cap
allows now, are skipped, and cost less as they write nothing.
`spendable_gamma` in [`gamma-deposit`](/docs/query/gamma-deposit) is what an
entry can spend now. Once the spend runs, `result.data["spent"]` lists each
entry that spent, with its `hotkey_ss58`, `amount_gamma` as an exact decimal
string, and `reference`, and `result.data["skipped"]` lists each entry that was
skipped, with the chain error that skipped it as `reason`, such as
`InsufficientGammaBalance`.

A reference is any 32 bytes, all zero when omitted. The chain repeats it in the
entry's `GammaSpent` or `GammaSpendSkipped` event and reads it nowhere else, so
an entry sent twice spends twice. By convention it is the service's own 32-byte id for the request
the entry pays for, returned with its response, so the customer can match each
spend to its own request.

Since the coldkey can change the spender or pause the deposit at any time, a
service spends ahead: it spends what it is about to serve, and serves what was
spent. The spender can hand this right to a `GammaSpend` proxy, which can
make no other call and spends with `--proxy-for` (`proxy_for=` in Python):

```bash
btcli proxy add --delegate BILLING_KEY --proxy-type GammaSpend -w SERVICE
btcli gamma spend --netuid 51 --spend API_KEY=0.25 -w BILLING_KEY --proxy-for SERVICE
```

## The TAO/USD price [#the-taousd-price]

An oracle set by root feeds the TAO/USD price in gamma units, 10^9 per US
dollar, so 400 dollars per TAO is fed as 400000000000. The accepted price falls
to a lower feed at once and rises toward a higher one by at most 0.0066% (66
ppm) per block, about 2% per hour. A mint values TAO at the accepted price and
needs a feed at most 300 blocks (one hour) old; otherwise it fails with
[`TaoUsdPriceUnavailable`](/docs/errors/chain/TaoUsdPriceUnavailable). Setting
or removing the oracle clears the price, so no gamma can be minted until an
oracle feeds. Read it with [`tao-usd-price`](/docs/query/tao-usd-price):

```bash
btcli query tao-usd-price
```

## Limitations [#limitations]

* Gamma confers no claim on any party and cannot be redeemed. A subnet decides
  whether, and at what prices, it accepts its gamma.
* Dissolving or pruning a subnet destroys all of its gamma, and holders receive
  nothing.
* Spent gamma pays its spender nothing: the burned alpha's value accrues to the
  subnet's alpha holders.
* While a coldkey swap is announced, the coldkey's gamma calls are refused, but
  its spenders keep spending. A spender whose own swap is announced cannot
  spend.
* A coldkey swap adds the coldkey's deposits to the new coldkey's. It fails if
  the new coldkey would hold more than 64 on a subnet, and is refused when the
  two coldkeys hold more than 128 together.
* A spender's coldkey swap does not change any deposit's or service's spender.
  After a subnet owner or lease beneficiary swaps its coldkey, the deposits and
  the owner's service that name the old coldkey keep it. The owner republishes
  its service, and a deposit's coldkey re-points it with
  `btcli gamma set-spender --default-spender`. An owner whose service names a
  spender that never needs a swap, such as a multisig, needs neither.
* The oracle is trusted: its accepted price can rise at most about 61% per day,
  until root replaces or removes it.
