smoldot 1.2.1 copy "smoldot: ^1.2.1" to clipboard
smoldot: ^1.2.1 copied to clipboard

A Dart wrapper for smoldot-light, providing a lightweight Polkadot/Substrate client implementation via Rust FFI bindings

smoldot #

A Dart wrapper for smoldot-light, providing a lightweight Polkadot/Substrate client implementation.

Features #

  • Lightweight: No need for a full node, runs entirely in-process via FFI
  • Multi-chain: Support for multiple chains simultaneously (relay chains + parachains)
  • Async/Await: Idiomatic Dart async APIs for all operations
  • JSON-RPC: Full JSON-RPC support with concurrent requests
  • Subscriptions: Stream-based subscriptions to blockchain events
  • Chain Information: Query chain status, peers, block numbers, and more
  • Type-safe: Comprehensive type definitions and error handling
  • Cross-platform: Works on Android, iOS, macOS, Linux, and Windows
  • Thread-safe: Concurrent requests handled safely with Rust Tokio runtime

Installation #

Add this to your package's pubspec.yaml file:

dependencies:
  smoldot: ^1.2.0

Then download the prebuilt native library for your platform — no Rust toolchain required:

dart run smoldot:setup

This fetches the signed smoldot-light library from the matching GitHub Release, verifies its Ed25519 signature, and installs it into a per-user cache that SmoldotClient loads automatically. Re-run it after upgrading the package (the cache is keyed by version). Flags:

  • --force — re-download even if already installed.
  • --no-verify — skip the signature check (not recommended).

Override the cache root with the SMOLDOT_CACHE_DIR environment variable.

Prerequisites #

dart run smoldot:setup ships prebuilt libraries for desktop platforms (Linux, macOS, and Windows on x64 + arm64). On those platforms nothing else is needed.

For mobile (Android/iOS) — or any platform without a prebuilt, or to develop against the Rust crate directly — build the native library from source instead; see BUILD.md. The loader also picks up a local cargo build from rust/target/{debug,release}/.

Usage #

Basic Example #

import 'package:smoldot/smoldot.dart';

void main() async {
  // Create and initialize the client
  final client = SmoldotClient(
    config: SmoldotConfig(
      maxLogLevel: 3,
      maxChains: 8,
    ),
  );

  await client.initialize();

  // Add a chain
  final chain = await client.addChain(
    AddChainConfig(
      chainSpec: polkadotChainSpec,
    ),
  );

  // Make JSON-RPC calls
  final response = await chain.request('system_chain', []);
  print('Connected to: ${response.result}');

  // Get chain information
  final info = await chain.getInfo();
  print('Chain: ${info.name}');
  print('Status: ${info.status}');
  print('Peers: ${info.peerCount}');
  print('Block: #${info.bestBlockNumber}');

  // Subscribe to new blocks
  final subscription = chain.subscribe('chain_subscribeNewHeads', []);
  await for (final block in subscription.take(5)) {
    final header = block.result as Map<String, dynamic>;
    print('New block: ${header['number']}');
  }

  // Clean up
  await client.dispose();
}

Multi-Chain Support #

// Add Polkadot relay chain
final polkadot = await client.addChain(
  AddChainConfig(chainSpec: polkadotSpec),
);

// Add Statemint parachain
final statemint = await client.addChain(
  AddChainConfig(
    chainSpec: statemintSpec,
    potentialRelayChains: [polkadot.chainId],
  ),
);

// Interact with both chains
final polkadotName = await polkadot.request('system_chain', []);
final statemintName = await statemint.request('system_chain', []);

Chain Information #

// Get comprehensive chain info
final info = await chain.getInfo();
print('Name: ${info.name}');
print('Status: ${info.status}');
print('Peers: ${info.peerCount}');
print('Block: #${info.bestBlockNumber}');
print('Hash: ${info.bestBlockHash}');

// Get specific information
final blockNumber = await chain.getBestBlockNumber();
final blockHash = await chain.getBestBlockHash();
final peerCount = await chain.getPeerCount();
final status = await chain.getStatus();

// Get info for all chains
final allChains = await client.getAllChainInfo();
for (final chainInfo in allChains) {
  print('${chainInfo.name}: ${chainInfo.status}');
}

Concurrent Requests #

// Make multiple concurrent JSON-RPC requests
final futures = [
  chain.request('system_chain', []),
  chain.request('system_version', []),
  chain.request('system_name', []),
  chain.request('system_properties', []),
];

final responses = await Future.wait(futures);
print('Chain: ${responses[0].result}');
print('Version: ${responses[1].result}');

Error Handling #

try {
  final response = await chain.request('system_chain', []);
  print(response.result);
} on JsonRpcException catch (e) {
  print('RPC error: ${e.error?.message}');
} on ChainException catch (e) {
  print('Chain ${e.chainId} error: ${e.message}');
} on SmoldotException catch (e) {
  print('Smoldot error: ${e.message}');
}

API Reference #

SmoldotClient #

The main client class for managing smoldot-light.

  • initialize(): Initialize the client
  • addChain(config): Add a new chain
  • removeChain(chainId): Remove a chain
  • getAllChainInfo(): Get info for all chains
  • getChain(chainId): Get a specific chain by ID
  • hasChain(chainId): Check if a chain exists
  • chains: Get list of all active chains
  • chainCount: Get the number of active chains
  • dispose(): Clean up resources

Chain #

Represents a blockchain chain.

  • request(method, params): Send JSON-RPC request (concurrent-safe)
  • subscribe(method, params): Subscribe to notifications (returns Stream)
  • unsubscribe(subscriptionId): Unsubscribe from notifications
  • getInfo(): Get comprehensive chain information
  • getBestBlockNumber(): Get the current best block number
  • getBestBlockHash(): Get the current best block hash
  • getPeerCount(): Get the number of connected peers
  • getStatus(): Get the chain status (syncing/synced)
  • waitUntilSynced(): Wait for sync completion
  • dispose(): Clean up chain resources

Configuration #

SmoldotConfig

SmoldotConfig(
  maxLogLevel: 3,        // 0=off, 1=error, 2=warn, 3=info, 4=debug, 5=trace
  maxChains: 8,          // Maximum number of chains
  cpuRateLimit: 1.0,     // CPU rate limit (0.0 to 1.0)
  wasmCpuMetering: false,// Enable WASM CPU metering
)

AddChainConfig

AddChainConfig(
  chainSpec: '...',                    // Chain specification JSON
  databaseContent: '...',              // Optional: Restore from database
  potentialRelayChains: ['...'],      // Optional: Relay chain IDs
  disableJsonRpc: false,               // Optional: Disable JSON-RPC
  statementStore: StatementStoreConfig(// Optional: enable the statement-store protocol
    maxSeenStatements: 65536,          //   per-subscription dedup cache (default 65536)
    falsePositiveRate: 0.01,           //   topic-affinity bloom FPR, in (0,1) (default 0.01)
    affinityUpdateIntervalMs: 1000,    //   affinity update debounce in ms (default 1000)
  ),
)

JSON-RPC API #

Chain is a transport for arbitrary JSON-RPC. Use chain.request(method, params) for calls and chain.subscribe(method, params) for subscriptions; both the legacy Substrate API and smoldot's newer JSON-RPC v2 (chainHead/transaction) API are available. Common method names are exposed as constants on SubstrateRpcMethods.

Capabilities added by smoldot-light 1.x (all reachable through the generic request/subscribe pump, no extra setup beyond what's noted):

  • chainHead_v1_* / transaction_v1_* / transactionWatch_v1_* — the recommended JSON-RPC v2 API for following the chain head, reading storage, and broadcasting transactions.
  • chainHead_v1_storage child-trie reads — pass the optional childTrie parameter to read the default child trie directly (e.g. contract storage) without a runtime call.
  • bitswap_v1_get — fetch an IPFS/Bitswap block by CID over the chain's p2p network.
  • Statement store (statement_submit, statement_subscribeStatement, statement_unsubscribeStatement) — only functional when the chain was added with AddChainConfig.statementStore set; otherwise these calls return an error.
// Enable the statement store, then submit/subscribe to statements.
final chain = await client.addChain(
  AddChainConfig(chainSpec: spec, statementStore: const StatementStoreConfig()),
);
await chain.request(SubstrateRpcMethods.statementSubmit, ['0x...']);

Platform Support #

Platform Support Library Format
Android .so
iOS .dylib
macOS .dylib
Linux .so
Windows .dll

Building the Native Library #

The native smoldot-light library must be built from Rust:

# Clone smoldot
git clone https://github.com/smol-dot/smoldot.git
cd smoldot

# Build the FFI library (example, adjust as needed)
cargo build --release --package smoldot-light-ffi

# Copy to package directory
cp target/release/libsmoldot_light.* /path/to/smoldot_light/native/

Development Status #

This package is fully functional with comprehensive FFI bridge implementation.

Implemented Features:

  • ✅ Client initialization and disposal
  • ✅ Chain creation with real chain specs
  • ✅ Multi-chain support (relay chains + parachains)
  • ✅ Cross-thread FFI callbacks (Rust Tokio → Dart)
  • ✅ JSON-RPC requests with concurrent request support
  • ✅ Subscriptions to chain events (stream-based)
  • ✅ Chain information queries
  • ✅ Enhanced chain management

Known Limitations:

  • ⚠️ Database persistence: Not exposed by smoldot-light API
  • ⚠️ Logging: Handled by platform (Android logcat, iOS oslog)
0
likes
160
points
318
downloads

Documentation

API reference

Publisher

verified publishersnowpine.io

Weekly Downloads

A Dart wrapper for smoldot-light, providing a lightweight Polkadot/Substrate client implementation via Rust FFI bindings

Homepage
Repository (GitHub)
View/report issues
Contributing

License

Apache-2.0 (license)

Dependencies

convert, cryptography, ffi, meta, path

More

Packages that depend on smoldot