Stake Locking & Conviction
v411 adds a parallel staking primitive: locks. Ordinary stake is liquid; you can unwind it at any block. A lock commits alpha on a specific (hotkey, subnet) pair for a measurable duration, and that duration accrues conviction. Conviction is the runtime's measure of long-term alignment. Emission and owner-cut policies read it, which is how the runtime can tell capital that's just visiting apart from capital that's staying.
Lock vs stake: what's different
Both stake and lock hold alpha on a (coldkey, hotkey, subnet) tuple. Both contribute to the hotkey's voice in consensus. The difference is in what the chain tracks beside the amount.
| Liquid stake | Locked stake | |
|---|---|---|
| Removable | Any block, via remove_stake | Only after the lock is released (or never, if perpetual) |
| Conviction | None recorded | Accrues per block while locked |
| Movable | Via move_stake (TAO out / alpha in) | Via move_lock (preserves conviction) |
| Signals | Present-tense alignment | Committed alignment over time |
| Storage key | Alpha((coldkey, hotkey, netuid)) | Lock((coldkey, netuid)) |
A coldkey can hold liquid stake and a lock on the same subnet at once; they're separate
accounting buckets. There is a catch though: a coldkey can have at most one lock per subnet. The lock is keyed by (coldkey, netuid), not by hotkey. If you
already have one and call lock_stake again, the destination hotkey
has to match the existing lock's hotkey, and the runtime tops it up rather than opening a second
one.
How conviction accrues
Conviction is a function of locked amount and time held. Two runtime parameters govern its shape:
- MaturityRate sets the per-block rate at which conviction builds. A higher rate means locks mature faster, and short locks carry more weight. A lower rate means conviction is hard-won and tends to be dominated by long-term holders.
- UnlockRate sets the per-block rate at which conviction decays once a lock is released. This is what makes "lock, unlock, re-lock" cycling unattractive: you keep the alpha, but you lose the standing.
The runtime exposes the lock's current state through three storage maps: Lock (per-coldkey lock record), HotkeyLock (aggregated per hotkey), and DecayingHotkeyLock (the accumulating decay state for released locks). Indexers and validators can read any of these
to reconstruct effective conviction at any point in time.
Three kinds of lock
Decaying locks (default)
The default behaviour of lock_stake. The lock can be released by
the coldkey at any time. While held, conviction accrues; once released, the DecayingLock records the conviction so it can decay at UnlockRate rather than vanishing instantly. This is the right choice
for the vast majority of stakers: you signal commitment, you accrue value, but you retain the option
to exit.
Perpetual locks
Pinned via set_perpetual_lock. A perpetual lock can never be released by the coldkey; the alpha is committed for the
lifetime of the runtime. In exchange, the lock's conviction never decays. This is the
strongest commitment signal available, and it's mostly useful for early subnet supporters or
long-term-aligned validators who want to be visibly all-in. The PerpetualLockUpdated event records every pin and unpin attempt for auditability.
Perpetual is perpetual. There is no off-ramp once committed. Treat this as a one-way door and only pin amounts you're prepared to never recover.
Owner locks
Subnet owners have a parallel lock primitive recorded in OwnerLock and DecayingOwnerLock. These are owner-side commitments to their own subnet, separate from general staker locks.
AdminUtils exposes a toggle sudo_set_owner_cut_auto_lock_enabled that, when on, can automatically route owner cut into the owner lock. The effect is to tighten the
alignment loop between owner economics and subnet longevity.
Why this matters for subnet ownership
Lock state is also the substrate for the new SubnetOwnerChanged event. Subnet ownership in Bittensor isn't a static assignment; it can shift when the conditions
encoded in the runtime change. Locks (especially owner locks and large staker locks) are part of
that picture. They give the runtime a way to identify who is most committed to a subnet's long-term
health.
Worked scenario
Scenario: Alice locks 1,000 α on a subnet
Step 1 of 6Setup: liquid alpha
Alice has 1,000 α of liquid stake on hotkey H, subnet 7. She can call remove_stake right now and the alpha would be unwound through the AMM back into TAO. Her alpha contributes to consensus and earns emissions, but she carries no commitment beyond "I have stake here today."
The chain calls
Each call below has its own reference page with worked input parameters, error conditions, events emitted, and storage modified.
lock_stake(hotkey, netuid, amount). Creates a new lock or tops up an existing one. Emits StakeLocked.move_lock(dest_hotkey). Migrates the lock to a different hotkey on the same subnet without resetting conviction. Emits LockMoved.set_perpetual_lock(perpetual). Pins the lock as perpetual (one-way). Emits PerpetualLockUpdated.
Where to go next
- Staking & Delegation. The prerequisites: hotkeys vs coldkeys, liquid stake, delegated stake, take fees.
- What's New in Runtime v411. Stake locking in context with the rest of the v411 changes.
- Emissions. How reward distribution interacts with stake, and increasingly with conviction.