Skip to content

Commit 0b40df1

Browse files
committed
wip: subxt
1 parent 6d68308 commit 0b40df1

File tree

5 files changed

+477
-3
lines changed

5 files changed

+477
-3
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "my-project"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
subxt = "0.39.0"
8+
subxt-signer = "0.39.0"
9+
tokio = { version = "1.43.0", features = ["rt", "macros"] }
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
use std::str::FromStr;
2+
use subxt::utils::AccountId32;
3+
use subxt::{OnlineClient, PolkadotConfig};
4+
use subxt_signer::{bip39::Mnemonic,sr25519::Keypair};
5+
6+
#[tokio::main(flavor = "current_thread")]
7+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
8+
// Define the node URL.
9+
const NODE_URL: &str = "INSERT_NODE_URL";
10+
11+
// Initialize the Subxt client for interacting with the blockchain.
12+
let api = OnlineClient::<PolkadotConfig>::from_url(NODE_URL).await?;
13+
14+
// A query to obtain some contant:
15+
let constant_query = polkadot::constants().balances().existential_deposit();
16+
17+
// Obtain the value:
18+
let value = api.constants().at(&constant_query)?;
19+
20+
println!("Existential deposit: {:?}", value);
21+
22+
// Define the target account address.
23+
const ADDRESS: &str = "INSERT_ADDRESS";
24+
let account = AccountId32::from_str(ADDRESS).unwrap();
25+
26+
// Build a storage query to access account information.
27+
let storage_query = polkadot::storage().system().account(&account.into());
28+
29+
// Fetch the latest state for the account.
30+
let result = api
31+
.storage()
32+
.at_latest()
33+
.await?
34+
.fetch(&storage_query)
35+
.await?
36+
.unwrap();
37+
38+
println!("Account info: {:?}", result);
39+
40+
// Define the recipient address and transfer amount.
41+
const DEST_ADDRESS: &str = "INSERT_DEST_ADDRESS";
42+
const AMOUNT: u128 = INSERT_AMOUNT;
43+
44+
// Convert the recipient address into an `AccountId32`.
45+
let dest = AccountId32::from_str(DEST_ADDRESS).unwrap();
46+
47+
// Build the balance transfer extrinsic.
48+
let balance_transfer_tx = polkadot::tx()
49+
.balances()
50+
.transfer_allow_death(dest.into(), AMOUNT);
51+
52+
// Load the sender's keypair from a mnemonic phrase.
53+
const SECRET_PHRASE: &str = "INSERT_SECRET_PHRASE";
54+
let mnemonic = Mnemonic::parse(SECRET_PHRASE).unwrap();
55+
let sender_keypair = Keypair::from_phrase(&mnemonic, None).unwrap();
56+
57+
// Sign and submit the extrinsic, then wait for it to be finalized.
58+
let events = api
59+
.tx()
60+
.sign_and_submit_then_watch_default(&balance_transfer_tx, &sender_keypair)
61+
.await?
62+
.wait_for_finalized_success()
63+
.await?;
64+
65+
// Check for a successful transfer event.
66+
if let Some(event) = events.find_first::<polkadot::balances::events::Transfer>()? {
67+
println!("Balance transfer successful: {:?}", event);
68+
}
69+
70+
Ok(())
71+
}

develop/toolkit/api-libraries/.pages

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ nav:
44
- 'Polkadot.js API': polkadot-js-api.md
55
- 'Polkadot-API': papi.md
66
- 'Sidecar Rest API': sidecar.md
7-
- 'Python Substrate Interface': py-substrate-interface.md
7+
- 'Python Substrate Interface': py-substrate-interface.md
8+
- 'Subxt': subxt.md
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
---
2+
title: Subxt
3+
description: TODO
4+
---
5+
6+
# Subxt
7+
8+
## Introduction
9+
10+
Subxt is a Rust library designed for interacting 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.
11+
12+
## Prerequisites
13+
14+
Before using Subxt, ensure you have the following installed:
15+
16+
- Rust and Cargo installed on your system. You can install them using [Rustup](https://rustup.rs/){target=\_blank}
17+
- A Rust project initialized. If you don’t have one, create it with:
18+
```bash
19+
cargo new my_project && cd my_project
20+
```
21+
22+
## Installation
23+
24+
To use subxt in your project, you need to install the necessary dependencies. Each plays a specific role in enabling interaction with the blockchain:
25+
26+
### Install subxt-cli
27+
28+
[`subxt-cli`](https://crates.io/crates/subxt-cli){target=\_blank} is a command-line tool that provides utilities for working with Polkadot SDK metadata. In the context of subxt, it is essential for downloading chain metadata, which is required to generate type-safe Rust interfaces for interacting with the blockchain. Install it using:
29+
30+
```bash
31+
cargo install subxt-cli
32+
```
33+
34+
### Add Core Dependencies
35+
36+
These dependencies are essential for interacting with the blockchain:
37+
38+
- **[subxt](https://crates.io/crates/subxt){target=\_blank}** - the main library for communicating with Polkadot SDK nodes. It handles RPC requests, encoding/decoding, and type generation
39+
40+
```bash
41+
cargo add subxt
42+
```
43+
44+
- **[subxt-signer](https://crates.io/crates/subxt-signer){target=\_blank}** - provides cryptographic functionality for signing transactions. Without this, you can only read data but cannot submit transactions
45+
46+
```bash
47+
cargo add subxt-signer
48+
```
49+
50+
- **[tokio](https://crates.io/crates/tokio){target=\_blank}** - an asynchronous runtime for Rust. Since blockchain operations are async, Tokio enables efficient handling of network requests
51+
52+
```bash
53+
cargo add tokio --features rt,macros
54+
```
55+
56+
After adding the dependencies, your `Cargo.toml` should look like this:
57+
58+
```toml
59+
[package]
60+
name = "my_project"
61+
version = "0.1.0"
62+
edition = "2021"
63+
64+
[dependencies]
65+
subxt = "0.39.0"
66+
subxt-signer = "0.39.0"
67+
tokio = { version = "1.43.0", features = ["rt", "macros"] }
68+
```
69+
70+
## Get Started
71+
72+
This guide will walk you through the basic operations using subxt.
73+
74+
### Downloading Chain Metadata
75+
76+
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:
77+
78+
```bash
79+
subxt metadata --url INSERT_NODE_URL > polkadot_metadata.scale
80+
```
81+
82+
### Generating Type-Safe Interfaces
83+
84+
Use the `#[subxt::subxt]` macro to generate a type-safe Rust interface from the downloaded metadata:
85+
86+
```rust
87+
// Generate an interface that we can use from the node's metadata.
88+
#[subxt::subxt(runtime_metadata_path = "./polkadot_metadata.scale")]
89+
pub mod polkadot {}
90+
```
91+
92+
### Initializing the Subxt client
93+
94+
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:
95+
96+
```rust
97+
use std::str::FromStr;
98+
use subxt::utils::AccountId32;
99+
use subxt::{OnlineClient, PolkadotConfig};
100+
use subxt_signer::{bip39::Mnemonic,sr25519::Keypair};
101+
102+
#[tokio::main(flavor = "current_thread")]
103+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
104+
// Define the node URL.
105+
const NODE_URL: &str = "INSERT_NODE_URL";
106+
107+
// Initialize the Subxt client for interacting with the blockchain.
108+
let api = OnlineClient::<PolkadotConfig>::from_url(NODE_URL).await?;
109+
110+
// Your code here...
111+
112+
Ok(())
113+
}
114+
```
115+
116+
### Reading Chain Data
117+
118+
Subxt provides multiple ways to access on-chain data:
119+
120+
- Constants - constants are predefined values in the runtime that remain unchanged unless modified by a runtime upgrade
121+
122+
For example, to retrieve the existential deposit, use:
123+
```rust
124+
// A query to obtain some contant:
125+
let constant_query = polkadot::constants().balances().existential_deposit();
126+
127+
// Obtain the value:
128+
let value = api.constants().at(&constant_query)?;
129+
```
130+
131+
- State - state refers to the current chain data, which updates with each block
132+
133+
To fetch account information, use:
134+
```rust
135+
// Define the target account address.
136+
const ADDRESS: &str = "INSERT_ADDRESS";
137+
let account = AccountId32::from_str(ADDRESS).unwrap();
138+
139+
// Build a storage query to access account information.
140+
let storage_query = polkadot::storage().system().account(&account.into());
141+
142+
// Fetch the latest state for the account.
143+
let result = api
144+
.storage()
145+
.at_latest()
146+
.await?
147+
.fetch(&storage_query)
148+
.await?
149+
.unwrap();
150+
151+
println!("Account info: {:?}", result);
152+
```
153+
154+
### Submitting Transasctions
155+
156+
To submit a transaction, you need to construct an extrinsic, sign it with your private key, and send it to the blockchain.
157+
158+
For example, to transfer funds to another account:
159+
160+
```rust
161+
// Define the recipient address and transfer amount.
162+
const DEST_ADDRESS: &str = "INSERT_DEST_ADDRESS";
163+
const AMOUNT: u128 = INSERT_AMOUNT;
164+
165+
// Convert the recipient address into an `AccountId32`.
166+
let dest = AccountId32::from_str(DEST_ADDRESS).unwrap();
167+
168+
// Build the balance transfer extrinsic.
169+
let balance_transfer_tx = polkadot::tx()
170+
.balances()
171+
.transfer_allow_death(dest.into(), AMOUNT);
172+
173+
// Load the sender's keypair from a mnemonic phrase.
174+
const SECRET_PHRASE: &str = "INSERT_SECRET_PHRASE";
175+
let mnemonic = Mnemonic::parse(SECRET_PHRASE).unwrap();
176+
let sender_keypair = Keypair::from_phrase(&mnemonic, None).unwrap();
177+
178+
// Sign and submit the extrinsic, then wait for it to be finalized.
179+
let events = api
180+
.tx()
181+
.sign_and_submit_then_watch_default(&balance_transfer_tx, &sender_keypair)
182+
.await?
183+
.wait_for_finalized_success()
184+
.await?;
185+
186+
// Check for a successful transfer event.
187+
if let Some(event) = events.find_first::<polkadot::balances::events::Transfer>()? {
188+
println!("Balance transfer successful: {:?}", event);
189+
}
190+
```
191+
192+
## Where to Go Next
193+
194+
Now that you've covered the basics, dive into the official [Subxt documentation](https://docs.rs/subxt/latest/subxt/book/index.html){target=\_blank} for comprehensive reference materials and advanced features.

0 commit comments

Comments
 (0)