apex-sdk-substrate

Crates.ioapex-sdk-substrate
lib.rsapex-sdk-substrate
version0.1.5
created_at2025-11-15 09:00:01.159962+00
updated_at2026-01-13 06:51:54.821502+00
descriptionSubstrate adapter for Apex SDK
homepage
repositoryhttps://github.com/carbobit/apex-sdk
max_upload_size
id1934168
size469,612
(kh3rld)

documentation

README

apex-sdk-substrate

Crates.io Documentation Downloads License Substrate Rust

Substrate blockchain adapter for the Apex SDK, enabling seamless interaction with Polkadot, Kusama, and other Substrate-based chains.

Overview

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.

Features

  • Multi-Chain Support: Polkadot, Kusama, Westend, and custom Substrate chains
  • Type-Safe Metadata: Compile-time type checking with generated metadata
  • Smart Contracts: Full ink! smart contract support with deployment and interaction
  • XCM Integration: Cross-chain messaging and asset transfers
  • Wallet Management: SR25519/ED25519 key pair management and signing
  • Connection Pooling: Robust connection management with health checks
  • Caching Layer: Intelligent caching for storage queries and account data
  • Metrics: Comprehensive monitoring and observability

Installation

Add this to your Cargo.toml:

[dependencies]
apex-sdk-substrate = "0.1.3"
tokio = { version = "1.0", features = ["full"] }

Feature Flags

[dependencies]
apex-sdk-substrate = { version = "0.1.3", features = ["typed-westend"] }

Available features:

  • typed-polkadot - Typed metadata for Polkadot
  • typed-kusama - Typed metadata for Kusama
  • typed-westend - Typed metadata for Westend
  • typed - Base typed metadata support

Quick Start

Basic Connection

use 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(())
}

Different Chain Connections

// 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?;

Account and Wallet Management

Creating Wallets

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()));

From Mnemonic

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"))?;

Account Queries

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);

Transaction Building and Submission

Basic Transfers

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());

Batch Transactions

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()?;

Smart Contract Integration (ink!)

Contract Deployment

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());

Contract Interaction

// 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);

Contract Events

// 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);
        }
        _ => {}
    }
}

Cross-Chain Messaging (XCM)

Asset Transfers

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 Transfers

// 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?;

Storage Queries

System Storage

// 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?;

Custom Storage Queries

// 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);

Advanced Features

Connection Pooling

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?;

Caching

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);

Typed Metadata

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?;

Monitoring and Metrics

Built-in Metrics

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);

Error Handling

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
    }
}

Testing

Unit Tests

cargo test

Integration Tests

cargo test --features integration-tests

Integration tests connect to Westend testnet.

Examples

Complete examples in the examples directory:

Configuration

Chain Endpoints

// 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",
];

Environment Variables

# 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"

Generating Typed Metadata

To use typed metadata features:

cd apex-sdk-substrate
./scripts/generate_metadata.sh westend

This generates type-safe Rust code from live chain metadata.

License

Licensed under the Apache License, Version 2.0. See LICENSE for details.

Contributing

Contributions are welcome! Please read CONTRIBUTING.md for guidelines.

Support

Commit count: 95

cargo fmt