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}