Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
406 changes: 4 additions & 402 deletions Cargo.lock

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "nest-cli"
version = "0.2.0"
version = "0.2.1"
edition = "2024"
description = "CLI and TUI for Nest Vaults on Plume Network"
license = "MIT"
Expand Down Expand Up @@ -30,15 +30,15 @@ tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"

# Self-update
self_update = { version = "0.43", features = ["archive-tar", "archive-zip", "compression-flate2"] }

# Utilities
dirs = "6"
dotenvy = "0.15"
eyre = "0.6"
color-eyre = "0.6"
hex = "0.4"
sha2 = "0.10"
flate2 = "1"
tar = "0.4"
chrono = { version = "0.4", features = ["serde"] }

[dev-dependencies]
Expand Down
173 changes: 159 additions & 14 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,8 @@ pub struct ComplianceArgs {
#[derive(Args)]
pub struct HistoryArgs {
/// Vault slug
#[arg(long)]
pub vault_slug: String,
#[arg(long, visible_alias = "vault-slug")]
pub vault: String,

/// Days of history
#[arg(long, default_value_t = 30)]
Expand Down Expand Up @@ -278,8 +278,9 @@ pub struct ClaimPendingArgs {
pub redemption_asset: Option<String>,
#[arg(long, default_value = "plume")]
pub chain: String,
#[arg(long)]
pub user: Option<String>,
/// Wallet address (overrides address derived from --private-key)
#[arg(long, visible_alias = "user")]
pub address: Option<String>,
}
#[derive(Args)]
pub struct ClaimSubmitArgs {
Expand All @@ -289,8 +290,9 @@ pub struct ClaimSubmitArgs {
pub redemption_asset: String,
#[arg(long, default_value = "plume")]
pub chain: String,
#[arg(long)]
pub user: Option<String>,
/// Wallet address (overrides address derived from --private-key)
#[arg(long, visible_alias = "user")]
pub address: Option<String>,
#[arg(long)]
pub skip_simulation: bool,
}
Expand Down Expand Up @@ -336,8 +338,9 @@ pub struct InstantRedeemSubmitArgs {
pub shares: String,
#[arg(long, default_value = "plume")]
pub chain: String,
#[arg(long)]
pub user: Option<String>,
/// Wallet address (overrides address derived from --private-key)
#[arg(long, visible_alias = "user")]
pub address: Option<String>,
#[arg(long)]
pub receiver: Option<String>,
#[arg(long)]
Expand All @@ -362,8 +365,9 @@ pub struct UpdateRedeemQuery {
pub redemption_asset: String,
#[arg(long, default_value = "plume")]
pub chain: String,
#[arg(long)]
pub user: Option<String>,
/// Wallet address (overrides address derived from --private-key)
#[arg(long, visible_alias = "user")]
pub address: Option<String>,
}
#[derive(Args)]
pub struct UpdateRedeemSubmit {
Expand All @@ -373,8 +377,9 @@ pub struct UpdateRedeemSubmit {
pub redemption_asset: String,
#[arg(long, default_value = "plume")]
pub chain: String,
#[arg(long)]
pub user: Option<String>,
/// Wallet address (overrides address derived from --private-key)
#[arg(long, visible_alias = "user")]
pub address: Option<String>,
/// Final reduced pending-share total (reduce-only)
#[arg(long)]
pub new_shares: String,
Expand All @@ -397,8 +402,148 @@ pub enum AutoClaimAction {
pub struct AutoClaimQuery {
#[arg(long, default_value = "plume")]
pub chain: String,
#[arg(long)]
pub user: Option<String>,
/// Wallet address (overrides address derived from --private-key)
#[arg(long, visible_alias = "user")]
pub address: Option<String>,
#[arg(long)]
pub skip_simulation: bool,
}

#[cfg(test)]
mod tests {
use super::*;

fn parse(args: &[&str]) -> Cli {
Cli::try_parse_from(args).expect("parse failed")
}

#[test]
fn claim_pending_accepts_user_alias() {
// Both the new --address and the legacy --user resolve to the same field.
for flag in ["--user", "--address"] {
let cli = parse(&["nest", "claim", "pending", flag, "0xABC"]);
let Some(Commands::Claim(a)) = cli.command else {
panic!("expected claim")
};
let ClaimAction::Pending(q) = a.action else {
panic!("expected pending")
};
assert_eq!(q.address.as_deref(), Some("0xABC"));
}
}

#[test]
fn claim_submit_accepts_user_alias() {
let cli = parse(&[
"nest",
"claim",
"submit",
"--vault",
"v",
"--redemption-asset",
"0xR",
"--user",
"0xABC",
]);
let Some(Commands::Claim(a)) = cli.command else {
panic!()
};
let ClaimAction::Submit(s) = a.action else {
panic!()
};
assert_eq!(s.address.as_deref(), Some("0xABC"));
}

#[test]
fn instant_redeem_submit_accepts_user_alias() {
let cli = parse(&[
"nest",
"instant-redeem",
"submit",
"--vault",
"v",
"--redemption-asset",
"0xR",
"--shares",
"1",
"--user",
"0xABC",
]);
let Some(Commands::InstantRedeem(a)) = cli.command else {
panic!()
};
let InstantRedeemAction::Submit(s) = a.action else {
panic!()
};
assert_eq!(s.address.as_deref(), Some("0xABC"));
}

#[test]
fn update_redeem_pending_accepts_user_alias() {
let cli = parse(&[
"nest",
"update-redeem",
"pending",
"--vault",
"v",
"--redemption-asset",
"0xR",
"--user",
"0xABC",
]);
let Some(Commands::UpdateRedeem(a)) = cli.command else {
panic!()
};
let UpdateRedeemAction::Pending(q) = a.action else {
panic!()
};
assert_eq!(q.address.as_deref(), Some("0xABC"));
}

#[test]
fn update_redeem_submit_accepts_user_alias() {
let cli = parse(&[
"nest",
"update-redeem",
"submit",
"--vault",
"v",
"--redemption-asset",
"0xR",
"--new-shares",
"1",
"--user",
"0xABC",
]);
let Some(Commands::UpdateRedeem(a)) = cli.command else {
panic!()
};
let UpdateRedeemAction::Submit(s) = a.action else {
panic!()
};
assert_eq!(s.address.as_deref(), Some("0xABC"));
}

#[test]
fn auto_claim_status_accepts_user_alias() {
let cli = parse(&["nest", "auto-claim", "status", "--user", "0xABC"]);
let Some(Commands::AutoClaim(a)) = cli.command else {
panic!()
};
let AutoClaimAction::Status(q) = a.action else {
panic!()
};
assert_eq!(q.address.as_deref(), Some("0xABC"));
}

#[test]
fn history_accepts_vault_slug_alias() {
for flag in ["--vault", "--vault-slug"] {
let cli = parse(&["nest", "history", flag, "myvault"]);
let Some(Commands::History(h)) = cli.command else {
panic!()
};
assert_eq!(h.vault, "myvault");
}
}
}
4 changes: 2 additions & 2 deletions src/commands/auto_claim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub async fn run(cfg: &AppConfig, args: AutoClaimArgs) -> Result<()> {
async fn status(cfg: &AppConfig, q: AutoClaimQuery) -> Result<()> {
let chain_id = resolve_chain_id(&q.chain)?;
ensure_actions_chain(chain_id)?;
let account = resolve_account(cfg, &q.user)?;
let account = resolve_account(cfg, &q.address)?;
let actions = EvmActionsClient::new(&cfg.evm_actions_api_url);
let req = AutoClaimStatusRequest {
chain_id,
Expand All @@ -34,7 +34,7 @@ async fn status(cfg: &AppConfig, q: AutoClaimQuery) -> Result<()> {
async fn set(cfg: &AppConfig, q: AutoClaimQuery, enabled: bool) -> Result<()> {
let chain_id = resolve_chain_id(&q.chain)?;
ensure_actions_chain(chain_id)?;
let account = resolve_account(cfg, &q.user)?;
let account = resolve_account(cfg, &q.address)?;
let actions = EvmActionsClient::new(&cfg.evm_actions_api_url);
let req = AutoClaimBuildTxRequest {
chain_id,
Expand Down
4 changes: 2 additions & 2 deletions src/commands/claim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub async fn run(cfg: &AppConfig, args: ClaimArgs) -> Result<()> {

async fn pending(cfg: &AppConfig, q: ClaimPendingArgs) -> Result<()> {
let chain_id = resolve_chain_id(&q.chain)?;
let account = resolve_account(cfg, &q.user)?;
let account = resolve_account(cfg, &q.address)?;

match q.vault {
// Single vault → the API claim/pending route (structured response).
Expand Down Expand Up @@ -143,7 +143,7 @@ async fn sweep_all(cfg: &AppConfig, chain_id: u64, account: Address) -> Result<(
async fn submit(cfg: &AppConfig, s: ClaimSubmitArgs) -> Result<()> {
let chain_id = resolve_chain_id(&s.chain)?;
ensure_actions_chain(chain_id)?;
let account = resolve_account(cfg, &s.user)?;
let account = resolve_account(cfg, &s.address)?;
let asset: Address = s
.redemption_asset
.parse()
Expand Down
4 changes: 2 additions & 2 deletions src/commands/history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ pub async fn run(cfg: &AppConfig, args: HistoryArgs) -> Result<()> {

let api = NestApiClient::new(&cfg.api_url);
let history = api
.get_performance_history(&args.vault_slug, start_date, now)
.get_performance_history(&args.vault, start_date, now)
.await?;

let points = &history.history;

if points.is_empty() {
println!("No history data for '{}'.", args.vault_slug);
println!("No history data for '{}'.", args.vault);
return Ok(());
}

Expand Down
2 changes: 1 addition & 1 deletion src/commands/instant_redeem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ async fn liquidity(cfg: &AppConfig, a: InstantRedeemLiquidityArgs) -> Result<()>
async fn submit(cfg: &AppConfig, a: InstantRedeemSubmitArgs) -> Result<()> {
let chain_id = resolve_chain_id(&a.chain)?;
ensure_actions_chain(chain_id)?;
let account = resolve_account(cfg, &a.user)?;
let account = resolve_account(cfg, &a.address)?;
let asset: Address = a
.redemption_asset
.parse()
Expand Down
Loading
Loading