1pub mod amount;
28pub mod cli;
29pub mod commands;
30pub mod config;
31pub mod devnet;
32pub mod error;
33pub mod output;
34pub mod state;
35
36use std::io::IsTerminal as _;
37use std::process::ExitCode;
38
39use clap::Parser as _;
40
41use crate::cli::{Cli, Command};
42use crate::config::{Globals, Role};
43use crate::error::{CliResult, Exit};
44use crate::output::Output;
45
46pub const PROTOCOL_VERSION: &str = "1.1";
48
49pub fn main() -> ExitCode {
51 let cli = match Cli::try_parse() {
52 Ok(cli) => cli,
53 Err(e) => {
54 let _ = e.print();
55 return ExitCode::from(if e.use_stderr() { Exit::Usage.code() } else { Exit::Ok.code() });
56 }
57 };
58 init_tracing(&cli);
59 let out = Output { json: cli.global.json };
60 let runtime = match tokio::runtime::Builder::new_multi_thread().enable_all().build() {
61 Ok(runtime) => runtime,
62 Err(e) => {
63 out.error(&error::CliError::failed(format!("can't start the async runtime: {e}")));
64 return ExitCode::from(Exit::Failed.code());
65 }
66 };
67 let result = runtime.block_on(run(cli, out));
68 runtime.shutdown_timeout(std::time::Duration::from_secs(2));
70 match result {
71 Ok(exit) => ExitCode::from(exit.code()),
72 Err(e) => {
73 out.error(&e);
74 ExitCode::from(e.exit.code())
75 }
76 }
77}
78
79fn init_tracing(cli: &Cli) {
80 use tracing_subscriber::EnvFilter;
81 let default = match cli.global.verbose {
82 0 => "warn",
83 1 => "warn,paralock=info,paralock_evm=info,paralock_cli=info",
84 _ => "info,paralock=debug,paralock_evm=debug,paralock_cli=debug",
85 };
86 let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(default));
87 let _ = tracing_subscriber::fmt()
88 .with_env_filter(filter)
89 .with_writer(std::io::stderr)
90 .with_ansi(std::io::stderr().is_terminal())
91 .with_target(cli.global.verbose > 1)
92 .try_init();
93}
94
95pub async fn run(cli: Cli, out: Output) -> CliResult<Exit> {
97 let globals = Globals {
98 devnet: cli.global.devnet,
99 config: cli.global.config.clone(),
100 maker_url: cli.global.maker_url.clone(),
101 evm_account: cli.global.evm_account,
102 lightwalletd: cli.global.lightwalletd,
103 };
104 match cli.command {
105 Command::Version => {
106 out.say(format!(
107 "paralock {} (paralock-cli, protocol v{PROTOCOL_VERSION}; experimental, not audited)",
108 env!("CARGO_PKG_VERSION")
109 ));
110 out.result(serde_json::json!({ "version": env!("CARGO_PKG_VERSION"), "protocol": PROTOCOL_VERSION }));
111 Ok(Exit::Ok)
112 }
113 Command::Doctor(args) => {
114 let role = if args.maker { Role::Maker } else { Role::Taker };
115 let setup = config::load(&globals, role)?;
116 commands::doctor::doctor(&setup, out, args).await
117 }
118 Command::Quote(args) => commands::taker::quote(&config::load(&globals, Role::Taker)?, out, args).await,
119 Command::Swap(args) => commands::taker::swap(&config::load(&globals, Role::Taker)?, out, args).await,
120 Command::Pay(args) => commands::taker::pay(&config::load(&globals, Role::Taker)?, out, args).await,
121 Command::Swaps(args) => commands::taker::swaps(&config::load(&globals, Role::Taker)?, out, args),
122 Command::Resume(args) => commands::taker::resume(&config::load(&globals, Role::Taker)?, out, args).await,
123 Command::Refund(args) => commands::taker::refund(&config::load(&globals, Role::Taker)?, out, args).await,
124 Command::Maker(args) => commands::maker::maker(&config::load(&globals, Role::Maker)?, out, args).await,
125 }
126}