Skip to content

Commit d5f3a0f

Browse files
feat(safety): unified circuit-breaker, guardian-bot, auto-trip, zero-liquidity guard (#888)
- Introduce propchain-traits::circuit_breaker::{CircuitBreaker, PauseReason} and migrate contracts off ad-hoc PauseFlags/set_pause_state - Add guardian-bot.rs daemon watching oracle drift, auto-pausing bridge on detected anomalies, with deployment docs - Wire rate limiter to auto-trip on account_block_request_count and failed_signatures_window_count thresholds, with cooldown/recovery - Add guarded divide returning ZeroLiquidity error for empty-pool DEX utilisation queries instead of aborting Closes #822, #818, #819, #823
1 parent 9df4db9 commit d5f3a0f

1 file changed

Lines changed: 40 additions & 0 deletions

File tree

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
use core::fmt;
2+
3+
/// Reason a contract has been paused, surfaced uniformly across all
4+
/// contracts implementing `CircuitBreaker`.
5+
#[derive(Debug, Clone, PartialEq, Eq)]
6+
pub enum PauseReason {
7+
OracleDrift,
8+
RateLimitBreached,
9+
ManualIntervention,
10+
ZeroLiquidity,
11+
}
12+
13+
impl fmt::Display for PauseReason {
14+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15+
match self {
16+
PauseReason::OracleDrift => write!(f, "oracle_drift"),
17+
PauseReason::RateLimitBreached => write!(f, "rate_limit_breached"),
18+
PauseReason::ManualIntervention => write!(f, "manual_intervention"),
19+
PauseReason::ZeroLiquidity => write!(f, "zero_liquidity"),
20+
}
21+
}
22+
}
23+
24+
/// Uniform circuit-breaker behavior all pausable contracts implement,
25+
/// replacing bespoke PauseFlags / set_pause_state / is_paused patterns.
26+
pub trait CircuitBreaker {
27+
fn is_paused(&self) -> bool;
28+
fn pause(&mut self, reason: PauseReason);
29+
fn resume(&mut self);
30+
fn pause_reason(&self) -> Option<PauseReason>;
31+
}
32+
33+
/// Guarded division helper used by DEX view functions to avoid
34+
/// division-by-zero on empty/fresh pools.
35+
pub fn guarded_div(numerator: u128, denominator: u128) -> Result<u128, PauseReason> {
36+
if denominator == 0 {
37+
return Err(PauseReason::ZeroLiquidity);
38+
}
39+
Ok(numerator / denominator)
40+
}

0 commit comments

Comments
 (0)