Refs #42
PR: feat(cli): wire scanner → router → builder → simulator pipeline (feat/17-cli-e2e-pipeline)
Commit: latest on feat/17-cli-e2e-pipeline
File: crates/charon-cli/src/main.rs (pipeline tick, BOT_SIGNER_KEY branch)
PRD / invariant violated: CLAUDE.md safety invariant (hard rule): 'Every liquidation transaction passes an eth_call simulation gate before broadcast. Do not add a bypass.'
Problem:
The PR description states: 'Tx builder + simulator gracefully degrade if BOT_SIGNER_KEY unset.' In this mode, the simulator is skipped and the opportunity is still pushed to OpportunityQueue.
This is not graceful degradation — it is a simulation gate bypass. The queue is the handoff point to the broadcast PR (#44). An entry in the queue is an implicit assertion that it has passed all off-chain gates including simulation. If PR #44 consumes unsimulated entries and submits them, the CLAUDE.md invariant is violated in production.
The correct behavior when BOT_SIGNER_KEY is absent:
- Log that simulation is unavailable.
- Do NOT push the opportunity to the queue.
- Optionally track a counter of skipped-due-to-no-signer opportunities for observability.
Impact: When deployed without BOT_SIGNER_KEY configured, every liquidation attempted by the broadcast layer will skip the eth_call gate, risking on-chain reverts that burn gas and potentially interact with the contract in unintended ways.
Fix: In the no-signer branch, after logging the skip, do not call queue.push(opportunity). The queue must only receive simulated entries. Add a unit test asserting this behavior.
Refs #42
PR: feat(cli): wire scanner → router → builder → simulator pipeline (feat/17-cli-e2e-pipeline)
Commit: latest on feat/17-cli-e2e-pipeline
File: crates/charon-cli/src/main.rs (pipeline tick, BOT_SIGNER_KEY branch)
PRD / invariant violated: CLAUDE.md safety invariant (hard rule): 'Every liquidation transaction passes an eth_call simulation gate before broadcast. Do not add a bypass.'
Problem:
The PR description states: 'Tx builder + simulator gracefully degrade if BOT_SIGNER_KEY unset.' In this mode, the simulator is skipped and the opportunity is still pushed to OpportunityQueue.
This is not graceful degradation — it is a simulation gate bypass. The queue is the handoff point to the broadcast PR (#44). An entry in the queue is an implicit assertion that it has passed all off-chain gates including simulation. If PR #44 consumes unsimulated entries and submits them, the CLAUDE.md invariant is violated in production.
The correct behavior when BOT_SIGNER_KEY is absent:
Impact: When deployed without BOT_SIGNER_KEY configured, every liquidation attempted by the broadcast layer will skip the eth_call gate, risking on-chain reverts that burn gas and potentially interact with the contract in unintended ways.
Fix: In the no-signer branch, after logging the skip, do not call queue.push(opportunity). The queue must only receive simulated entries. Add a unit test asserting this behavior.