Logo
New RPC users get 35% off their first monthView the offer
OnFinality Learn
Network & Protocol Guides14 min read

Bittensor Staking State Over RPC: Reading Delegation, Alpha Stakes, and Pool State

Learn how to read Bittensor staking and delegation state correctly from a Subtensor node, including alpha stakes, pool reserves, and hotkey relationships.

TL;DR

Reading a Bittensor delegator's position correctly requires understanding that stake is not a single balance but a vector: root TAO stake, alpha stake per subnet, the hotkey it is delegated to, and the subnet's pool reserves that determine alpha-to-TAO conversion. This guide explains the Subtensor storage read path, how to resolve storage keys against runtime metadata, and how to compute implied alpha prices from pool reserves. It provides a runnable Python example using the official Subtensor interface, a troubleshooting checklist, and a results table for readers to measure their own endpoint's behavior. All economic parameters are documented values that must be confirmed on-chain, as subnet token economics have changed over runtime upgrades.

Why a Single Stake Number Misleads: The Vector Model of Bittensor Staking

In Bittensor, a delegator's position is not a scalar balance. It is a vector: root stake denominated in TAO, alpha stake held per subnet, the hotkey (validator) that stake is delegated to, and the subnet's pool state (TAO reserve and alpha reserve) that determines how much TAO an alpha position is currently worth. Treating 'my stake' as one number will produce incorrect dashboards, validator tools, and audit scripts.

Delegation is to a hotkey, which is part of a validator's coldkey-hotkey pair. The same coldkey can hold stake across many subnets and many hotkeys. To report a user's real position, you must read each stake entry separately and apply the correct conversion for each subnet's pool.

This read path is distinct from reading metagraph weights and emissions, which track reward flows rather than stake and position state. For a deeper dive into reward flows, see Reading Bittensor metagraph state, weights and emissions.

  • Root stake: TAO delegated to the root network (netuid 0).
  • Alpha stake: subnet-specific tokens held per subnet, not interchangeable with TAO.
  • Hotkey: the validator identity to which stake is delegated; a coldkey can delegate to multiple hotkeys.
  • Pool reserves: each subnet has a TAO reserve and an alpha reserve that determine the alpha-to-TAO conversion rate.

Subtensor Storage Layout: Where Staking State Lives

Staking state lives in Substrate storage, typically in maps keyed by coldkey/hotkey and by subnet. The exact pallet and storage item names are defined by the runtime metadata at the block you are inspecting. You read this state with state_getStorage at a specific block hash, using storage keys derived from the current metadata.

Alternatively, you can use the polkadot.js API or the Python Subtensor interface, which handle key derivation and SCALE decoding for you. These libraries are recommended for most use cases because they abstract away the low-level storage key construction and decoding.

Pool state (TAO reserve and alpha reserve) also lives in storage. The alpha-to-TAO conversion must be computed from both reserves rather than assumed. The conversion formula is documented in the Bittensor staking and pools documentation, but the current parameters and pool mechanics must be confirmed on-chain because subnet token economics have changed over runtime upgrades. The Bittensor official documentation covers staking and pool mechanics, and the Subtensor node and staking runtime reference is the authoritative source for the runtime implementation.

  • Use state_getRuntimeVersion or the metadata at the block under inspection to know which storage layout and pallet names apply.
  • A runtime upgrade can rename or restructure storage items, so hard-coded keys may silently decode to nothing.
  • Always read at a specific block hash, not 'latest', if you need reproducible results.

Resolving Storage Keys Against Runtime Metadata

Before reading any storage, fetch the runtime metadata for the block you are querying. The metadata describes all pallets, storage items, and their key types. You can retrieve it with state_getMetadata or via the polkadot.js API. For a detailed guide on reading runtime metadata, see Reading runtime metadata with state_getMetadata.

Once you have the metadata, derive the storage key for the stake-info map. The key is typically a tuple of the coldkey, hotkey, and netuid, encoded according to the SCALE codec. The Python Subtensor interface provides helper functions to construct these keys and decode the results.

If you are using raw JSON-RPC, you must encode the key manually. This is error-prone and not recommended unless you are building a custom client. The official Substrate JSON-RPC specification and SCALE codec documentation are authoritative primary sources for this encoding. The Subtensor node and staking runtime reference documents the runtime storage items and their key types.

  • Fetch metadata at the target block hash to ensure consistency.
  • Use the Subtensor interface or polkadot.js to avoid manual SCALE encoding.
  • Verify that the storage item exists in the metadata before querying; missing items indicate a runtime change.

Runnable Python Example: Reading Stake, Pool Reserves, and Delegation

The following Python example uses the official Subtensor interface to connect to a Bittensor endpoint, decode metadata, read a coldkey's stake across the root and one named subnet, read the subnet pool reserves, compute the implied alpha price, and read the delegation relationship to identify the hotkey.

This example assumes you have the bittensor Python package installed and access to a Subtensor RPC endpoint. Replace the endpoint URL and coldkey/hotkey values with your own. The output shape is a dictionary with root stake, subnet stake, pool reserves, implied alpha price, and the hotkey associated with the delegation. The Bittensor official documentation and the Subtensor node and staking runtime reference describe the staking and pool interfaces used here.

import bittensor as bt

# Connect to a Subtensor endpoint
subtensor = bt.subtensor(network='finney')

# Define the coldkey and hotkey to inspect
coldkey_ss58 = '5F...'  # replace with actual coldkey
hotkey_ss58 = '5G...'   # replace with actual hotkey
netuid = 1  # example subnet

# Read stake for the coldkey on root (netuid 0) and the specified subnet
stake_root = subtensor.get_stake(coldkey_ss58, hotkey_ss58, netuid=0)
stake_subnet = subtensor.get_stake(coldkey_ss58, hotkey_ss58, netuid=netuid)

# Read pool reserves for the subnet
pool = subtensor.get_subnet_pool(netuid)
tao_reserve = pool.tao_reserve
alpha_reserve = pool.alpha_reserve

# Compute implied alpha price in TAO
implied_alpha_price = tao_reserve / alpha_reserve if alpha_reserve else 0

# Read delegation relationship (hotkey associated with the coldkey's stake)
delegation = subtensor.get_delegation(coldkey_ss58, netuid)

print({
    'root_stake_tao': stake_root,
    'subnet_stake_alpha': stake_subnet,
    'tao_reserve': tao_reserve,
    'alpha_reserve': alpha_reserve,
    'implied_alpha_price_tao': implied_alpha_price,
    'delegated_hotkey': delegation.hotkey if delegation else None
})

Verifying the Alpha-to-TAO Conversion Independently

The implied alpha price computed from pool reserves should match the conversion used by the Subtensor interface when it reports stake in TAO. To verify, compare the output of your script against a second source, such as a block explorer or a different RPC endpoint. Alternatively, re-derive the conversion from the reserves using the documented formula and check that it matches. The Bittensor official documentation documents the pool conversion formula.

If the numbers diverge, check that you are reading reserves and stake at the same block height. Reading stake at 'latest' and reserves at a historical block will produce inconsistent results. Always pin a block hash for all reads in a single verification.

  • Compare your computed alpha price with the value returned by the Subtensor interface's stake-to-TAO conversion.
  • Cross-check with a second RPC endpoint or a block explorer that displays pool reserves.
  • Ensure all reads use the same block hash to avoid temporal inconsistency.

Common Failures When Reading Bittensor Staking State

Several pitfalls can cause your dashboard or audit script to report incorrect positions. The most common is treating alpha as if it were TAO 1:1. Alpha tokens are subnet-specific and their TAO value is determined by the pool reserves. Another frequent error is reading stake at 'latest' and then reporting it against a historical block, which mixes states from different times.

Using storage keys copied from an older runtime can silently decode to nothing, because runtime upgrades may rename or restructure storage items. Summing a coldkey's stake across subnets into one number is also misleading, as each subnet has its own alpha token and conversion rate. Confusing a validator's own stake with delegated stake is another common mistake: validators may have their own stake, and delegators' stake is separate.

Finally, hammering a public endpoint with a per-coldkey loop can trigger rate limits or timeouts. Use batch reads or range reads where possible. For more on timeout errors, see Bittensor RPC timeout errors on Subtensor.

  • Do not assume alpha equals TAO; always apply the pool conversion.
  • Pin a block hash for all reads in a single report.
  • Verify storage keys against the current runtime metadata.
  • Report stake per subnet and per hotkey, not as a single sum.
  • Distinguish validator self-stake from delegated stake.
  • Use batch or range reads to avoid rate limits.

Results Table: Measure Your Endpoint's Behavior

Use the following table to record your own endpoint's observed behavior. Fill in the values by running the Python example or your own script against your endpoint. This will help you understand latency, consistency, and any rate-limiting characteristics.

The table is intentionally blank for you to populate. Do not rely on generic benchmarks; measure your own setup.

  • Endpoint URL: [your endpoint]
  • Block hash used: [hash]
  • Root stake (TAO): [value]
  • Subnet stake (alpha): [value]
  • TAO reserve: [value]
  • Alpha reserve: [value]
  • Implied alpha price (TAO): [value]
  • Delegated hotkey: [hotkey]
  • Response time (ms): [value]
  • Any errors or rate limits: [notes]

Troubleshooting Checklist for Staking State Reads

If your reads fail or return unexpected values, work through this checklist. Start by confirming that your endpoint is synced and that you are querying a block that exists. Then verify that the runtime metadata at that block includes the storage items you are trying to read.

Check that your storage keys are correctly encoded for the current runtime. If you are using a library, ensure it is up to date with the latest runtime. If you are using raw RPC, double-check the SCALE encoding of the key. The Subtensor node and staking runtime reference is the authoritative source for the runtime storage items and their encoding.

Finally, ensure that you are not mixing block heights. All reads for a single report should use the same block hash. If you encounter timeouts, consider using a dedicated endpoint or reducing request frequency. For RPC access options, see Bittensor RPC access and endpoints (RPC Assistant).

  • Is the endpoint synced and the block hash valid?
  • Does the metadata at the block include the expected storage items?
  • Are storage keys correctly encoded for the current runtime?
  • Are all reads pinned to the same block hash?
  • Are you hitting rate limits or timeouts?
  • Is your library version compatible with the runtime?

Limitations and Assumptions: Moving-Target Subnet Economics

Subnet token economics have changed over runtime upgrades, and they may continue to evolve. The formulas and storage layouts described here are based on documented behavior at the time of writing, but you must confirm current parameters on-chain. Do not hard-code economic parameters; always read them from the runtime. The Bittensor official documentation and the Subtensor node and staking runtime reference are the primary sources for current parameters and runtime behavior.

The Python example assumes the Subtensor interface provides helper methods for stake and pool reads. If those methods change, you may need to adapt the code. The example also assumes a single subnet; for multiple subnets, loop over netuids and apply the same logic.

This guide does not cover staking transactions (add_stake, remove_stake) or delegation management. It focuses solely on the read path. For node access and network details, see Bittensor RPC and node access on Finney and Bittensor Finney network.

  • Economic parameters are documented values; confirm on-chain.
  • Runtime upgrades can change storage layouts and pallet names.
  • The read path is separate from transaction construction.
  • Always verify against a second source when possible.

Next Steps: Building Reliable Staking Dashboards and Audits

To build a reliable staking dashboard or audit script, start by using the Subtensor interface or polkadot.js to abstract storage key derivation. Pin a block hash for each report, read stake per subnet and per hotkey, and compute alpha-to-TAO conversions from pool reserves. Cross-check your results with a second endpoint or explorer.

For production use, consider a dedicated RPC endpoint to avoid rate limits and ensure consistent performance. Explore RPC pricing and API service for options. For more guides, visit the OnFinality Learn hub.

Remember that Bittensor's staking state is a vector, not a scalar. Reporting it correctly requires understanding the pool mechanics and the delegation relationships. With the methods in this guide, you can avoid common pitfalls and produce accurate, verifiable results.

  • Use libraries for key derivation and decoding.
  • Pin block hashes for reproducibility.
  • Compute conversions from reserves, not assumptions.
  • Cross-verify with independent sources.
  • Consider dedicated RPC endpoints for production.

Never Worry about Infrastructure Again

OnFinality takes away the heavy lifting of DevOps so you can build smarter and faster.

Get Started