Skip to main content

ConfigError

Enum ConfigError 

Source
pub enum ConfigError {
    InvalidDeviationBps,
    InvalidStalenessSeconds,
    InvalidLiquidityThreshold,
    InvalidCrossSourceBps,
    InvalidHaltLedgers,
    InvalidTradeCountThreshold,
    InvalidSnapshotAge,
    InvalidPreviousStalenessSeconds,
}
Expand description

Errors returned by SafeOracleConfig::validate when a config field has an out-of-range value that would silently disable a guardrail or produce nonsensical behavior at runtime.

§Spec

See spec §4 — Config Struct. Validation prevents silent guardrail disabling caused by misconfiguration (e.g., max_deviation_bps = 0 allows infinite deviation, effectively disabling the deviation check without any visible signal).

§Audit notes

  • Validation is opt-in — callers must invoke config.validate(). The library does not enforce validation in lastprice() to avoid per-call gas cost. Production integrators should validate at init time (recommended pattern: MockLending::initialize calls validate).

  • All errors are recoverable at init time; runtime config changes are not supported (config is immutable after deploy per spec §4).

Variants§

§

InvalidDeviationBps

max_deviation_bps is 0 (allows infinite deviation, disabling the check) or > 10_000 (100% — values above this are nonsensical for a relative-deviation threshold).

§

InvalidStalenessSeconds

max_staleness_seconds is 0 (rejects every recorded price as stale) or > 86_400 (24h — stale data older than a day is unsafe regardless of how lenient the integrator wants to be).

§

InvalidLiquidityThreshold

min_liquidity_usd is <= 0 — negative values are semantically nonsense (liquidity is non-negative by definition), and 0 silently disables the Layer 2 liquidity check (every snapshot’s volume_30m_usd > 0 trivially passes the threshold). Same defensive principle as InvalidTradeCountThreshold: a zero guardrail is no guardrail.

§AR.H M1 closure

This variant’s runtime rule was tightened from < 0 to <= 0 after AR.H surfaced the silent-disable case as the single residual asymmetry from Hardening Closure (Debt #22).

§

InvalidCrossSourceBps

max_cross_source_bps is 0 (requires impossible primary/secondary price equality) or > 10_000 (semantically nonsensical, > 100% deviation) when secondary_oracle is configured. Validation skipped if secondary is None (field is dormant).

§AR.H L2 closure

Validation rule was tightened from > 10_000 only to == 0 || > 10_000 after AR.H surfaced the silent-footgun case where a zero threshold produces always-fires CrossSourceMismatch on every borrow.

§

InvalidHaltLedgers

circuit_breaker_halt_ledgers is 0 (degenerate halt window — the breaker would fire and immediately auto-recover, providing no actual halt) or > MAX_CIRCUIT_BREAKER_HALT_LEDGERS (~1 week, beyond the reasonable auto-recovery window) when circuit_breaker_enabled is true. Validation skipped if breaker is disabled (field is dormant).

§AR.H L1 closure

Upper bound added after AR.H surfaced that u32::MAX (~6.8 years at Stellar’s ledger cadence) makes a misconfigured deploy effectively-permanently halted without governance intervention.

§

InvalidTradeCountThreshold

min_trade_count_1h is 0 — disables thin-sampling check entirely (every snapshot’s unique_trades_1h >= 0 always true). Same defensive principle as InvalidDeviationBps: a “guardrail of zero” is no guardrail at all. Integrators wanting to disable Layer 2 thin-sampling should leave the guardrail’s threshold meaningful and route around it via Layer 1 / circuit breaker controls.

§Hardening 3A follow-up (Debt #22)

This variant closes the gap intentionally left open in Hardening 3A, where the prompt’s “5 variant” boundary kept the pattern consistent with the other guardrails but left two silent-disable cases undetected. Hardening Closure brings parity.

§

InvalidSnapshotAge

max_snapshot_age_seconds is 0 (rejects all snapshots) or > 86_400 (24h — staler than this is unsafe regardless of integrator intent). Mirrors InvalidStalenessSeconds boundary logic for the Layer 2 path.

§Hardening 3A follow-up (Debt #22)

Same closure rationale as InvalidTradeCountThreshold. The Hardening 3A boundary kept the new-variant count at 5; the Layer 2 snapshot age validation remained an audit-trail gap until this patch.

§

InvalidPreviousStalenessSeconds

previous_max_staleness_seconds == 0 silently disables the previous-price freshness check (every previous price would be classified StaleData, blocking every borrow), or > 86_400 (24h) accepts unsafe staleness for the deviation reference. Mirrors InvalidStalenessSeconds boundary logic.

Phase 7.2 addition — pairs with the new previous_max_staleness_seconds field on SafeOracleConfig.

Implementations§

Source§

impl ConfigError

Source

pub const fn spec_xdr() -> [u8; 4580]

Trait Implementations§

Source§

impl Clone for ConfigError

Source§

fn clone(&self) -> ConfigError

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ConfigError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl PartialEq for ConfigError

Source§

fn eq(&self, other: &ConfigError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl TryFromVal<Env, &ConfigError> for Val

Source§

impl TryFromVal<Env, ConfigError> for Val

Source§

impl TryFromVal<Env, Val> for ConfigError

Source§

impl Eq for ConfigError

Source§

impl StructuralPartialEq for ConfigError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T, C> Compare<&T> for C
where C: Compare<T>,

Source§

type Error = <C as Compare<T>>::Error

Source§

fn compare(&self, a: &&T, b: &&T) -> Result<Ordering, <C as Compare<&T>>::Error>

Source§

impl<T, U, E, C> Compare<(T, U)> for C
where C: Compare<T, Error = E, Error = E> + Compare<U>,

Source§

type Error = E

Source§

fn compare( &self, a: &(T, U), b: &(T, U), ) -> Result<Ordering, <C as Compare<(T, U)>>::Error>

Source§

impl<T, U, V, E, C> Compare<(T, U, V)> for C
where C: Compare<T, Error = E, Error = E, Error = E> + Compare<U> + Compare<V>,

Source§

impl<T, U, V, W, E, C> Compare<(T, U, V, W)> for C
where C: Compare<T, Error = E, Error = E, Error = E, Error = E> + Compare<U> + Compare<V> + Compare<W>,

Source§

impl<T, U, V, W, X, E, C> Compare<(T, U, V, W, X)> for C
where C: Compare<T, Error = E, Error = E, Error = E, Error = E, Error = E> + Compare<U> + Compare<V> + Compare<W> + Compare<X>,

Source§

impl<T, C> Compare<Box<T>> for C
where C: Compare<T>,

Source§

type Error = <C as Compare<T>>::Error

Source§

fn compare( &self, a: &Box<T>, b: &Box<T>, ) -> Result<Ordering, <C as Compare<Box<T>>>::Error>

Source§

impl<T, C> Compare<Option<T>> for C
where C: Compare<T>,

Source§

type Error = <C as Compare<T>>::Error

Source§

fn compare( &self, a: &Option<T>, b: &Option<T>, ) -> Result<Ordering, <C as Compare<Option<T>>>::Error>

Source§

impl<T, C> Compare<Rc<T>> for C
where C: Compare<T>,

Source§

type Error = <C as Compare<T>>::Error

Source§

fn compare( &self, a: &Rc<T>, b: &Rc<T>, ) -> Result<Ordering, <C as Compare<Rc<T>>>::Error>

Source§

impl<T, C> Compare<Vec<T>> for C
where C: Compare<T>,

Source§

type Error = <C as Compare<T>>::Error

Source§

fn compare( &self, a: &Vec<T>, b: &Vec<T>, ) -> Result<Ordering, <C as Compare<Vec<T>>>::Error>

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<E, T, U> FromVal<E, T> for U
where E: Env, U: TryFromVal<E, T>,

Source§

fn from_val(e: &E, v: &T) -> U

Source§

impl<T> FromXdr for T
where T: TryFromVal<Env, Val>,

Source§

type Error = <T as TryFromVal<Env, Val>>::Error

The error type returned if the Val cannot be converted into the target type.
Source§

fn from_xdr(env: &Env, b: &Bytes) -> Result<T, <T as FromXdr>::Error>

Deserializes the value from XDR Bytes. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<E, T, U> IntoVal<E, T> for U
where E: Env, T: FromVal<E, U>,

Source§

fn into_val(&self, e: &E) -> T

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToXdr for T
where T: IntoVal<Env, Val>,

Source§

fn to_xdr(self, env: &Env) -> Bytes

Serializes the value to XDR as Bytes.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<E, T, U> TryIntoVal<E, T> for U
where E: Env, T: TryFromVal<E, U>,

Source§

type Error = <T as TryFromVal<E, U>>::Error

Source§

fn try_into_val(&self, env: &E) -> Result<T, <U as TryIntoVal<E, T>>::Error>

Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V