Polkadart Logo
Substrate Metadata

Overview

Comprehensive guide to the substrate_metadata package - metadata types, codecs, and utilities

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:

  1. Metadata Layer: Raw metadata types (V14/V15)
  2. Registry Layer: Type resolution and codec management
  3. Derived Codecs Layer: Specialized codecs for events, extrinsics, etc.
  4. Facade Layer: High-level ChainInfo API
  5. Utils Layer: Hashers, merkleization, and utilities

This design provides both low-level control and high-level convenience.

Next Steps