state_getKeysPaged - Bifrost RPC Method
Enumerate storage keys with pagination on Bifrost. Iterate over storage maps like accounts, validators, and assets efficiently with cursor-based pagination.
Returns storage keys matching a prefix with cursor-based pagination on Bifrost. This is the standard way to iterate over storage maps (like System.Account, Staking.Validators, or any pallet storage map) without loading all keys into memory at once.
Why Bifrost? Build on Polkadot's largest liquid staking appchain with 60% DOT LST market share and $125M+ TVL with first LST governance on OpenGov, 60% DOT market share, Hyperbridge ETH integration, and 500K DOT treasury support.
When to Use This Method
state_getKeysPaged is essential for liquid staking developers, DeFi builders, and teams requiring cross-chain yield solutions:
- Storage Map Iteration -- Enumerate all entries in a storage map (accounts, balances, staking data) on Bifrost
- Data Export and Indexing -- Bulk export on-chain state for analytics, indexers, and data pipelines for omnichain liquid staking (vDOT, vKSM, vGLMR, vMOVR, vASTR), cross-chain vToken governance, and DOT/ETH liquidity bridging
- Account Enumeration -- List all accounts that have balances, staking positions, or other on-chain state
- State Migration Tooling -- Iterate storage for runtime upgrades, audits, or cross-chain migration
Code Examples
Common Use Cases
1. Enumerate All Accounts
List all accounts with on-chain state and fetch their balances:
import { ApiPromise, WsProvider } from '@polkadot/api';
async function enumerateAccounts(api, pageSize = 200) {
const prefix = api.query.system.account.keyPrefix();
const allKeys = [];
let startKey;
// Paginate through all account keys
while (true) {
const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
if (keys.length === 0) break;
allKeys.push(...keys);
startKey = keys[keys.length - 1];
}
console.log(`Found ${allKeys.length} accounts`);
// Fetch balances in batches using queryStorageAt
const batchSize = 100;
for (let i = 0; i < allKeys.length; i += batchSize) {
const batch = allKeys.slice(i, i + batchSize);
const results = await api.rpc.state.queryStorageAt(batch);
results[0].changes.forEach(([key, value]) => {
if (value) {
const accountInfo = api.createType('AccountInfo', value);
console.log(` Free: ${accountInfo.data.free.toHuman()}`);
}
});
}
}2. Export Storage Map for Analysis
Export all entries of a specific storage map for offline analysis:
async function exportStorageMap(api, palletName, storageName) {
const prefix = api.query[palletName][storageName].keyPrefix();
const entries = [];
let startKey;
while (true) {
const keys = await api.rpc.state.getKeysPaged(prefix, 500, startKey);
if (keys.length === 0) break;
const values = await api.rpc.state.queryStorageAt(keys);
for (const [key, value] of values[0].changes) {
entries.push({
key: key.toHex(),
value: value ? value.toHex() : null
});
}
startKey = keys[keys.length - 1];
console.log(`Exported ${entries.length} entries...`);
}
return entries;
}
// Export all System.Account entries
const accounts = await exportStorageMap(api, 'system', 'account');3. Count Storage Items by Prefix
Get a count of entries in any storage map without fetching values:
async function countStorageKeys(api, prefix) {
let count = 0;
let startKey;
while (true) {
const keys = await api.rpc.state.getKeysPaged(prefix, 1000, startKey);
if (keys.length === 0) break;
count += keys.length;
startKey = keys[keys.length - 1];
}
return count;
}
// Count total accounts
const accountPrefix = api.query.system.account.keyPrefix();
const totalAccounts = await countStorageKeys(api, accountPrefix);
console.log(`Total accounts on chain: ${totalAccounts}`);Error Handling
Common errors and solutions:
| Error Code | Description | Solution |
|---|---|---|
| -32603 | Internal error | Verify the prefix is a valid hex string; reduce count if the request is too large |
| -32602 | Invalid params | Ensure prefix and startKey are properly hex-encoded with 0x prefix |
| -32005 | Rate limit exceeded | Reduce page size or add delays between pagination requests |
| State pruned | Historical state unavailable | Use an archive node for queries at old block hashes |
| Timeout | Response too slow | Reduce count parameter (try 100 instead of 1000) |
Related Methods
state_getStorage-- Get the value for a specific storage keystate_queryStorageAt-- Batch query multiple storage keys at oncestate_call-- Call a runtime API functionstate_getMetadata-- Get runtime metadata to determine storage key prefixes
state_getKeys
List storage keys under a given prefix in Bifrost's state, useful for enumerating omnipool or staking data.
state_queryStorageAt
Batch query multiple storage keys at a specific block on Bifrost. Efficiently retrieve consistent multi-key state snapshots for indexers, dashboards, and analytics.