Subxt Rust API¶
Introduction¶
subxt is a Rust library designed to interact with Polkadot SDK-based blockchains. It provides a type-safe interface for submitting transactions, querying on-chain state, and performing other blockchain interactions. By leveraging Rust's strong type system, subxt ensures that your code is validated at compile time, reducing runtime errors and improving reliability.
Prerequisites¶
Before using subxt, ensure you have the following requirements:
- Rust and Cargo installed on your system. You can install them using Rustup
- A Rust project initialized. If you don't have one, create it with:
Installation¶
To use subxt in your project, you must install the necessary dependencies. Each plays a specific role in enabling interaction with the blockchain:
-
Install the subxt CLI -
subxt-cli
is a command-line tool that provides utilities for working with Polkadot SDK metadata. In the context of subxt, it is essential to download chain metadata, which is required to generate type-safe Rust interfaces for interacting with the blockchain. Install it using: -
Add core dependencies - these dependencies are essential for interacting with the blockchain:
-
subxt - the main library for communicating with Polkadot SDK nodes. It handles RPC requests, encoding/decoding, and type generation
-
subxt-signer - provides cryptographic functionality for signing transactions. Without this, you can only read data but cannot submit transactions
-
tokio - an asynchronous runtime for Rust. Since blockchain operations are async, Tokio enables the efficient handling of network requests. The
rt
feature enables Tokio's runtime, including the current-thread single-threaded scheduler, which is necessary for async execution. Themacros
feature provides procedural macros like#[tokio::main]
to simplify runtime setup
After adding the dependencies, your
Cargo.toml
should look like this: -
Get Started¶
This guide will walk you through the fundamental operations of subxt, from setting up your environment to executing transactions and querying blockchain state.
Download Chain Metadata¶
Before interacting with a blockchain, you need to retrieve its metadata. This metadata defines storage structures, extrinsics, and other runtime details. Use the subxt-cli
tool to download the metadata, replacing INSERT_NODE_URL
with the URL of the node you want to interact with:
Generate Type-Safe Interfaces¶
Use the #[subxt::subxt]
macro to generate a type-safe Rust interface from the downloaded metadata:
// Generate an interface that we can use from the node's metadata.
#[subxt::subxt(runtime_metadata_path = "./polkadot_metadata.scale")]
pub mod polkadot {}
Once subxt interfaces are generated, you can interact with your node in the following ways. You can use the links below to view the related subxt documentation:
- Transactions - builds and submits transactions, monitors their inclusion in blocks, and retrieves associated events
- Storage - enables querying of node storage data
- Events - retrieves events emitted from recent blocks
- Constants - accesses constant values stored in nodes that remain unchanged across a specific runtime version.
- Blocks - loads recent blocks or subscribes to new/finalized blocks, allowing examination of extrinsics, events, and storage at those blocks
- Runtime APIs - makes calls into pallet runtime APIs to fetch data
- Custom values - accesses "custom values" contained within metadata
- Raw RPC calls - facilitates raw RPC requests to compatible nodes
Initialize the Subxt client¶
To interact with a blockchain node using subxt, create an asynchronous main function and initialize the client. Replace INSERT_NODE_URL
with the URL of your target node:
use std::str::FromStr;
use subxt::utils::AccountId32;
use subxt::{OnlineClient, PolkadotConfig};
use subxt_signer::{bip39::Mnemonic,sr25519::Keypair};
// Generate an interface that we can use from the node's metadata.
#[subxt::subxt(runtime_metadata_path = "./polkadot_metadata.scale")]
pub mod polkadot {}
#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Define the node URL.
const NODE_URL: &str = "INSERT_NODE_URL";
// Initialize the Subxt client to interact with the blockchain.
let api = OnlineClient::<PolkadotConfig>::from_url(NODE_URL).await?;
// Your code here...
Ok(())
}
Read Chain Data¶
subxt provides multiple ways to access on-chain data:
-
Constants - constants are predefined values in the runtime that remain unchanged unless modified by a runtime upgrade
For example, to retrieve the existential deposit, use:
-
State - state refers to the current chain data, which updates with each block
To fetch account information, replace
INSERT_ADDRESS
with the address you want to fetch data from and use:// Define the target account address. const ADDRESS: &str = "INSERT_ADDRESS"; let account = AccountId32::from_str(ADDRESS).unwrap(); // Build a storage query to access account information. let storage_query = polkadot::storage().system().account(&account.into()); // Fetch the latest state for the account. let result = api .storage() .at_latest() .await? .fetch(&storage_query) .await? .unwrap(); println!("Account info: {:?}", result);
Submit Transactions¶
To submit a transaction, you must construct an extrinsic, sign it with your private key, and send it to the blockchain. Replace INSERT_DEST_ADDRESS
with the recipient's address, INSERT_AMOUNT
with the amount to transfer, and INSERT_SECRET_PHRASE
with the sender's mnemonic phrase:
// Define the recipient address and transfer amount.
const DEST_ADDRESS: &str = "INSERT_DEST_ADDRESS";
const AMOUNT: u128 = INSERT_AMOUNT;
// Convert the recipient address into an `AccountId32`.
let dest = AccountId32::from_str(DEST_ADDRESS).unwrap();
// Build the balance transfer extrinsic.
let balance_transfer_tx = polkadot::tx()
.balances()
.transfer_allow_death(dest.into(), AMOUNT);
// Load the sender's keypair from a mnemonic phrase.
const SECRET_PHRASE: &str = "INSERT_SECRET_PHRASE";
let mnemonic = Mnemonic::parse(SECRET_PHRASE).unwrap();
let sender_keypair = Keypair::from_phrase(&mnemonic, None).unwrap();
// Sign and submit the extrinsic, then wait for it to be finalized.
let events = api
.tx()
.sign_and_submit_then_watch_default(&balance_transfer_tx, &sender_keypair)
.await?
.wait_for_finalized_success()
.await?;
// Check for a successful transfer event.
if let Some(event) = events.find_first::<polkadot::balances::events::Transfer>()? {
println!("Balance transfer successful: {:?}", event);
}
Where to Go Next¶
Now that you've covered the basics dive into the official subxt documentation for comprehensive reference materials and advanced features.
| Created: March 12, 2025