state_getStorage - Hydration RPC Method
Read a storage value by key on Hydration. Query account balances, pallet state, and any on-chain data using SCALE-encoded storage keys for single-sided liquidity provision, cross-chain trading (SOL, KSM, tBTC), and HOLLAR decentralized stablecoin.
Returns the SCALE-encoded storage value for a given key on Hydration. Storage keys are constructed by hashing the pallet name and storage item name (and any map keys) using the hashing algorithms specified in the runtime metadata. This is the fundamental method for reading any on-chain state.
Why Hydration? Build on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin with Omnipool with reduced slippage, permissioned listings, 3M DOT DAO allocation, and 200%+ APR farm yields.
When to Use This Method
state_getStorage is essential for DeFi developers, liquidity providers, and DAOs requiring capital-efficient trading:
- Low-Level State Access -- Read the raw SCALE-encoded value stored under a known key on Hydration
- Metadata-Aware Tooling -- Pair runtime metadata with raw storage reads when building custom indexers, explorers, or debugging tools
- Historical State Queries -- Read storage values at a specific block hash to analyze state changes over time
- Pallet Storage Inspection -- Inspect pallet state directly when higher-level client helpers are unavailable or too opinionated
Code Examples
Common Use Cases
1. Raw Storage Watcher
Query and track changes for a specific storage key over time:
import { ApiPromise, WsProvider } from '@polkadot/api';
async function monitorStorageKey(api, storageKey, intervalMs = 12000) {
let previousValue = null;
setInterval(async () => {
const current = await api.rpc.state.getStorage(storageKey);
const raw = current?.toHex() ?? null;
if (previousValue !== null && raw !== previousValue) {
console.log(`Storage value changed: ${previousValue} -> ${raw}`);
}
previousValue = raw;
}, intervalMs);
}2. Metadata-Aware Decode
Use a higher-level library to decode the value after you confirm the raw storage key:
async function decodeAccountStorage(api, address) {
const storageKey = api.query.system.account.key(address);
const raw = await api.rpc.state.getStorage(storageKey);
const decoded = await api.query.system.account(address);
return {
storageKey: storageKey.toHex(),
raw: raw?.toHex() ?? null,
decoded: decoded.toJSON()
};
}3. Historical State Comparison
Compare storage values between two blocks to detect state transitions:
async function compareStateAtBlocks(api, storageQuery, params, blockHashA, blockHashB) {
const [apiAtA, apiAtB] = await Promise.all([
api.at(blockHashA),
api.at(blockHashB)
]);
// Navigate the nested query path (e.g., 'system.account')
const parts = storageQuery.split('.');
let queryA = apiAtA.query;
let queryB = apiAtB.query;
for (const part of parts) {
queryA = queryA[part];
queryB = queryB[part];
}
const [valueA, valueB] = await Promise.all([
queryA(...params),
queryB(...params)
]);
const jsonA = valueA.toJSON();
const jsonB = valueB.toJSON();
console.log(`Block A: ${JSON.stringify(jsonA, null, 2)}`);
console.log(`Block B: ${JSON.stringify(jsonB, null, 2)}`);
return { before: jsonA, after: jsonB };
}
// Example: compare account state between two blocks
// compareStateAtBlocks(api, 'system.account', ['5GrwvaEF...'], blockHashOld, blockHashNew);Storage Key Construction
For developers who need to construct storage keys manually (without a high-level library):
| Storage Type | Key Structure | Example |
|---|---|---|
| Value | xxhash128(Pallet) + xxhash128(Item) | Timestamp.Now |
| Map | xxhash128(Pallet) + xxhash128(Item) + hasher(Key) | System.Account(accountId) |
| Double Map | xxhash128(Pallet) + xxhash128(Item) + hasher1(Key1) + hasher2(Key2) | Staking.ErasStakers(era, validatorId) |
Common hashers used in Substrate:
- Blake2_128Concat -- 16-byte Blake2b hash followed by the raw key (allows key enumeration)
- Twox64Concat -- 8-byte xxhash followed by the raw key (faster, for trusted keys)
- Identity -- Raw key with no hashing (used for already-unique keys)
Error Handling
Common errors and solutions:
| Error Code | Description | Solution |
|---|---|---|
| -32603 | State not available | The requested block's state may be pruned or unavailable on this node -- use an archive node for deep historical queries |
| -32602 | Invalid params | Verify the storage key is a valid hex string with 0x prefix |
| -32005 | Rate limit exceeded | Reduce request frequency or implement client-side rate limiting |
null result | No value at key | This is not an error -- the storage key has no value (default state). Verify the key is correctly constructed |
Important: Historical-state availability depends on the node's pruning configuration. Archive nodes retain full history, while pruned/full nodes may not serve older state.
Related Methods
state_getKeysPaged-- Enumerate storage keys matching a prefix (useful for iterating map entries)state_queryStorageAt-- Query multiple storage keys at a specific block in a single requeststate_getMetadata-- Get runtime metadata including storage definitions, types, and hashing algorithmsstate_call-- Call runtime APIs for computed state that is not directly in storagestate_subscribeStorage-- Subscribe to storage changes in real time via WebSocket
chain_subscribeFinalizedHeads
Subscribe to finalized block headers on Hydration. Real-time WebSocket notifications for blocks that have achieved GRANDPA finality — essential for exchanges, bridges, and applications requiring irreversibility on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin.
state_getMetadata
Get runtime metadata on Hydration. Essential for decoding storage, building extrinsics, and discovering available pallets and calls on Polkadot's leading DEX with $200M+ TVL, Omnipool AMM, and native HOLLAR stablecoin.