state_getKeysPaged - Bridge Hub RPC Method
Enumerate storage keys with pagination on Bridge Hub. 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 Bridge Hub. 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 Bridge Hub? Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.
When to Use This Method
state_getKeysPaged is essential for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:
- Storage Map Iteration -- Enumerate all entries in a storage map (accounts, balances, staking data) on Bridge Hub
- Data Export and Indexing -- Bulk export on-chain state for analytics, indexers, and data pipelines for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- 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