data-anchor-client

Crates.iodata-anchor-client
lib.rsdata-anchor-client
version0.4.3
created_at2025-06-05 16:12:25.858871+00
updated_at2025-09-23 09:45:30.840597+00
descriptionContains blober client for interacting with the Blober program on Solana.
homepagehttps://www.termina.technology
repositoryhttps://github.com/nitro-svm/data-anchor-oss
max_upload_size
id1701757
size352,608
Petar Vujović (petarvujovic98)

documentation

README

Data Anchor Client

This crate is a Rust client which handles interactions with the Nitro Blober on-chain program and with the Data Anchor indexer service in an optimized way.

Usage

All you need to do to get started with the client is add it to your project dependencies:

cargo add data-anchor-client

Connecting

To start uploading and reading data, pass the configs into the client like the following:

let data_anchor_client = DataAnchorClient::builder()
    .payer(payer)
    .program_id(program_id)
    .indexer_from_url(&indexer_url)
    .await?
    .build_with_config(config)
    .await?;
  • The payer is a Arc<Keypair> - a solana keypair you want to use with the client
  • The program_id is the address of the blober on-chain program you want to interact with
  • The indexer_url is an optional parameter to provide if you are using our indexer service
  • The config is a solana_cli_config::Config object used to determine RPC details with which to send the transactions

Builder options

The builder exposes a few additional helpers. A common pattern is to use an indexer together with the Helius fee estimator:

let client = DataAnchorClient::builder()
    .payer(payer)
    .program_id(program_id)
    .indexer_from_url("https://indexer.example.com", None)
    .await?
    .with_helius_fee_estimate()
    .build_with_config(Config::default())
    .await?;

The with_helius_fee_estimate flag enables querying the Helius API for a better priority fee estimate when sending transactions.

Uploading data

Uploading data once you have a blober client is as simple as:

let transaction_outcomes = data_anchor_client.upload_blob(data, fee, blober_id, timeout).await?;
  • The data is a slice of bytes (&[u8]) to upload
  • The fee is a fee strategy for how much you want to send as the priority fee
  • The blober_id is the blober PDA (namespace) you want to upload to
  • The timeout is an optional parameter which specifies how long to wait before discarding a started data upload

The transaction outcomes is a vector of TransactionOutcome enum structs which contain the success state (successfull, failed or unknown) and in case of success the transaction signature and slot at which the transaction landed.

Estimating fees

Before uploading a blob you can estimate the expected cost using estimate_fees:

let priority = Priority::default();
let expected_fees = data_anchor_client
    .estimate_fees(data.len(), blober_pubkey, priority)
    .await?;
println!("Estimated lamports: {}", expected_fees.total_fee());

Querying data

To later retrieve the data that was uploaded, you can either do it from the ledger directly:

let blob = data_anchor_client
    .get_ledger_blobs_from_signatures(blober, signatures)
    .await?;

Where the signatures are the list of signatures you got by sending the upload request.

let blobs = data_anchor_client.get_ledger_blobs(slot, blober, lookback_slots).await?;

Where the slot is the slot at which the upload was finalized and lookback_slots is an optional parameter to limit how many slots before the slot to fetch in the past.

Or from the indexer service with:

let blobs = data_anchor_client.get_blobs(slot, blober).await?;

And getting the indexer proofs (these prove that the indexer is sending you valid data):

let proof = data_anchor_client.get_slot_proof(slot, blober).await?;

Complete workflow

The following snippet demonstrates creating a blober, uploading data and fetching it back from the ledger:

use std::{sync::Arc, time::Duration};
use data_anchor_client::{DataAnchorClient, FeeStrategy};
use solana_cli_config::Config;
use solana_keypair::Keypair;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let payer = Arc::new(Keypair::new());
    let client = DataAnchorClient::builder()
        .payer(payer.clone())
        .program_id(data_anchor_blober::id())
        .build_with_config(Config::default())
        .await?;

    let ns = "example";
    client.initialize_blober(FeeStrategy::default(), ns, None).await?;

    let blob = b"hello world";
    let outcomes = client
        .upload_blob(blob, FeeStrategy::default(), ns, Some(Duration::from_secs(10)))
        .await?;

    let sigs = outcomes.iter().map(|o| o.signature).collect::<Vec<_>>();
    let recovered = client
        .get_ledger_blobs_from_signatures(ns.into(), sigs)
        .await?;
    assert_eq!(blob.to_vec(), recovered);
    Ok(())
}

For more details, check out the docs.

API reference

The following table contains small examples for the public methods provided by DataAnchorClient. Every function is asynchronous and returns a DataAnchorClientResult.

Blober management

let ns = "example";
client.initialize_blober(FeeStrategy::default(), ns, None).await?;
client.close_blober(FeeStrategy::default(), ns, None).await?;

Upload helpers

let blob_pubkey = Pubkey::new_unique();
client.upload_blob(data, FeeStrategy::default(), ns, None).await?;
client.discard_blob(FeeStrategy::default(), blob_pubkey, ns, None).await?;
client.estimate_fees(data.len(), blob_pubkey, Priority::default()).await?;

Ledger queries

client.get_ledger_blobs_from_signatures(ns.into(), signatures).await?;
client.get_ledger_blobs(slot, ns.into(), None).await?;
client.get_blob_messages(slot, ns.into()).await?;

Indexer queries

client.get_blobs(slot, ns.into()).await?;
client.get_blobs_by_blober(ns.into(), None).await?;
client.get_blobs_by_payer(payer_pubkey, network_name.clone(), None).await?;
client.get_blobs_by_network(network_name.clone(), time_range).await?;
client.get_blobs_by_namespace_for_payer(ns.into(), Some(payer_pubkey), time_range).await?;
client.get_proof(slot, ns.into()).await?;
client.get_proof_for_blob(blob_pubkey).await?;

Builder helpers

let client = DataAnchorClient::builder()
    .payer(payer)
    .program_id(program_id)
    .indexer_from_url(indexer_url, None)
    .await?
    .with_helius_fee_estimate()
    .build_with_config(Config::default())
    .await?;
Commit count: 240

cargo fmt