Contractless/src/bin/lookup_local_balance.rs

90 lines
2.8 KiB
Rust
Raw Normal View History

2026-05-24 17:56:57 +00:00
use blockchain::env;
use blockchain::fs;
use blockchain::tilde;
use rustyline::completion::FilenameCompleter;
use rustyline::error::ReadlineError;
use rustyline::{history::DefaultHistory, CompletionType, Config, Editor};
use rustyline_derive::Completer;
use rustyline_derive::Helper as RustyHelper;
use rustyline_derive::Highlighter as RustyHighlighter;
use rustyline_derive::Hinter as RustyHinter;
use rustyline_derive::Validator as RustyValidator;
fn format_balance(balance: u64) -> String {
// Balance files store atomic units; display as whole coins with 8 decimals.
let whole = balance / 100_000_000;
let fractional = balance % 100_000_000;
format!("{whole}.{fractional:08}")
}
#[derive(RustyHelper, Completer, RustyHinter, RustyHighlighter, RustyValidator)]
struct PathHelper {
#[rustyline(Completer)]
completer: FilenameCompleter,
}
fn prompt_for_path(prompt: &str) -> Result<String, String> {
// Rustyline provides path completion for interactive balance-file lookup.
let config = Config::builder()
.completion_type(CompletionType::List)
.build();
let mut editor =
Editor::<PathHelper, DefaultHistory>::with_config(config).map_err(|e| e.to_string())?;
editor.set_helper(Some(PathHelper {
completer: FilenameCompleter::new(),
}));
match editor.readline(prompt) {
Ok(line) => Ok(line.trim().to_string()),
Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => {
Err("Input cancelled".to_string())
}
Err(err) => Err(format!("Failed to read balance file path: {err}")),
}
}
#[tokio::main]
async fn main() {
// The tool accepts a balance file path as an arg or prompts with completion.
let args: Vec<String> = env::args().collect();
if args.len() > 1 && args.len() != 2 {
eprintln!("Usage: ./lookup_local_balance <path/to/file.bal>");
return;
}
let balance_file_path = if args.len() == 2 {
args[1].clone()
} else {
match prompt_for_path("Please enter the path to the balance file: ") {
Ok(path) => path,
Err(err) => {
eprintln!("{err}");
return;
}
}
};
// Allow users to type paths with ~ and read the balance bytes from disk.
let expanded_path = tilde(&balance_file_path).to_string();
let bytes = match fs::read(&expanded_path) {
Ok(bytes) => bytes,
Err(err) => {
eprintln!("Error reading file: {err}");
return;
}
};
if bytes.len() < 8 {
eprintln!("Error: File should have at least 8 bytes of data");
return;
}
// The first 8 bytes are the little-endian u64 balance value.
let mut buffer = [0u8; 8];
buffer.copy_from_slice(&bytes[..8]);
let value = u64::from_le_bytes(buffer);
println!("{}", format_balance(value));
}