use crate::client::Client;
use crate::service::submit::Wait;
use crate::service::trade::{self, TradeInput};
use crate::signer::Signer;
use comfy_table::{presets::UTF8_FULL_CONDENSED, Table};
use eyre::Result;
use std::sync::Arc;
pub struct Args {
pub chain_id: String,
pub from: String,
pub to: String,
pub amount: String,
pub slippage: Option<u16>,
pub min_out: Option<String>,
pub max_amount: Option<String>,
pub mode: String,
pub proxy: String,
pub nonce: Option<String>,
pub deadline_secs: Option<u64>,
pub dry_run: bool,
pub self_submit: bool,
pub json: bool,
}
pub async fn run(
client: &Client,
signer: Arc<dyn Signer>,
args: Args,
allow_trade: bool,
) -> Result<()> {
let json = args.json;
crate::tokens::chain_name_to_id(&args.chain_id)
.ok_or_else(|| eyre::eyre!("{}", crate::tokens::unknown_chain_id(&args.chain_id)))?;
let outcome = trade::execute_trade(client, signer, input(args), allow_trade, Wait::CLI).await?;
if outcome.dry_run || outcome.self_submit.is_some() {
print_outcome(&outcome, json)?;
}
outcome.not_confirmed().map_or(Ok(()), |failure| Err(failure.into()))
}
fn input(args: Args) -> TradeInput {
TradeInput {
chain_id: args.chain_id,
from: args.from,
to: args.to,
amount: args.amount,
slippage: args.slippage,
min_out: args.min_out,
max_amount: args.max_amount,
mode: args.mode,
proxy: args.proxy,
nonce: args.nonce,
deadline_secs: args.deadline_secs,
dry_run: args.dry_run,
self_submit: args.self_submit,
verify_quote: true,
}
}
#[test]
fn cli_trade_keeps_quote_verification_enabled() {
let trade = input(Args {
chain_id: "base".into(), from: "USDC".into(), to: "WETH".into(), amount: "1".into(),
slippage: None, min_out: None, max_amount: None, mode: "agent-order".into(),
proxy: alloy::primitives::Address::repeat_byte(2).to_string(), nonce: None,
deadline_secs: None, dry_run: true, self_submit: false, json: false,
});
assert!(trade.verify_quote);
}
fn print_outcome(outcome: &trade::TradeOutcome, json: bool) -> Result<()> {
if json {
println!("{}", serde_json::to_string_pretty(outcome)?);
return Ok(());
}
let mut table = Table::new();
table.load_preset(UTF8_FULL_CONDENSED);
table.set_header(vec!["AgentSwap Trade", ""]);
table.add_row(vec!["Mode", outcome.mode.as_str()]);
table.add_row(vec!["Dry Run", &outcome.dry_run.to_string()]);
table.add_row(vec!["Digest", outcome.digest.as_str()]);
table.add_row(vec!["Agent", outcome.order.agent.as_str()]);
table.add_row(vec!["Router", outcome.order.router.as_str()]);
table.add_row(vec!["Token In", outcome.order.token_in.as_str()]);
table.add_row(vec!["Amount In", outcome.order.amount_in.as_str()]);
table.add_row(vec!["Token Out", outcome.order.token_out.as_str()]);
table.add_row(vec!["Min Out", outcome.order.min_out.as_str()]);
if let Some(preview) = &outcome.self_submit {
table.add_row(vec!["Self Submit To", preview.to.as_str()]);
table.add_row(vec!["Self Submit Calldata", preview.calldata.as_str()]);
if let Some(hash) = &preview.tx_hash {
table.add_row(vec!["Self Submit Tx", hash.as_str()]);
crate::display::add_tx_status_rows(&mut table, preview.tx_status, preview.tx_error.as_deref());
if let Some(url) = &preview.tx_explorer_url {
table.add_row(vec!["Explorer", url.as_str()]);
}
}
}
println!("{table}");
Ok(())
}