#bitcoin #lightning #payment #lsp #blocktank

rust-blocktank-client

A Rust client for the Blocktank LSP HTTP API

10 releases

0.0.10 Mar 13, 2025
0.0.9 Mar 12, 2025
0.0.6 Feb 27, 2025
0.0.5 Jan 30, 2025

#25 in #lightning

Download history 49/week @ 2025-01-08 181/week @ 2025-01-15 178/week @ 2025-01-22 165/week @ 2025-01-29 20/week @ 2025-02-05 149/week @ 2025-02-26 132/week @ 2025-03-05 393/week @ 2025-03-12

674 downloads per month

MIT license

57KB
1K SLoC

rust-blocktank-client

A Rust client for the Blocktank LSP HTTP API.

Installation

Add this to your Cargo.toml:

[dependencies]
rust-blocktank-client = "0.0.10"

By default, the client uses rustls as the TLS backend. If you prefer to use the native TLS implementation:

[dependencies]
rust-blocktank-client = { version = "0.0.10", default-features = false, features = ["native-tls"] }

Usage

use rust_blocktank_client::{BlocktankClient, CreateOrderOptions, CreateCjitOptions};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize the client (note: base_url is Option<&str>)
    let client = BlocktankClient::new(Some("https://api1.blocktank.to/api"))?;

    // Get service information
    let info = client.get_info().await?;
    println!("Service version: {}", info.version);
    println!("Network: {:?}", info.onchain.network);
    println!("Min channel size: {} sats", info.options.min_channel_size_sat);

    // Estimate channel order fee
    let fee_estimate = client.estimate_order_fee(
        100_000,     // lsp_balance_sat
        4,           // channel_expiry_weeks
        Some(CreateOrderOptions {
            client_balance_sat: 20_000,
            source: Some("example".to_string()),
            ..Default::default()
        }),
    ).await?;
    println!("Estimated fee: {} sats", fee_estimate.fee_sat);

    // Estimate fee with detailed breakdown
    let full_fee_estimate = client.estimate_order_fee_full(
        100_000,     // lsp_balance_sat
        4,           // channel_expiry_weeks
        Some(CreateOrderOptions {
            client_balance_sat: 20_000,
            ..Default::default()
        }),
    ).await?;
    println!("Service fee: {} sats", full_fee_estimate.service_fee_sat);
    println!("Network fee: {} sats", full_fee_estimate.network_fee_sat);
    println!("Total fee: {} sats", full_fee_estimate.fee_sat);

    // Create a channel order
    let order = client.create_order(
        100_000,     // lsp_balance_sat
        4,           // channel_expiry_weeks
        Some(CreateOrderOptions {
            client_balance_sat: 20_000,
            zero_conf: true,
            source: Some("example".to_string()),
            ..Default::default()
        }),
    ).await?;
    println!("Created order: {}", order.id);
    println!("Zero-conf enabled: {}", order.zero_conf);

    // Get existing order
    let order = client.get_order(&order.id).await?;
    println!("Order state: {:?}", order.state2);

    // Get minimum zero-conf transaction fee
    let min_fee = client.get_min_zero_conf_tx_fee(&order.id).await?;
    println!("Minimum fee rate: {} sat/vbyte", min_fee.sat_per_vbyte);
    println!("Valid until: {}", min_fee.validity_ends_at);

    // Open channel to a node
    let connection_string = "02eadbd9e7557375161df8b646776a547c5cbc2e95b3071ec81553f8ec2cea3b8c@127.0.0.1:9735";
    let updated_order = client.open_channel(&order.id, connection_string).await?;
    println!("Channel opening: {:?}", updated_order.channel);

    // Create a CJIT entry
    let cjit = client.create_cjit_entry(
        200_000,            // channel_size_sat
        50_000,             // invoice_sat
        "Test invoice",     // invoice_description
        "node_pubkey_hex",  // node_id
        4,                  // channel_expiry_weeks
        Some(CreateCjitOptions {
            source: Some("example".to_string()),
            ..Default::default()
        }),
    ).await?;
    println!("Created CJIT entry: {}", cjit.id);

    // Get multiple orders
    let order_ids = vec![order.id.clone()];
    let orders = client.get_orders(&order_ids).await?;
    println!("Retrieved {} orders", orders.len());

    Ok(())
}

Regtest Examples

use rust_blocktank_client::BlocktankClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = BlocktankClient::new(Some("http://localhost:3000/api"))?;

    // Mine some blocks
    client.regtest_mine(Some(6)).await?;

    // Deposit to an address
    let tx_id = client.regtest_deposit(
        "bcrt1q94n9ekw8v3g7ksk76kq8k9kn4n7tqx0vfqva0w",
        Some(100_000)
    ).await?;
    println!("Deposit transaction: {}", tx_id);

    // Pay an invoice
    let payment_id = client.regtest_pay(
        "lnbcrt1...",  // Invoice string
        Some(50_000)   // Optional amount for zero-amount invoices
    ).await?;
    println!("Payment ID: {}", payment_id);

    // Get payment info
    let payment = client.regtest_get_payment(&payment_id).await?;
    println!("Payment state: {:?}", payment.state);

    // Close a channel
    let closing_tx = client.regtest_close_channel(
        "txid",     // funding_tx_id
        0,          // vout
        Some(3600), // force close after 1 hour
    ).await?;
    println!("Closing transaction: {}", closing_tx);

    Ok(())
}

Running Tests

To run all tests:

cargo test

To run tests with output (including println! statements):

cargo test -- --nocapture

To run a specific test:

cargo test <test_name>

Dependencies

~7–19MB
~253K SLoC