Overview
What is substrate_metadata?
The substrate_metadata package is a fundamental component of the Polkadart ecosystem that provides everything needed to work with Substrate runtime metadata. It enables you to decode and encode blockchain data including extrinsics, events, storage entries, and constants.
Think of it as the bridge between the raw blockchain data and your Dart application - it knows how to interpret the metadata from any Substrate-based chain and provides the tools to encode/decode all types of blockchain data.
Key Features
Metadata Support
Full support for both V14 and V15 metadata formats with automatic version detection
Type Registry
Intelligent type resolution with caching for optimal performance
Derived Codecs
Pre-built codecs for events, extrinsics, calls, and constants
Storage Hashers
Complete implementation of all Substrate storage hashing algorithms
Metadata Merkleization
RFC-78 compliant metadata hash generation for secure offline signing
Chain Info Facade
Convenient high-level API for common metadata operations
Core Components
The package is organized into several key modules:
Metadata Types
The metadata system provides complete type definitions for both V14 and V15 runtime metadata:
- RuntimeMetadataPrefixed: Top-level metadata container with magic number and version
- PalletMetadata: Pallet-specific metadata including calls, events, storage, and constants
- PortableType: Type registry entries with full type definitions
- ExtrinsicMetadata: Metadata for transaction structure and signed extensions
Type Registry
The MetadataTypeRegistry is the heart of the package:
// Create registry from metadata bytes
final prefixed = RuntimeMetadataPrefixed.codec.decode(input);
final registry = MetadataTypeRegistry(prefixed);
// Get codec for any type ID
final codec = registry.codecFor(42);
final value = codec.decode(input);
// Access pallets and their components
final pallet = registry.palletByName('System');
final constantValue = registry.getConstantValue('System', 'BlockHashCount');
Key features:
- Automatic V14/V15 metadata handling
- Intelligent codec caching for performance
- Recursive type support via proxy pattern
- O(1) pallet lookups
Derived Codecs
Pre-built specialized codecs for common blockchain data:
- EventsRecordCodec: Decode event records from storage
- ExtrinsicsCodec: Decode extrinsics from blocks
- RuntimeCallCodec: Encode/decode runtime calls
- ConstantsCodec: Access pallet constants
ChainInfo Facade
The ChainInfo class provides a convenient one-stop interface:
// Create from metadata bytes
final chainInfo = ChainInfo.fromMetadata(metadataBytes);
// Decode events
final events = chainInfo.decodeEvents(eventBytes);
// Decode extrinsics
final extrinsics = chainInfo.decodeExtrinsics(extrinsicBytes);
// Access constants
final value = chainInfo.getConstant('System', 'BlockHashCount');
// Access registry for advanced operations
final customCodec = chainInfo.registry.codecFor(typeId);
Storage Hashers
Complete implementation of all Substrate storage hashing algorithms:
- Blake2_128
- Blake2_256
- Blake2_128Concat
- Twox128
- Twox256
- Twox64Concat
- Identity
These are used for generating storage keys for querying chain state.
Metadata Merkleization
RFC-78 compliant implementation for generating metadata hashes:
final merkleizer = MetadataMerkleizer.fromMetadata(
metadata,
decimals: 10,
tokenSymbol: 'DOT',
);
// Get the metadata hash
final metadataHash = hex.encode(merkleizer.digest());
// Generate proof for extrinsic
final proof = merkleizer.getProofForExtrinsic(extrinsic, additionalSigned);
This enables secure offline transaction signing by proving the metadata used.
Installation
Add substrate_metadata to your pubspec.yaml:
dependencies:
substrate_metadata: ^2.0.0
Quick Start
Here's a complete example of using substrate_metadata:
import 'dart:typed_data';
import 'package:substrate_metadata/substrate_metadata.dart';
import 'package:polkadart_scale_codec/polkadart_scale_codec.dart';
void main() async {
// 1. Decode metadata from bytes
final metadataBytes = Uint8List.fromList([...]); // Your metadata bytes
final chainInfo = ChainInfo.fromMetadata(metadataBytes);
print('Metadata version: ${chainInfo.version}');
print('Number of pallets: ${chainInfo.pallets.length}');
// 2. Access pallet information
final systemPallet = chainInfo.pallet('System');
print('System pallet index: ${systemPallet?.index}');
// 3. Get a constant value
final blockHashCount = chainInfo.getConstant('System', 'BlockHashCount');
print('BlockHashCount: $blockHashCount');
// 4. Decode events
final eventBytes = Uint8List.fromList([...]); // Event data from storage
final events = chainInfo.decodeEvents(eventBytes);
for (final eventRecord in events) {
print('Event: ${eventRecord.event.pallet}.${eventRecord.event.name}');
print('Phase: ${eventRecord.phase}');
}
// 5. Decode extrinsics from a block
final extrinsicBytes = Uint8List.fromList([...]); // Extrinsic data
final extrinsics = chainInfo.decodeExtrinsics(extrinsicBytes);
for (final extrinsic in extrinsics) {
print('Extrinsic version: ${extrinsic.version}');
print('Signed: ${extrinsic.isSigned}');
print('Call: ${extrinsic.call.pallet}.${extrinsic.call.name}');
}
// 6. Access the registry for advanced operations
final accountIdType = chainInfo.registry.accountIdType;
final accountIdCodec = chainInfo.registry.codecFor(accountIdType);
// Use the codec to decode account IDs
final accountId = accountIdCodec.decode(Input.fromBytes(accountBytes));
}
Use Cases
The substrate_metadata package is essential for:
- Building blockchain explorers
- Creating wallet applications
- Developing dApps that need to decode chain data
- Implementing custom RPC clients
- Offline transaction signing
- Chain indexers and monitoring tools
Architecture
The package follows a layered architecture:
- Metadata Layer: Raw metadata types (V14/V15)
- Registry Layer: Type resolution and codec management
- Derived Codecs Layer: Specialized codecs for events, extrinsics, etc.
- Facade Layer: High-level ChainInfo API
- Utils Layer: Hashers, merkleization, and utilities
This design provides both low-level control and high-level convenience.