| Crates.io | apex-sdk-substrate |
| lib.rs | apex-sdk-substrate |
| version | 0.1.5 |
| created_at | 2025-11-15 09:00:01.159962+00 |
| updated_at | 2026-01-13 06:51:54.821502+00 |
| description | Substrate adapter for Apex SDK |
| homepage | |
| repository | https://github.com/carbobit/apex-sdk |
| max_upload_size | |
| id | 1934168 |
| size | 469,612 |
Substrate blockchain adapter for the Apex SDK, enabling seamless interaction with Polkadot, Kusama, and other Substrate-based chains.
apex-sdk-substrate provides a comprehensive Rust interface for interacting with Substrate-based blockchains. It offers type-safe APIs for transactions, storage queries, smart contracts (ink!), cross-chain messaging (XCM), and more.
Add this to your Cargo.toml:
[dependencies]
apex-sdk-substrate = "0.1.3"
tokio = { version = "1.0", features = ["full"] }
[dependencies]
apex-sdk-substrate = { version = "0.1.3", features = ["typed-westend"] }
Available features:
typed-polkadot - Typed metadata for Polkadottyped-kusama - Typed metadata for Kusamatyped-westend - Typed metadata for Westendtyped - Base typed metadata supportuse apex_sdk_substrate::SubstrateAdapter;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Connect to Polkadot
let adapter = SubstrateAdapter::polkadot("wss://rpc.polkadot.io").await?;
// Get latest block number
let block_number = adapter.get_latest_block().await?;
println!("Latest block: {}", block_number);
Ok(())
}
// Polkadot
let polkadot = SubstrateAdapter::polkadot("wss://rpc.polkadot.io").await?;
// Kusama
let kusama = SubstrateAdapter::kusama("wss://kusama-rpc.polkadot.io").await?;
// Westend Testnet
let westend = SubstrateAdapter::westend("wss://westend-rpc.polkadot.io").await?;
// Custom Substrate chain
let custom = SubstrateAdapter::custom("wss://your-node.com", "your-chain").await?;
use apex_sdk_substrate::{Wallet, Keypair};
// Generate new SR25519 keypair
let keypair = Keypair::generate_sr25519();
let wallet = Wallet::new(keypair);
println!("Address: {}", wallet.address());
println!("Public key: {}", hex::encode(wallet.public_key()));
use apex_sdk_substrate::Wallet;
// Create from mnemonic phrase
let mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
let wallet = Wallet::from_mnemonic(mnemonic, None)?;
// With custom derivation path
let wallet = Wallet::from_mnemonic(mnemonic, Some("//Ilara"))?;
let adapter = SubstrateAdapter::westend("wss://westend-rpc.polkadot.io").await?;
// Get account balance
let account_id = wallet.account_id();
let balance = adapter.get_balance(&account_id).await?;
println!("Balance: {} WND", balance);
// Get account nonce
let nonce = adapter.get_nonce(&account_id).await?;
println!("Nonce: {}", nonce);
// Get account info
let account_info = adapter.get_account_info(&account_id).await?;
println!("Free balance: {}", account_info.data.free);
println!("Reserved: {}", account_info.data.reserved);
use apex_sdk_substrate::{SubstrateAdapter, TransactionBuilder};
let adapter = SubstrateAdapter::westend("wss://westend-rpc.polkadot.io").await?;
let wallet = Wallet::from_mnemonic("your mnemonic", None)?;
// Build transfer transaction
let dest = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"; // Ilara
let amount = 1_000_000_000_000u128; // 1 WND
let tx = TransactionBuilder::new(&adapter)
.transfer_keep_alive(dest, amount)
.build()?;
// Sign and submit
let signed_tx = wallet.sign(&tx).await?;
let hash = adapter.submit_transaction(&signed_tx).await?;
println!("Transaction submitted: {}", hash);
// Wait for finalization
let events = adapter.wait_for_finalized(&hash).await?;
println!("Transaction finalized with {} events", events.len());
let tx = TransactionBuilder::new(&adapter)
.batch(vec![
// Multiple transfers in one transaction
adapter.tx().balances().transfer_keep_alive(dest1, amount1),
adapter.tx().balances().transfer_keep_alive(dest2, amount2),
adapter.tx().balances().transfer_keep_alive(dest3, amount3),
])
.build()?;
use apex_sdk_substrate::{ContractClient, ContractMetadata};
let adapter = SubstrateAdapter::westend("wss://westend-rpc.polkadot.io").await?;
let wallet = Wallet::from_mnemonic("your mnemonic", None)?;
// Load contract metadata and WASM
let metadata = ContractMetadata::load("contract.json")?;
let wasm_code = std::fs::read("contract.wasm")?;
// Deploy contract
let contract = ContractClient::new(&adapter, &wallet)
.deploy(
wasm_code,
metadata.clone(),
"new", // constructor name
vec![], // constructor args
1_000_000_000_000u64, // endowment
None, // salt
)
.await?;
println!("Contract deployed at: {}", contract.address());
// Call contract method
let result = contract
.call("get_value")
.args(vec![])
.dry_run() // Read-only call
.await?;
println!("Contract returned: {:?}", result);
// Execute contract transaction
let tx_hash = contract
.call("set_value")
.args(vec![42u32.into()])
.value(0) // No payment
.submit()
.await?;
println!("Contract call submitted: {}", tx_hash);
// Listen for contract events
let mut event_stream = contract.events().await?;
while let Some(event) = event_stream.next().await {
match event {
ContractEvent::ValueChanged { old_value, new_value } => {
println!("Value changed from {} to {}", old_value, new_value);
}
_ => {}
}
}
use apex_sdk_substrate::xcm::{XcmClient, Destination, Asset};
let adapter = SubstrateAdapter::polkadot("wss://rpc.polkadot.io").await?;
let wallet = Wallet::from_mnemonic("your mnemonic", None)?;
let xcm = XcmClient::new(&adapter, &wallet);
// Transfer DOT to a parachain
let dest = Destination::parachain(1000); // Acala parachain
let asset = Asset::native(10_000_000_000u128); // 1 DOT
let beneficiary = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY";
let tx_hash = xcm
.transfer_asset(dest, asset, beneficiary)
.await?;
println!("XCM transfer submitted: {}", tx_hash);
// Reserve-based transfer
let tx_hash = xcm
.reserve_transfer_asset(dest, asset, beneficiary)
.await?;
// Teleport (for trusted chains)
let tx_hash = xcm
.teleport_asset(dest, asset, beneficiary)
.await?;
// Query any storage item
let storage_key = adapter.storage().system().account(account_id);
let account_info = adapter.query_storage(&storage_key, None).await?;
// Get storage at specific block
let block_hash = adapter.get_block_hash(Some(100_000)).await?;
let historical_data = adapter.query_storage(&storage_key, Some(block_hash)).await?;
// Using storage client
let storage = adapter.storage();
// Query balances
let balance_key = storage.balances().account(&account_id);
let balance_info = adapter.query_storage(&balance_key, None).await?;
// Query runtime version
let version = adapter.runtime_version().await?;
println!("Runtime version: {}", version.spec_version);
use apex_sdk_substrate::{SubstrateAdapter, PoolConfig};
let pool_config = PoolConfig {
max_connections: 10,
min_connections: 2,
connection_timeout: Duration::from_secs(30),
health_check_interval: Duration::from_secs(60),
reconnect_attempts: 5,
};
let adapter = SubstrateAdapter::with_pool(
vec![
"wss://rpc.polkadot.io",
"wss://polkadot-rpc.dwellir.com",
"wss://1rpc.io/dot",
],
pool_config,
).await?;
use apex_sdk_substrate::CacheConfig;
let cache_config = CacheConfig {
max_entries: 10000,
ttl: Duration::from_secs(300), // 5 minutes
storage_cache_enabled: true,
account_cache_enabled: true,
};
let adapter = SubstrateAdapter::westend("wss://westend-rpc.polkadot.io")
.await?
.with_cache(cache_config);
With typed metadata, you get compile-time type safety:
// Enable with feature flag: features = ["typed-westend"]
use apex_sdk_substrate::metadata::westend;
let adapter = SubstrateAdapter::westend("wss://westend-rpc.polkadot.io").await?;
// Type-safe transaction building
let tx = westend::tx()
.balances()
.transfer_keep_alive(dest, amount);
// Type-safe storage queries
let storage_query = westend::storage()
.system()
.account(&account_id);
let account_info = adapter.query_storage(&storage_query, None).await?;
use apex_sdk_substrate::MetricsConfig;
let metrics_config = MetricsConfig {
enabled: true,
prometheus_endpoint: Some("0.0.0.0:9090".to_string()),
collect_rpc_metrics: true,
collect_cache_metrics: true,
};
let adapter = SubstrateAdapter::westend("wss://westend-rpc.polkadot.io")
.await?
.with_metrics(metrics_config);
// Access metrics
let metrics = adapter.metrics();
println!("RPC calls: {}", metrics.rpc_calls_total());
println!("Cache hit rate: {:.2}%", metrics.cache_hit_rate() * 100.0);
use apex_sdk_substrate::{SubstrateError, Result};
match some_operation().await {
Err(SubstrateError::InsufficientFunds) => {
println!("Account has insufficient balance");
}
Err(SubstrateError::TransactionFailed(reason)) => {
println!("Transaction failed: {}", reason);
}
Err(SubstrateError::ConnectionError(msg)) => {
println!("Connection error: {}", msg);
}
Err(SubstrateError::MetadataError(msg)) => {
println!("Metadata error: {}", msg);
}
Ok(result) => {
// Handle success
}
}
cargo test
cargo test --features integration-tests
Integration tests connect to Westend testnet.
Complete examples in the examples directory:
// Polkadot
const POLKADOT_ENDPOINTS: &[&str] = &[
"wss://rpc.polkadot.io",
"wss://polkadot-rpc.dwellir.com",
"wss://1rpc.io/dot",
];
// Kusama
const KUSAMA_ENDPOINTS: &[&str] = &[
"wss://kusama-rpc.polkadot.io",
"wss://kusama-rpc.dwellir.com",
"wss://1rpc.io/ksm",
];
# Chain endpoints
POLKADOT_RPC_URL="wss://rpc.polkadot.io"
KUSAMA_RPC_URL="wss://kusama-rpc.polkadot.io"
WESTEND_RPC_URL="wss://westend-rpc.polkadot.io"
# Mnemonics (for testing)
TEST_MNEMONIC="abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
# API keys for public nodes
DWELLIR_API_KEY="your-dwellir-key"
ONFINALITY_API_KEY="your-onfinality-key"
To use typed metadata features:
cd apex-sdk-substrate
./scripts/generate_metadata.sh westend
This generates type-safe Rust code from live chain metadata.
Licensed under the Apache License, Version 2.0. See LICENSE for details.
Contributions are welcome! Please read CONTRIBUTING.md for guidelines.