mod commands;
mod format;
use clap::{CommandFactory, Parser, Subcommand};
use clap_complete::{generate, Shell};
use format::OutputFormat;
#[derive(Parser)]
#[command(
name = "percli",
about = "Offline simulator for the Percolator risk engine",
long_about = "Simulate haircuts, liquidations, margin checks, and conservation proofs\nfor the Percolator risk engine — no chain required.",
version
)]
struct Cli {
#[command(subcommand)]
command: Commands,
#[arg(long, short, global = true)]
format: Option<OutputFormat>,
}
#[derive(Subcommand)]
enum Commands {
Init {
#[arg(long, default_value = "basic")]
template: String,
},
Sim {
path: String,
#[arg(long)]
step_by_step: bool,
#[arg(long)]
no_check_conservation: bool,
#[arg(long, short)]
verbose: bool,
#[arg(long = "override", value_name = "KEY=VALUE")]
overrides: Vec<String>,
},
Step {
#[arg(long)]
state: String,
#[command(subcommand)]
action: StepAction,
},
Query {
#[arg(long)]
state: String,
metric: String,
#[arg(long)]
account: Option<String>,
},
Inspect {
path: String,
},
Completions {
shell: Shell,
},
}
#[derive(Subcommand)]
enum StepAction {
Deposit { account: String, amount: u128 },
Withdraw { account: String, amount: u128 },
Trade {
long: String,
short: String,
#[arg(long)]
size: i128,
#[arg(long)]
price: u64,
},
Crank {
#[arg(long)]
oracle: u64,
#[arg(long)]
slot: u64,
},
Liquidate { account: String },
Settle { account: String },
SetOracle { price: u64 },
SetSlot { slot: u64 },
SetFundingRate { rate: i64 },
}
fn main() -> anyhow::Result<()> {
let cli = Cli::parse();
let fmt = cli.format.unwrap_or_else(OutputFormat::from_env);
match cli.command {
Commands::Init { template } => commands::init::run(&template),
Commands::Sim {
path,
step_by_step,
no_check_conservation,
verbose,
overrides,
} => commands::sim::run(
&path,
fmt,
step_by_step,
!no_check_conservation,
verbose,
&overrides,
),
Commands::Step { state, action } => commands::step::run(&state, action, fmt),
Commands::Query {
state,
metric,
account,
} => commands::query::run(&state, &metric, account.as_deref(), fmt),
Commands::Inspect { path } => commands::inspect::run(&path),
Commands::Completions { shell } => {
let mut cmd = Cli::command();
generate(shell, &mut cmd, "percli", &mut std::io::stdout());
Ok(())
}
}
}