Wired up the /autotrade Telegram bot command handler in the autotrade-foundation branch, completing the command dispatch layer for the autotrade config-repo module.
What Was Built
commands.rs — crates/polymarket-fetch/src/pmv2/autotrade/commands.rs
Four new items added:
apply_set(param, value) -> Result<(&'static str, f64)>
Pure function. Calls validate_set then param_to_column, returns the resolved (column_name, validated_f64) tuple. Used by the SetParam arm in run_autotrade.
format_status(c: &AutotradeConfig) -> String
Formats the full AutotradeConfig row into a human-readable Telegram status string. BigDecimal fields format via their Display impl — no conversion needed.
run_autotrade(pool, args) -> String (async)
Top-level dispatcher. Calls parse_autotrade, then dispatches to:
config::load→ Status armconfig::update_numeric→ SetParam arm (viaapply_set)config::set_text→ SetMode / SetExit arms (viaset_text_reply)config::set_source_enabled→ Filter armconfig::set_text→ Maker arm (viaset_text_reply)
Always returns a reply String (errors are stringified, never propagated — the bot must always send something back).
set_text_reply (private async helper)
Shared by SetMode / SetExit / Filter / Maker arms to avoid repetition.
Test added: apply_set_ok_and_errors alongside the existing 2 tests.
Clippy gotcha
This project runs clippy with
-D clippy::unwrap_used. Test bodies using.unwrap()must be annotated with#[allow(clippy::unwrap_used)].
bot.rs — crates/polymarket-fetch/src/bot.rs
Added an "autotrade" match arm in run_command (around line 768):
"autotrade" => {
let reply = crate::pmv2::autotrade::commands::run_autotrade(&state.pool, &parsed.args).await;
send_with_timeout(&state.telegram, chat_id, &reply, None).await?;
Ok(())
}The owner-auth gate (scope_for("autotrade") -> Scope::Owner) was already present at the top of run_command from autotrade-authz-module. No second auth check was added — the single gate at the top of the match covers all arms uniformly.
Key Decisions & Gotchas
| Decision | Rationale |
|---|---|
run_autotrade returns String, never errors | Telegram dispatch must always reply; errors surface as user-readable strings |
send_with_timeout(..., None) — no parse_mode | Plain text; status output uses only printable ASCII |
BigDecimal via Display in format_status | AutotradeConfig stores NUMERIC as BigDecimal; {} formatter works out of the box |
c.mode / c.exit_mode are String, not enum | The DB column is text; AutotradeConfig stores them as String from sqlx |
| Auth gate NOT duplicated in the arm | scope_for("autotrade") in the preamble of run_command already blocks non-owners |
#[allow(clippy::unwrap_used)]required on all test fnsThe project-wide
-D clippy::unwrap_usedflag fires on test bodies too (--all-targetsincludes#[cfg(test)]). Every test function that calls.unwrap()must carry this allow attribute.
Test Results
cargo test -p polymarket-fetch autotrade::commands→ 3 passed (existing 2 + newapply_set_ok_and_errors)cargo fmt -p polymarket-fetch→ cleanbash scripts/gate.sh→ exit 0 (244 tests pass)
Related
- autotrade-config-repo — the
config.rslayer this module dispatches into - autotrade-authz-module —
scope_for("autotrade")auth gate wired atrun_commandtop - autotrade-engine-impl — engine the commands eventually drive
- autotrade-gates — gate chain used by the engine
- pmv2-autotrade-engine-design — overall auto-trade engine design spec