use clap::Parser;
#[derive(Debug, Parser)]
#[clap(version, about, author)]
pub struct NautilusCli {
#[clap(subcommand)]
pub command: Commands,
}
#[derive(Parser, Debug)]
pub enum Commands {
Database(DatabaseOpt),
#[cfg(feature = "defi")]
Blockchain(BlockchainOpt),
}
#[derive(Parser, Debug)]
#[command(about = "Postgres database operations", long_about = None)]
pub struct DatabaseOpt {
#[clap(subcommand)]
pub command: DatabaseCommand,
}
#[derive(Parser, Debug, Clone)]
pub struct DatabaseConfig {
#[arg(long)]
pub host: Option<String>,
#[arg(long)]
pub port: Option<u16>,
#[arg(long)]
pub username: Option<String>,
#[arg(long)]
pub database: Option<String>,
#[arg(long)]
pub password: Option<String>,
#[arg(long)]
pub schema: Option<String>,
}
#[derive(Parser, Debug, Clone)]
#[command(about = "Postgres database operations", long_about = None)]
pub enum DatabaseCommand {
Init(DatabaseConfig),
Drop(DatabaseConfig),
}
#[cfg(feature = "defi")]
#[derive(Parser, Debug)]
#[command(about = "Blockchain operations", long_about = None)]
pub struct BlockchainOpt {
#[clap(subcommand)]
pub command: BlockchainCommand,
}
#[cfg(feature = "defi")]
#[derive(Parser, Debug, Clone)]
#[command(about = "Blockchain operations", long_about = None)]
pub enum BlockchainCommand {
SyncBlocks {
#[arg(long)]
chain: String,
#[arg(long)]
from_block: Option<u64>,
#[arg(long)]
to_block: Option<u64>,
#[clap(flatten)]
database: DatabaseConfig,
},
SyncDex {
#[arg(long)]
chain: String,
#[arg(long)]
dex: String,
#[arg(long)]
rpc_url: Option<String>,
#[arg(long)]
reset: bool,
#[arg(long)]
multicall_calls_per_rpc_request: Option<u32>,
#[clap(flatten)]
database: DatabaseConfig,
},
AnalyzePool {
#[arg(long)]
chain: String,
#[arg(long)]
dex: String,
#[arg(long)]
address: String,
#[arg(long)]
from_block: Option<u64>,
#[arg(long)]
to_block: Option<u64>,
#[arg(long)]
rpc_url: Option<String>,
#[arg(long)]
reset: bool,
#[arg(long)]
multicall_calls_per_rpc_request: Option<u32>,
#[clap(flatten)]
database: DatabaseConfig,
},
AnalyzePools {
#[arg(long)]
chain: String,
#[arg(long)]
dex: String,
#[arg(long = "address")]
addresses: Vec<String>,
#[arg(long)]
addresses_file: Option<String>,
#[arg(long)]
from_block: Option<u64>,
#[arg(long)]
to_block: Option<u64>,
#[arg(long)]
rpc_url: Option<String>,
#[arg(long)]
reset: bool,
#[arg(long)]
multicall_calls_per_rpc_request: Option<u32>,
#[clap(flatten)]
database: DatabaseConfig,
},
}
#[cfg(all(test, feature = "defi"))]
mod tests {
use clap::Parser;
use rstest::rstest;
use super::*;
#[rstest]
fn analyze_pools_cli_parses_repeated_addresses_file_and_shared_options() {
let cli = NautilusCli::try_parse_from([
"nautilus",
"blockchain",
"analyze-pools",
"--chain",
"ethereum",
"--dex",
"UniswapV3",
"--address",
"0x1111111111111111111111111111111111111111",
"--address",
"0x2222222222222222222222222222222222222222",
"--addresses-file",
"/tmp/pools.txt",
"--from-block",
"100",
"--to-block",
"200",
"--rpc-url",
"http://localhost:8545",
"--reset",
"--multicall-calls-per-rpc-request",
"25",
"--host",
"localhost",
"--port",
"5433",
"--username",
"postgres",
"--database",
"nautilus",
"--password",
"secret",
])
.unwrap();
match cli.command {
Commands::Blockchain(BlockchainOpt {
command:
BlockchainCommand::AnalyzePools {
chain,
dex,
addresses,
addresses_file,
from_block,
to_block,
rpc_url,
reset,
multicall_calls_per_rpc_request,
database,
},
}) => {
assert_eq!(chain, "ethereum");
assert_eq!(dex, "UniswapV3");
assert_eq!(
addresses,
vec![
"0x1111111111111111111111111111111111111111".to_string(),
"0x2222222222222222222222222222222222222222".to_string(),
]
);
assert_eq!(addresses_file.as_deref(), Some("/tmp/pools.txt"));
assert_eq!(from_block, Some(100));
assert_eq!(to_block, Some(200));
assert_eq!(rpc_url.as_deref(), Some("http://localhost:8545"));
assert!(reset);
assert_eq!(multicall_calls_per_rpc_request, Some(25));
assert_eq!(database.host.as_deref(), Some("localhost"));
assert_eq!(database.port, Some(5433));
assert_eq!(database.username.as_deref(), Some("postgres"));
assert_eq!(database.database.as_deref(), Some("nautilus"));
assert_eq!(database.password.as_deref(), Some("secret"));
assert_eq!(database.schema, None);
}
_ => panic!("Expected analyze-pools blockchain command"),
}
}
}