Hi everyone!
Iβm Mehrdad (LinkedIn / GitHub),
a software engineer, and Iβm proud to introduce Substrate4j:
a full-featured Java toolset for interacting with Substrate-based chains.
I started this project two years ago and have put a great amount of time and effort into it. One of my main motivations
was that I really liked the Polkadot community, especially the tech behind it, and I wanted to be part of it.
Java is one of the most popular programming languages, but for a long time the community lacked complete Java tooling
for interacting with Polkadot. The few partial projects that existed were either abandoned and unmaintained, or incomplete.
Substrate4j is now in its final stages, just some final touches, refinement, and API stabilization left.
Iβd really appreciate feedback from the community at this point.
What is Substrate4j?
Substrate4j is a Java client to interact with Substrate-based chains like Polkadot, Kusama and Asset Hub, similar to
Polkadot-Api and Polkadot.js
Features
- Static, type-safe runtime β the full runtime for each supported chain is generated from runtime metadata, giving access to pallets, constants, storage, extrinsics, events, and runtime APIs.
- Developer-friendly, ergonomic APIs β since the runtime is generated straight from metadata, almost every bit of it is baked into the generated Java code. That means full IDE autocomplete and inline docs for the entire runtime β pallets, calls, storage, events β right as you type.
- Pure Java cryptography β SR25519, Ed25519, and ECDSA, all implemented natively in Java, no JNI, no native bindings. To support SR25519, the Merlin transcript protocol and Schnorrkel were ported from Rust to Java with full test coverage, and are published as standalone Maven packages for anyone who wants to use them independently. Also includes full support for Substrate-style secret strings and key derivation.
- A complete SCALE module β the SCALE module is well-written and thoroughly tested, with an innovative architecture that gives great flexibility. It defines a simple formal grammar called STN (SCALE Type Notation) to represent SCALE type metadata, and STN strings can be embedded directly into Java types using annotations. For more complex cases, custom encoding/decoding logic can be plugged in. The SCALE module is also published separately on Maven, so anyone can use it on its own.
- Built on the new Polkadot JSON-RPC spec.
- Resilient RPC abstraction layer β middleware built with network unpredictability and websocket disconnections in mind.
- Non-blocking, reactive API β built on Project Reactor for high throughput.
- Clients published to Maven Central β no extra setup for newcomers, just add the dependency and start interacting with the chain.
Examples
add Maven/Gradle dependency for your client:
<dependency>
<groupId>org.substrate4j</groupId>
<artifactId>polkadot</artifactId>
<version>r2003000.0-c0.0.2</version>
</dependency>
implementation 'org.substrate4j:polkadot:r2003000.0-c0.0.2'
connect, subscribe to blocks, and query an account balance:
// Create an API instance to interact with the network
PolkadotApi api = PolkadotApi.create("wss://rpc.example.io");
// The api exposes two sets of interfaces:
// - chain(): generic, non-runtime-aware primitives
// - runtime(): the fully typed runtime API for this chain
// Subscribe to finalized blocks
api.chain().finalizedBlocks().subscribe(block -> {
System.out.printf("number: %d, hash: %s, parentHash: %s\n",
block.number(), block.hash(), block.parentHash());
});
// Read the balance of an account
AccountId32 accountId32 = AccountId32.fromSs58("138PvUNqAtUWL9tiaJkt9cBDttXFf2Uih2rkQEUhU5zzHFwH");
StorageValue accountInfo =
api.runtime().system().storage.account(accountId32).query().block();
System.out.printf("balance: %s\n", accountInfo.value().data().free());
Submit and extrinsic:
// Create a key pair from a mnemonic phrase:
SR25519Pair pair = SR25519Pair.factory()
.fromPhrase("whale supreme diet sheriff income silk pulse mention dizzy parent rookie veteran", null)
.f0();
// Or use a Substrate-style secret string (ED25519Pair and ECDSAPair are also supported):
SR25519Pair pair = SR25519Pair.factory().fromString("//Alice", null);
// Construct, sign, and submit the extrinsic:
SentExtrinsic<RuntimeEvent> sent = api.runtime().system().call
.remarkWithEvent("I am using Substrate4j to send this extrinsic!".getBytes())
.signAndSend(pair);
// sent can be used to listen to extrinsic lifecycle events and also events it emmit in runtime
// Subscribe to lifecycle events (Validated, BestChainBlockIncluded, Finalized and so on):
sent.lifecycleEvents().subscribe(e -> System.out.printf("Lifecycle: %s", e));
// And subscribe to the runtime events emitted by the extrinsic:
sent.runtimeEvents().subscribe(e -> System.out.printf("Runtime event: %s", e));
Project Goals
- Be feature-rich, exposing a nearly complete spectrum of chain interaction
- Provide a full runtime representation, with generated static types for each chainβs runtime
- Be a production-grade tool, reliable enough for real applications
- Keep clients up to date with the latest runtime updates for each supported chain
I believe most of these goals are already achieved at this point β thereβs still room for refinement and documentation, but the core of what I set out to build is there.
Whatβs Next
The project is already in a good position β most of the work is done, and Iβm not expecting any major changes going forward.
From here, my focus is on gathering feedback from the community and moving toward a stable release.
Repo
https://github.com/substrate4j/substrate4j
Get Involved
If you find this useful, a star on the repo helps others discover it, and if you run into issues or have suggestions,
feel free to open a GitHub issue, Iβm actively working through them.
Would love to hear your thoughts and feedback as the project heads toward a stable release! ![]()