Problem
config/fork.toml bakes in [liquidator.bnb].contract_address = 0x5FbDB2315678afecb367f032d93F642f64180aa3, valid only when dev-account-0 nonce was 0 at deploy time. If the operator uses CHARON_SKIP_DEV0_NONCE_RESET=1 or a non-default signer, the deploy lands at a different address. The bot starts cleanly, the simulator returns Reverted for every position (because latest has empty bytecode at the baked address), and the operator has no signal that the deploy and the config disagree.
Evidence
crates/charon-cli/src/main.rs:1031-1074 builds the harness with liq_cfg.contract_address without ever calling provider.get_code(address, latest). The simulator at crates/charon-executor/src/simulation.rs:96-134 issues eth_call and gets a generic revert without distinguishing "wrong contract" from "wrong calldata".
scripts/anvil_fork.sh:296-312 shows the nonce-reset is best-effort and emits only a WARNING line on failure.
Proposed fix
At startup, after the Aave AddressesProvider check, fetch provider.get_code(liq_cfg.contract_address, latest):
- if empty (
0x), fail startup with liquidator contract not deployed at <addr> on chain <chain> — re-run forge create or update [liquidator.<chain>].contract_address.
- (optional) compare a 32-byte fingerprint (e.g. last 32 bytes of bytecode) against a checked-in
out/CharonLiquidator.sol/CharonLiquidator.json fingerprint. Mismatch -> warn, do not abort.
Acceptance criteria
Severity
medium
Problem
config/fork.tomlbakes in[liquidator.bnb].contract_address = 0x5FbDB2315678afecb367f032d93F642f64180aa3, valid only when dev-account-0 nonce was 0 at deploy time. If the operator usesCHARON_SKIP_DEV0_NONCE_RESET=1or a non-default signer, the deploy lands at a different address. The bot starts cleanly, the simulator returnsRevertedfor every position (becauselatesthas empty bytecode at the baked address), and the operator has no signal that the deploy and the config disagree.Evidence
crates/charon-cli/src/main.rs:1031-1074builds the harness withliq_cfg.contract_addresswithout ever callingprovider.get_code(address, latest). The simulator atcrates/charon-executor/src/simulation.rs:96-134issueseth_calland gets a generic revert without distinguishing "wrong contract" from "wrong calldata".scripts/anvil_fork.sh:296-312shows the nonce-reset is best-effort and emits only aWARNINGline on failure.Proposed fix
At startup, after the Aave AddressesProvider check, fetch
provider.get_code(liq_cfg.contract_address, latest):0x), fail startup withliquidator contract not deployed at <addr> on chain <chain> — re-run forge create or update [liquidator.<chain>].contract_address.out/CharonLiquidator.sol/CharonLiquidator.jsonfingerprint. Mismatch -> warn, do not abort.Acceptance criteria
listenaborts with a clear message when the configured liquidator address has empty bytecode on the connected chain.0xforget_code.Severity
medium