Skip to main content

aethel_vault/
error.rs

1//! Error type for the `signer`-mode surface (V-1/V-4/V-5).
2//!
3//! Distinct from the `extern "C"` `ERR_*` `u32` codes in
4//! [`crate::vault`], which stay as they are for the confidential-ledger
5//! state machine's ABI. [`VaultError`] is the Rust-native error type for
6//! [`crate::settlement::Wallet`], [`crate::policy::SpendPolicy`], and
7//! [`crate::receipt`].
8
9extern crate alloc;
10
11use crate::policy::PolicyViolation;
12use crate::settlement::SettlementError;
13
14/// Errors produced by the `signer`-mode surface: settlement authorization,
15/// spend policy enforcement, and receipt signing/verification.
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub enum VaultError {
18    /// The spend policy denied the request outright (no HITL escalation
19    /// possible for this violation — see [`PolicyViolation`]).
20    PolicyDenied(PolicyViolation),
21    /// The amount is above the policy's `hitl_above` threshold and no
22    /// valid [`crate::policy::HitlApproval`] was supplied (or the one
23    /// supplied did not verify against the configured approver key,
24    /// the expected intent, or was expired).
25    HitlRequired,
26    /// The injected [`crate::settlement::SettlementSigner`] failed to
27    /// produce a signature over the EIP-712 digest.
28    SignerFailure(SettlementError),
29    /// An address argument was structurally invalid (reserved for future
30    /// validation; addresses are fixed-size `[u8; 20]` today so this is not
31    /// yet reachable, but kept so a future checksum/format validation has
32    /// somewhere to report to without another breaking enum change).
33    InvalidAddress,
34    /// The requested rail is not in the policy's `allow_rails` list.
35    ///
36    /// Distinct from [`Self::PolicyDenied`]`(`[`PolicyViolation::RailNotAllowed`]`)`
37    /// only in which layer detected it; both are surfaced identically to a
38    /// caller and this variant exists for call sites that check the rail
39    /// before constructing a [`crate::policy::SpendRequest`] at all.
40    RailNotAllowed,
41    /// The aethel-core identity signing/verification layer reported a
42    /// failure (malformed key, oversized purpose, etc.) — see
43    /// [`aethel_core::IdentityError`].
44    IdentityError(aethel_core::IdentityError),
45    /// Bincode (de)serialization of an intent/receipt/approval message
46    /// failed.
47    SerializationError,
48}
49
50impl From<aethel_core::IdentityError> for VaultError {
51    fn from(e: aethel_core::IdentityError) -> Self {
52        VaultError::IdentityError(e)
53    }
54}
55
56impl From<PolicyViolation> for VaultError {
57    fn from(e: PolicyViolation) -> Self {
58        VaultError::PolicyDenied(e)
59    }
60}
61
62impl From<SettlementError> for VaultError {
63    fn from(e: SettlementError) -> Self {
64        VaultError::SignerFailure(e)
65    }
66}
67
68impl core::fmt::Display for VaultError {
69    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
70        match self {
71            VaultError::PolicyDenied(v) => write!(f, "spend policy denied: {v:?}"),
72            VaultError::HitlRequired => write!(f, "amount requires human-in-the-loop approval"),
73            VaultError::SignerFailure(e) => write!(f, "settlement signer failed: {e:?}"),
74            VaultError::InvalidAddress => write!(f, "invalid address"),
75            VaultError::RailNotAllowed => write!(f, "rail not allowed by policy"),
76            VaultError::IdentityError(e) => write!(f, "identity error: {e:?}"),
77            VaultError::SerializationError => write!(f, "serialization error"),
78        }
79    }
80}