State API
The State API is your gateway to querying blockchain state, including storage data, metadata, and runtime information. This API provides low-level access to the blockchain's state trie and is available through the StateApi class.
Quick Example
void main() async {
final provider = Provider.fromUri(Uri.parse('wss://rpc.polkadot.io'));
final stateApi = StateApi(provider);
// Get current runtime version
final runtimeVersion = await stateApi.getRuntimeVersion();
print(runtimeVersion.toJson());
// Get metadata
final metadata = await stateApi.getMetadata();
print('Metadata version: ${metadata.version}');
}
Expected Output
{
specName: polkadot,
implName: parity-polkadot,
authoringVersion: 0,
specVersion: 1003003,
implVersion: 0,
apis: [...],
transactionVersion: 26,
stateVersion: 1
}
Core Methods
Future types. Most methods accept an optional BlockHash at parameter to query historical state.The StateApi class provides comprehensive methods for querying blockchain state:
Runtime Calls
call
Future<Uint8List> call(String method, Uint8List bytes, {BlockHash? at})
Execute a runtime API call at a specific block's state.
Use case: Call runtime APIs for specialized queries not exposed through standard RPC.
Storage Queries
getPairs
Future<List<KeyValue>> getPairs(StorageKey prefix, {BlockHash? at})
Retrieve all key-value pairs matching a prefix.
Example:
// Get all account balances
final pairs = await stateApi.getPairs(
hex.decode('26aa394eea5630e07c48ae0c9558cef7'), // System.Account prefix
);
getKeysPaged
Future<List<StorageKey>> getKeysPaged({
required StorageKey key,
required int count,
StorageKey? startKey,
BlockHash? at
})
Query storage keys with pagination support.
Example:
// Get first 100 account keys
final keys = await stateApi.getKeysPaged(
key: accountPrefix,
count: 100,
);
// Get next 100 keys
final nextKeys = await stateApi.getKeysPaged(
key: accountPrefix,
count: 100,
startKey: keys.last,
);
getStorage
Future<StorageData?> getStorage(StorageKey key, {BlockHash? at})
Retrieve raw storage data for a specific key.
Returns: Raw SCALE-encoded data or null if the key doesn't exist.
getStorageHash & getStorageSize
Future<BlockHash?> getStorageHash(StorageKey key, {BlockHash? at})
Future<int?> getStorageSize(StorageKey key, {BlockHash? at})
Get the hash or size of storage data without fetching the full value.
Use case: Efficiently check if storage has changed or estimate data size.
Historical Queries
queryStorage
Future<List<StorageChangeSet>> queryStorage(
List<StorageKey> keys,
BlockHash fromBlock,
{BlockHash? toBlock}
)
Query storage changes over a block range.
Example:
// Track balance changes over 100 blocks
final changes = await stateApi.queryStorage(
[balanceStorageKey],
fromBlockHash,
toBlock: toBlockHash,
);
queryStorageAt
Future<List<StorageChangeSet>> queryStorageAt(
List<StorageKey> keys,
{BlockHash? at}
)
Query multiple storage entries at a specific block.
getReadProof
Future<ReadProof> getReadProof(List<StorageKey> keys, {BlockHash? at})
Generate a merkle proof for storage entries.
Use case: Prove storage values to light clients or cross-chain bridges.
Metadata & Runtime
getMetadata
Future<RuntimeMetadata> getMetadata({BlockHash? at})
Fetch the complete runtime metadata.
Contains:
- All pallets and their functions
- Storage layouts
- Types registry
- Runtime APIs
getRuntimeVersion
Future<RuntimeVersion> getRuntimeVersion({BlockHash? at})
Get runtime version information.
Includes:
specVersion: Runtime specification versionspecName: Chain identifier (e.g., "polkadot")implVersion: Implementation versionapis: Available runtime APIs
Real-time Subscriptions
subscribeRuntimeVersion
Future<StreamSubscription<RuntimeVersion>> subscribeRuntimeVersion(
Function(RuntimeVersion) onData
)
Subscribe to runtime version updates.
Example:
final subscription = await stateApi.subscribeRuntimeVersion((version) {
print('Runtime upgraded to version ${version.specVersion}');
});
// Don't forget to cancel when done
await subscription.cancel();
subscribeStorage
Future<StreamSubscription<StorageChangeSet>> subscribeStorage(
List<Uint8List> storageKeys,
Function(StorageChangeSet) onData
)
Monitor storage changes in real-time.
Example:
// Watch balance changes for multiple accounts
final subscription = await stateApi.subscribeStorage(
[aliceBalanceKey, bobBalanceKey],
(changes) {
print('Storage updated at block ${changes.block}');
for (final change in changes.changes) {
print('Key: ${hex.encode(change.$1)}');
print('New value: ${change.$2 != null ? hex.encode(change.$2!) : "deleted"}');
}
},
);
Best Practices
- Use
getKeysPagedfor large datasets to avoid timeouts - Query specific blocks for consistent reads across multiple calls
- Use
getStorageHashto detect changes before fetching full data
- Always cancel subscriptions when done to prevent memory leaks
- Handle reconnection logic for long-running subscriptions
- Use error handlers for subscription failures
queryStorage to avoid overwhelming responsesNext Steps
- Learn about type-safe storage queries
- Explore transaction building
- Understand chain synchronization
Chain API
The Chain API is mainly used to get information needed to build and sign transactions. This API is available through the ChainApi class from the polkadart package.
System API
The System API provides a way to query the system information of the blockchain. It allows you to query the chain name, version, health, and more. This API is available through the SystemApi class from the polkadart package.