txline 0.3.0

Devnet-only Rust SDK for TxLINE.
Documentation
//! Devnet-only legacy score stat-validation example.
//!
//! Required:
//! - `TXLINE_DEVNET_JWT`
//! - `TXLINE_DEVNET_API_TOKEN`
//! - `TXLINE_FIXTURE_ID`
//! - `TXLINE_SCORE_SEQ`
//! - `TXLINE_STAT_KEY`
//!
//! Optional:
//! - `TXLINE_STAT_KEY2`
//! - `TXLINE_VALIDATE_ON_CHAIN=1`
//! - `TXLINE_WALLET` or `ANCHOR_WALLET`

use std::env;

use solana_sdk::signature::read_keypair_file;
use txline::solana::validation::ValidationSimulationConfig;
use txline::validation::{Comparison, TraderPredicate};
use txline::{ApiToken, GuestJwt, TxlineClient, TxlineConfig};

#[tokio::main]
async fn main() -> txline::Result<()> {
    let Some((jwt, api_token)) = read_auth() else {
        eprintln!("Set TXLINE_DEVNET_JWT and TXLINE_DEVNET_API_TOKEN first.");
        return Ok(());
    };
    let Some((fixture_id, seq, stat_key, stat_key2)) = read_request() else {
        eprintln!(
            "Set TXLINE_FIXTURE_ID, TXLINE_SCORE_SEQ, and TXLINE_STAT_KEY from a real score record."
        );
        return Ok(());
    };

    let client = TxlineClient::new(TxlineConfig::devnet())?;
    client.set_guest_jwt(jwt);
    client.set_api_token(api_token);

    let proof = client
        .scores()
        .stat_validation_legacy(fixture_id, seq, stat_key, stat_key2)
        .await?;
    println!(
        "Legacy proof for fixture {} seq {} has {} stat proof nodes; epoch day {}",
        fixture_id,
        seq,
        proof.stat_proof.len(),
        proof.epoch_day()?
    );
    if should_simulate() {
        if let Some(wallet_path) = read_wallet_path() {
            let keypair = read_keypair_file(wallet_path).map_err(|err| {
                txline::TxlineError::Solana(format!("could not read wallet keypair: {err}"))
            })?;
            let predicate = TraderPredicate::new(0, Comparison::greater_than());
            let result = client.solana().simulate_validate_stat(
                &keypair,
                &proof,
                predicate,
                None,
                ValidationSimulationConfig::default(),
            )?;
            println!("On-chain validate_stat simulation returned {result}");
        } else {
            eprintln!("Set TXLINE_WALLET or ANCHOR_WALLET to run on-chain simulation.");
        }
    }
    Ok(())
}

fn read_auth() -> Option<(GuestJwt, ApiToken)> {
    let jwt = GuestJwt::new(env::var("TXLINE_DEVNET_JWT").ok()?).ok()?;
    let api_token = ApiToken::new(env::var("TXLINE_DEVNET_API_TOKEN").ok()?).ok()?;
    Some((jwt, api_token))
}

fn read_request() -> Option<(i64, i32, u32, Option<u32>)> {
    let fixture_id = env::var("TXLINE_FIXTURE_ID").ok()?.parse().ok()?;
    let seq = env::var("TXLINE_SCORE_SEQ").ok()?.parse().ok()?;
    let stat_key = env::var("TXLINE_STAT_KEY").ok()?.parse().ok()?;
    let stat_key2 = env::var("TXLINE_STAT_KEY2")
        .ok()
        .and_then(|value| value.parse().ok());
    Some((fixture_id, seq, stat_key, stat_key2))
}

fn should_simulate() -> bool {
    env::var("TXLINE_VALIDATE_ON_CHAIN").is_ok_and(|value| value == "1")
}

fn read_wallet_path() -> Option<String> {
    env::var("TXLINE_WALLET")
        .ok()
        .or_else(|| env::var("ANCHOR_WALLET").ok())
}