# Conviction

Conviction measures how long alpha has been locked to a hotkey. It decides who can take over a subnet after its first year.

_Source: https://beta.taostats.io/docs/concepts/chain-runtime/conviction-v2_

_Last reviewed: 2026-10-05_

## 1. What is conviction?

When you lock alpha to a hotkey on a subnet, the lock builds **conviction**: a score that grows the longer the alpha stays locked. Conviction is summed per hotkey, and the hotkey with the most conviction can take over ownership of a subnet that is more than a year old (see [Subnet king](#7-subnet-king-mechanism)).

Conviction exists to:

- Reward long-term alignment over short-term speculation
- Enable subnet ownership transitions through the **subnet king** mechanism
- Create skin-in-the-game for subnet owners and their backers

## 2. How locking works

You lock alpha with the `lock_stake(hotkey, netuid, amount)` extrinsic:

- **One lock per coldkey per subnet.** Each coldkey has a single lock on each subnet, pointing at one hotkey.
- **Lock to a hotkey.** The locked alpha counts towards that hotkey's conviction. This is usually the subnet owner's hotkey, or the hotkey of someone building conviction to challenge for ownership.
- **Top-ups must match.** Further locks on the same subnet must name the same hotkey, or they fail with `LockHotkeyMismatch`. Use `move_lock` to change hotkey.
- **You lock stake you already hold.** Your total alpha on the subnet (across all hotkeys) must cover the lock, or it fails with `InsufficientStakeForLock`.
- **Locks decay by default.** Locked alpha unlocks gradually unless you call `set_perpetual_lock(netuid, true)`.

> [!NOTE]
> **Conviction locking and staking are separate — you can do both with the same alpha**
>
> Conviction locking (via `lock_stake`) and regular [staking](https://beta.taostats.io/docs/concepts/staking/staking-in-dtao) don't have to point at the same hotkey. You can **lock to the subnet owner's hotkey** to build conviction for the owner, while **staking the same alpha to a different, higher-performing hotkey** (for example, a Taostats validator). The lock limits how much alpha you can unstake on the subnet; it doesn't move your stake.

## 3. Two types of locks

### Decaying locks (default)

A new lock decays unless you opt out:

- `locked_mass` decays exponentially at `UnlockRate`. Half of it unlocks in about **90 days**.
- `conviction` grows while the alpha is still locked, peaks after about **71 days**, then falls as the locked mass runs down.
- As the lock decays, the unlocked part becomes unstakable again. Nothing has to be claimed.

### Perpetual locks

Call `set_perpetual_lock(netuid, true)` to stop the decay:

- `locked_mass` stays constant.
- `conviction` grows towards `locked_mass`: 50% after about **30 days**, 87.5% after 90 days.
- None of the locked alpha can be unstaked. Call `set_perpetual_lock(netuid, false)` to return to decay.

### Locks on the subnet owner hotkey

A lock that points at the subnet owner hotkey gets **instant conviction**: its conviction always equals its `locked_mass`. It can be perpetual or decaying like any other lock.

## 4. The numbers

### System parameters

Time constants are in blocks (7,200 blocks ≈ 1 day).

| Parameter | Live value (blocks) | Time constant | Half-life | Meaning |
|---|---:|---:|---:|---|
| `UnlockRate` | 934,866 | ~130 days | ~90 days | How fast a decaying lock's `locked_mass` runs down |
| `MaturityRate` | 311,622 | ~43 days | ~30 days | How fast conviction catches up with locked mass |

`UnlockRate` is at its code default. `MaturityRate` is set on chain to 311,622; its code default is 934,866.

### Conviction growth (perpetual lock)

| Days elapsed | Conviction (% of `locked_mass`) |
|---:|---:|
| 0 | 0.0% |
| 7 | 14.9% |
| 30 | 50.0% |
| 60 | 75.0% |
| 90 | 87.5% |
| 120 | 93.8% |
| 180 | 98.4% |

### Locked-mass decay (decaying lock)

| Days elapsed | Locked mass remaining |
|---:|---:|
| 0 | 100.0% |
| 30 | 79.4% |
| 60 | 63.0% |
| 90 | 50.0% |
| 120 | 39.7% |
| 180 | 25.0% |
| 365 | 6.0% |

## 5. Worked example

**Scenario:** a coldkey holding 10,000 alpha on a subnet locks all of it to a hotkey.

### Default (decaying) lock

| Days | Locked mass | Conviction | Can unstake |
|---:|---:|---:|---:|
| 0 | 10,000 | 0 | 0 |
| 30 | 7,937 | 4,406 | 2,063 |
| 60 | 6,300 | 5,699 | 3,700 |
| 90 | 5,000 | 5,625 | 5,000 |
| 120 | 3,969 | 5,015 | 6,031 |
| 180 | 2,500 | 3,516 | 7,500 |
| 365 | 601 | 899 | 9,399 |

Unstakable amount = total alpha on the subnet − current `locked_mass`.

### Perpetual lock, then back to decay

With `set_perpetual_lock(netuid, true)`, locked mass stays at 10,000 and conviction reaches 9,998 after a year, with nothing unstakable. If the coldkey then calls `set_perpetual_lock(netuid, false)`:

| Days after switching | Locked mass | Conviction | Can unstake |
|---:|---:|---:|---:|
| 0 | 10,000 | 9,998 | 0 |
| 30 | 7,937 | 9,404 | 2,063 |
| 90 | 5,000 | 6,875 | 5,000 |
| 180 | 2,500 | 3,672 | 7,500 |
| 365 | 601 | 901 | 9,399 |

## 6. Subnet-owner locks

- **Instant conviction.** Any lock on the subnet owner hotkey has `conviction = locked_mass`, with no growth period.
- **Owner-cut auto-lock is off by default.** The subnet owner or root can turn it on with `sudo_set_owner_cut_auto_lock_enabled(netuid, true)` (`OwnerCutAutoLockEnabled`). When it's on, the owner's emission cut is locked each time it is paid out, to the owner coldkey's existing lock hotkey, or to the owner hotkey if there is no lock yet.
- **No initial alpha distribution.** Subnet registration gives the owner no alpha. Owner conviction comes from alpha the owner locks, or from the auto-locked owner cut when that is enabled.
- **Aggregate tracking.** Locks on the owner hotkey are summed in `OwnerLock` (perpetual) and `DecayingOwnerLock` (decaying) for the subnet king calculation.

## 7. Subnet king mechanism

After a subnet has been active for 1 year (365.25 days), ownership can transfer via the **subnet king** mechanism.

### Eligibility requirements

- Subnet must be at least 365.25 days old.
- A **single hotkey's own rolled aggregate conviction** must exceed **18% of eligible alpha**, where eligible alpha = `SubnetAlphaOut − SubnetProtocolAlpha − AlphaBurned`. The subtraction saturates at zero, so a subnet with zero eligible alpha can never transfer ownership. Other keys' locks (including the incumbent owner's) do not count towards a challenger's threshold.
- The hotkey with the highest aggregate conviction is the candidate, and that same hotkey must clear the 18% bar by itself. Conviction is aggregated per hotkey (from all coldkeys locking to that hotkey), not per coldkey.

> [!NOTE]
> **Reading eligible alpha from the API**
>
> You don't have to compute `SubnetAlphaOut − SubnetProtocolAlpha − AlphaBurned` yourself. The Taostats [dTAO pool](https://beta.taostats.io/docs/api-reference) endpoint exposes this exact quantity as the **`alpha_staked`** field (`GET /api/dtao/pool/latest/v1?netuid=<n>`). To check how close a subnet is to a takeover, compare a hotkey's rolled conviction against `0.18 × alpha_staked`.

### How it works

1. **Aggregate calculation:** For each hotkey, the system sums rolled conviction across all locks targeting it — `HotkeyLock + DecayingHotkeyLock`, plus `OwnerLock + DecayingOwnerLock` for the owner hotkey — via a single shared computation (`subnet_king_with_conviction`), so selection and the admission gate can never disagree.
2. **Comparison:** The hotkey with the highest aggregate conviction is the subnet king candidate. Ownership transfers only if **that hotkey's own conviction exceeds 18% of eligible alpha**. The comparison is cross-multiplied in 256-bit integers so high-range takeovers can't saturate.
3. **Transfer:** Ownership transfers, and the lock aggregates swap:
   - Old owner hotkey's owner aggregates → become non-owner aggregates
   - New owner hotkey's non-owner aggregates → become owner aggregates
4. **Instant conviction:** Locks on the new owner hotkey now get instant conviction.

Coalitions work because backers lock directly to the challenger's hotkey, so their conviction lands in that hotkey's aggregate.

## 8. What you can and can't do

### ✅ Allowed

- **Top up an existing lock** (same hotkey).
- **Move a lock to another hotkey on the same subnet** with `move_lock(destination_hotkey, netuid)`. The lock is rolled forward first. Conviction is kept if both hotkeys belong to the same owning coldkey; otherwise it resets to zero.
- **Switch between decaying and perpetual** at any time with `set_perpetual_lock`.
- **Unstake alpha above the locked amount.** On a decaying lock, that headroom grows as the lock decays.
- **Transfer locked stake to another coldkey**, if the recipient has opted in. Coldkeys reject locked alpha by default; the recipient calls `set_reject_locked_alpha(false)` to accept it. The lock moves with the stake, along with a proportional share of conviction (reset to zero if the hotkeys belong to different coldkeys).

### ❌ Not allowed

- **Unstaking locked alpha.** Your alpha on the subnet must stay at or above `locked_mass` (`StakeUnavailable`). Miner registration collateral is held back on top of the lock.
- **Moving a lock across subnets.**
- **Locking to two hotkeys on one subnet** from one coldkey.
- **Coldkey swap onto a coldkey with active locks.** The destination coldkey must have no active locks; the source coldkey's locks transfer to it.

## 9. Technical reference

### Storage

| Storage | Key | Value | Purpose |
|---|---|---|---|
| `Lock` | (coldkey, netuid, hotkey) | `LockState` | Each coldkey's lock on a subnet |
| `LockingColdkeys` | (netuid, hotkey, coldkey) | `()` | Reverse index of coldkeys locking to a hotkey |
| `HotkeyLock` | (netuid, hotkey) | `LockState` | Sum of perpetual non-owner locks on the hotkey |
| `DecayingHotkeyLock` | (netuid, hotkey) | `LockState` | Sum of decaying non-owner locks on the hotkey |
| `OwnerLock` | netuid | `LockState` | Sum of perpetual locks on the subnet owner hotkey |
| `DecayingOwnerLock` | netuid | `LockState` | Sum of decaying locks on the subnet owner hotkey |
| `DecayingLock` | (coldkey, netuid) | `bool` | Present and `false` = perpetual. Missing = decaying (the default) |
| `OwnerCutAutoLockEnabled` | netuid | `bool` | Owner-cut auto-lock; default `false` |
| `UnlockRate` / `MaturityRate` | — | `u64` | Time constants in blocks |

### `LockState` structure

```rust
LockState {
  locked_mass: AlphaBalance, // Locked alpha (decays unless perpetual)
  conviction: U64F64,        // Conviction score
  last_update: u64           // Block of last roll-forward
}
```

### Roll-forward formula

On every read or write, a lock is rolled forward from `last_update` to the current block. With `dt` blocks elapsed, $\tau_x$ = `UnlockRate` and $\tau_z$ = `MaturityRate`:

$$
d_x = e^{-dt/\tau_x} \qquad d_z = e^{-dt/\tau_z}
$$

**Perpetual lock:**

$$
locked\_mass_{new} = locked\_mass_{old} \qquad conviction_{new} = d_z \cdot conviction_{old} + locked\_mass_{old} \cdot (1 - d_z)
$$

**Decaying lock:**

$$
locked\_mass_{new} = locked\_mass_{old} \cdot d_x \qquad conviction_{new} = d_z \cdot conviction_{old} + \gamma \cdot locked\_mass_{old}
$$

$$
\gamma = \tau_x \cdot \dfrac{d_x - d_z}{\tau_x - \tau_z} \quad (\tau_x \ne \tau_z), \qquad \gamma = \dfrac{dt}{\tau_z}\, d_z \quad (\tau_x = \tau_z)
$$

**Owner hotkey lock:** after rolling, `conviction = locked_mass`.

### Extrinsics

- `lock_stake(hotkey, netuid, amount)` — Lock alpha to a hotkey on a subnet. New locks decay by default.
- `move_lock(destination_hotkey, netuid)` — Move your lock to another hotkey on the same subnet.
- `set_perpetual_lock(netuid, enabled)` — `true` stops decay; `false` returns to decay.
- `set_reject_locked_alpha(enabled)` — `false` lets your coldkey receive locked alpha from transfers and coldkey swaps.
- `AdminUtils::sudo_set_owner_cut_auto_lock_enabled(netuid, enabled)` — Subnet owner or root; turns owner-cut auto-locking on or off.

**Previously.** Before spec 447, ownership transferred once the subnet-wide total conviction (all hotkeys combined, including the owner) reached 10% of eligible alpha. It is now an 18% bar on a single hotkey's own conviction.
