Rust SDK

The official Rust SDK for MoltChain. Built on reqwest and tokio with strong typing and Result<T> error handling.

Installation

toml
# Cargo.toml
[dependencies]
moltchain-sdk = "0.1"
tokio = { version = "1", features = ["full"] }

Or via the command line:

bash
cargo add moltchain-sdk

Re-exports: moltchain_sdk::{Client, ClientBuilder, Keypair, TransactionBuilder, Balance, Block, NetworkInfo}

Quick Start

Rust
use moltchain_sdk::{Client, Keypair, TransactionBuilder, Balance};

#[tokio::main]
async fn main() -> Result<(), Box> {
    // Connect to local validator
    let client = Client::new("http://localhost:8899");

    // Generate a keypair
    let kp = Keypair::new();
    println!("Address: {}", kp.pubkey());

    // Check balance
    let balance = client.get_balance(&kp.pubkey().to_string()).await?;
    println!("Balance: {} shells", balance.shells());

    // Build and send a transfer
    let blockhash = client.get_recent_blockhash().await?;
    let tx = TransactionBuilder::new()
        .add_instruction(/* transfer instruction */)
        .recent_blockhash(&blockhash)
        .build_and_sign(&kp)?;

    let sig = client.send_transaction(&tx).await?;
    println!("Signature: {sig}");

    Ok(())
}

Client

Client::new(rpc_url: &str) -> Client

Create a client pointing at the given JSON-RPC endpoint.

Rust
let client = Client::new("http://localhost:8899");

Client::builder() -> ClientBuilder

Create a client with advanced options via the builder pattern.

Rust
let client = Client::builder()
    .rpc_url("http://localhost:8899")
    .timeout(std::time::Duration::from_secs(30))
    .build()?;
Builder MethodTypeDescription
rpc_url(url)&strSet RPC endpoint URL (required)
timeout(duration)DurationSet per-request timeout
build()Result<Client>Construct the client

Chain Queries

async get_slot(&self) -> Result<u64>

Get the current slot number.

Rust
let slot = client.get_slot().await?;
println!("Slot: {slot}");

async get_latest_block(&self) -> Result<Block>

Get the most recently produced block.

async get_block(&self, slot: u64) -> Result<Block>

Get a block by slot number.

async get_recent_blockhash(&self) -> Result<String>

Get a recent blockhash for signing transactions.

async get_metrics(&self) -> Result<Value>

Get chain performance metrics (TPS, total transactions/blocks, average block time).

async get_chain_status(&self) -> Result<Value>

Get comprehensive chain status.

async health(&self) -> Result<Value>

Liveness probe. Returns {"status": "ok"}.

async get_network_info(&self) -> Result<NetworkInfo>

Get network information — chain ID, network ID, version, slot.

Rust
let info = client.get_network_info().await?;
println!("Chain: {} v{}", info.chain_id, info.version);

async get_peers(&self) -> Result<Value>

Get connected P2P peers.

async get_total_burned(&self) -> Result<Value>

Get total burned MOLT — {"shells": ..., "molt": ...}.

Account Methods

async get_balance(&self, pubkey: &str) -> Result<Balance>

Get account balance. Returns a strongly-typed Balance.

Rust
let bal = client.get_balance("7xKXtg2CW87d...").await?;
println!("{} shells  ({} MOLT)", bal.shells(), bal.molt());

async get_account_info(&self, pubkey: &str) -> Result<Value>

Get enhanced account information with metadata.

async get_transaction_history(&self, pubkey: &str, limit: u64) -> Result<Value>

Get paginated transaction history for an account.

Transaction Methods

async send_transaction(&self, tx_json: &Value) -> Result<String>

Submit a signed transaction JSON. Returns the signature string.

Rust
let blockhash = client.get_recent_blockhash().await?;
let tx = TransactionBuilder::new()
    .add_instruction(serde_json::json!({
        "type": 0,
        "from": kp.pubkey(),
        "to": "RecipientAddress...",
        "amount": 1_000_000_000_u64
    }))
    .recent_blockhash(&blockhash)
    .build_and_sign(&kp)?;

let sig = client.send_transaction(&tx).await?;

async send_raw_transaction(&self, raw_tx: &str) -> Result<String>

Submit a pre-serialized transaction string.

async get_transaction(&self, signature: &str) -> Result<Value>

Look up a transaction by its signature hash.

Validator & Staking

async get_validators(&self) -> Result<Value>

Get all registered validators.

async get_validator_info(&self, pubkey: &str) -> Result<Value>

Get detailed validator information.

async get_validator_performance(&self, pubkey: &str) -> Result<Value>

Get validator performance metrics.

async stake(&self, from: &str, validator: &str, amount: u64) -> Result<String>

Stake MOLT to a validator. Amount in shells.

Rust
let sig = client.stake(
    &kp.pubkey(),
    "ValidatorPubkey...",
    10_000_000_000  // 10 MOLT
).await?;

async unstake(&self, from: &str, validator: &str, amount: u64) -> Result<String>

Unstake MOLT from a validator.

async get_staking_status(&self, pubkey: &str) -> Result<Value>

Get staking status for an account.

async get_staking_rewards(&self, pubkey: &str) -> Result<Value>

Get accumulated staking rewards.

Contract Methods

async get_contract_info(&self, contract_id: &str) -> Result<Value>

Get information about a deployed smart contract.

async get_contract_logs(&self, contract_id: &str) -> Result<Value>

Get execution logs emitted by a contract.

async get_all_contracts(&self) -> Result<Value>

List all deployed contracts.

Program Methods

async get_program(&self, program_id: &str) -> Result<Value>

Get program information.

async get_programs(&self) -> Result<Value>

List all deployed programs.

async get_program_stats(&self, program_id: &str) -> Result<Value>

Get execution statistics for a program.

async get_program_calls(&self, program_id: &str) -> Result<Value>

Get recent call history for a program.

async get_program_storage(&self, program_id: &str) -> Result<Value>

Get on-chain storage summary for a program.

NFT Methods

async get_collection(&self, collection_id: &str) -> Result<Value>

Get NFT collection metadata.

async get_nft(&self, collection_id: &str, token_id: u64) -> Result<Value>

Get a specific NFT by collection and token ID.

async get_nfts_by_owner(&self, owner: &str) -> Result<Value>

Get all NFTs owned by an address.

async get_nfts_by_collection(&self, collection_id: &str) -> Result<Value>

Get all NFTs in a collection.

async get_nft_activity(&self, collection_id: &str, token_id: u64) -> Result<Value>

Get activity history for a specific NFT.

Keypair

Ed25519 keypair wrapper around ed25519_dalek. Thread-safe and Clone-able.

Keypair::new() -> Keypair

Generate a new random keypair.

Rust
let kp = Keypair::new();
println!("Pubkey: {}", kp.pubkey());

Keypair::from_seed(seed: &[u8; 32]) -> Keypair

Derive a deterministic keypair from a 32-byte seed.

Rust
let seed = [0u8; 32];
let kp = Keypair::from_seed(&seed);

keypair.sign(message: &[u8]) -> Vec<u8>

Sign an arbitrary message. Returns the 64-byte detached signature.

keypair.pubkey() -> String

Get the base58-encoded public key string.

keypair.to_seed() -> [u8; 32]

Extract the 32-byte seed.

keypair.inner() -> &ed25519_dalek::SigningKey

Access the underlying ed25519_dalek::SigningKey for advanced use cases.

TransactionBuilder

Builder pattern for constructing and signing transactions. All methods consume and return self for chaining.

TransactionBuilder::new() -> TransactionBuilder

Create an empty builder.

.add_instruction(value: Value) -> Self

Append an instruction JSON value. Can be called multiple times.

.recent_blockhash(hash: &str) -> Self

Set the recent blockhash.

.build_and_sign(keypair: &Keypair) -> Result<Value>

Sign the instructions and return a transaction JSON object ready to submit.

Rust
use serde_json::json;

let blockhash = client.get_recent_blockhash().await?;
let tx = TransactionBuilder::new()
    .add_instruction(json!({
        "type": 0,
        "from": kp.pubkey(),
        "to": recipient,
        "amount": 5_000_000_000_u64
    }))
    .recent_blockhash(&blockhash)
    .build_and_sign(&kp)?;

let sig = client.send_transaction(&tx).await?;
println!("Transfer complete: {sig}");

Types

Balance

Strongly-typed balance with unit conversions.

Method / ConstructorReturnsDescription
Balance::from_shells(n: u64)BalanceCreate from raw shell count
Balance::from_molt(n: f64)BalanceCreate from MOLT (1 MOLT = 109 shells)
balance.shells()u64Get balance in shells
balance.molt()f64Get balance in MOLT
Rust
let b = Balance::from_molt(25.0);
assert_eq!(b.shells(), 25_000_000_000);
assert_eq!(b.molt(), 25.0);

Block

Deserialized block data.

Rust
#[derive(Debug, Deserialize)]
pub struct Block {
    pub slot: u64,
    pub hash: String,
    pub parent_hash: String,
    pub timestamp: u64,
    pub transactions: Vec,
}

NetworkInfo

Deserialized network information.

Rust
#[derive(Debug, Deserialize)]
pub struct NetworkInfo {
    pub chain_id: String,
    pub network_id: String,
    pub version: String,
    pub slot: u64,
    pub validator_count: u64,
    pub peer_count: u64,
}

Error Handling

All client methods return Result<T, Box<dyn std::error::Error>>. RPC errors surface with their JSON-RPC error code and message.

Rust
match client.get_balance("7xKXtg2CW87d...").await {
    Ok(balance) => println!("{} MOLT", balance.molt()),
    Err(e) => {
        let msg = e.to_string();
        if msg.contains("Account not found") {
            println!("Account does not exist yet");
        } else {
            eprintln!("RPC error: {e}");
        }
    }
}

Common error codes:

  • -32601 — Method not found
  • -32602 — Invalid params
  • -32003 — Admin auth required
  • -32005 — Rate limit exceeded

Tip: For production services, use the ClientBuilder with a custom timeout and wrap calls in a retry loop with exponential backoff for transient network errors.

WebSocket Subscriptions

The Rust SDK supports real-time event streaming via WebSocket. Create a WsClient and subscribe to on-chain events with typed callbacks.

WebSocket — Subscribe to Slots & Accounts
use moltchain_sdk::{WsClient, Pubkey};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let ws = WsClient::connect("ws://localhost:8900").await?;

    // Subscribe to slot updates
    let slot_sub = ws.on_slot(|slot| {
        println!("New slot: {}", slot);
    }).await?;

    // Subscribe to account changes
    let acct = Pubkey::from_base58("YourAccountBase58Here")?;
    let acct_sub = ws.on_account_change(&acct, |account| {
        println!("Balance changed: {} shells", account.shells);
    }).await?;

    // Unsubscribe when done
    ws.off_slot(slot_sub).await?;
    ws.off_account_change(acct_sub).await?;

    // Close all subscriptions
    ws.close().await;
    Ok(())
}

WsClient::connect(url: &str) -> Result<WsClient>

Open a WebSocket connection to the given endpoint.

on_slot(callback) / off_slot(sub_id)

Subscribe to slot updates. Returns a subscription ID for unsubscribing.

on_block(callback) / off_block(sub_id)

Subscribe to new blocks.

on_account_change(pubkey, callback) / off_account_change(sub_id)

Watch a specific account for balance or data changes.

on_logs(callback, contract_id?) / off_logs(sub_id)

Stream contract logs. Optionally filter by contract ID.

close()

Close the WebSocket connection and clear all active subscriptions.