smoldot 1.3.1
smoldot: ^1.3.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.3.1
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 clientaddChain(config): Add a new chainremoveChain(chainId): Remove a chaingetAllChainInfo(): Get info for all chainsgetChain(chainId): Get a specific chain by IDhasChain(chainId): Check if a chain existschains: Get list of all active chainschainCount: Get the number of active chainsdispose(): 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 notificationsgetInfo(): Get comprehensive chain informationgetBestBlockNumber(): Get the current best block numbergetBestBlockHash(): Get the current best block hashgetPeerCount(): Get the number of connected peersgetStatus(): Get the chain status (syncing/synced)waitUntilSynced(): Wait for sync completiondispose(): 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_storagechild-trie reads — pass the optionalchildTrieparameter 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 withAddChainConfig.statementStoreset; 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)