Problem
On a misconfigured fork where the liquidator address has no bytecode, every opportunity drops at the simulation stage with a generic record_opportunity_dropped_reason(SIM_REVERT). There is no signal in the dashboard separating "the liquidation logic reverted" from "the contract isn't deployed at the address we're calling". Operators staring at a quiet Grafana cannot tell which problem they have.
Evidence
crates/charon-cli/src/main.rs:2016-2022:
if let Err(err) = gate.encode_and_simulate(&opp, ¶ms).await {
charon_metrics::record_simulation(chain, sim_result::REVERT);
charon_metrics::record_opportunity_dropped(chain, drop_stage::SIMULATION);
charon_metrics::record_opportunity_dropped_reason(chain, drop_reason::SIM_REVERT);
...
}
Proposed fix
Detect the empty-bytecode case once at startup (paired bytecode-check issue) and refuse to start; and add a drop_reason::LIQUIDATOR_NOT_DEPLOYED so a contract that gets self-destructed mid-run still surfaces a distinct counter. Update Grafana's "Executor — opportunities queued vs dropped" panel to break out drops by reason as well as stage.
Acceptance criteria
Severity
medium (low impact once startup bytecode check lands; covers runtime self-destruct edge case)
Problem
On a misconfigured fork where the liquidator address has no bytecode, every opportunity drops at the simulation stage with a generic
record_opportunity_dropped_reason(SIM_REVERT). There is no signal in the dashboard separating "the liquidation logic reverted" from "the contract isn't deployed at the address we're calling". Operators staring at a quiet Grafana cannot tell which problem they have.Evidence
crates/charon-cli/src/main.rs:2016-2022:Proposed fix
Detect the empty-bytecode case once at startup (paired bytecode-check issue) and refuse to start; and add a
drop_reason::LIQUIDATOR_NOT_DEPLOYEDso a contract that gets self-destructed mid-run still surfaces a distinct counter. Update Grafana's "Executor — opportunities queued vs dropped" panel to break out drops by reason as well as stage.Acceptance criteria
drop_reasonconstant added incharon-metrics.simulatereturns the well-known "no code at address" revert payload.Severity
medium (low impact once startup bytecode check lands; covers runtime self-destruct edge case)