xforth 0.1.0

CLI tool for bootstrapping x402 Solana projects.
Documentation
use solana_sdk::signature::Keypair;
use anyhow::{Result, Context};
use colored::Colorize;
use std::env;

/// Generate a new Solana keypair
pub fn generate_keypair() -> Keypair {
    Keypair::new()
}

/// Convert keypair to JSON array format for .env storage
pub fn keypair_to_json(keypair: &Keypair) -> String {
    let bytes = keypair.to_bytes();
    serde_json::to_string(&bytes.to_vec()).unwrap()
}

/// Load keypair from JSON array string
pub fn keypair_from_json(json_str: &str) -> Result<Keypair> {
    let bytes: Vec<u8> = serde_json::from_str(json_str)
        .context("Failed to parse keypair JSON")?;

    // Solana SDK 3.0: keypair is 64 bytes (secret key 32 + public key 32)
    // Use new_from_array which takes only the secret key (first 32 bytes)
    if bytes.len() != 64 {
        return Err(anyhow::anyhow!("Invalid keypair bytes length: expected 64, got {}", bytes.len()));
    }

    let mut secret_key = [0u8; 32];
    secret_key.copy_from_slice(&bytes[..32]);
    Ok(Keypair::new_from_array(secret_key))
}

/// Load keypair from environment variable
pub fn load_keypair_from_env(env_var: &str) -> Result<Keypair> {
    let json_str = env::var(env_var)
        .context(format!("Environment variable {} not found", env_var))?;
    keypair_from_json(&json_str)
}

/// Logging functions with colored output
pub fn log_action(msg: &str) {
    println!("{} {}", "Action:".green().bold(), msg);
}

pub fn log_info(msg: &str) {
    println!("{} \"{}\"", "Log:".yellow(), msg);
}

#[allow(dead_code)]
pub fn log_error(msg: &str) {
    eprintln!("{} {}", "Error:".red().bold(), msg);
}

pub fn log_balance(label: &str, balance: f64) {
    println!("{}: {} SOL", label, balance);
}

/// JSON output for programmatic consumption
pub fn output_json(data: &serde_json::Value) {
    println!("{}", serde_json::to_string_pretty(data).unwrap());
}

/// Truncate public key for display (first 4 chars...last 4 chars)
pub fn truncate_pubkey(pubkey: &str) -> String {
    if pubkey.len() > 8 {
        format!("{}...{}", &pubkey[..4], &pubkey[pubkey.len()-4..])
    } else {
        pubkey.to_string()
    }
}