templar_curator_primitives/auth/
mod.rs

1//! Chain-agnostic authentication and authorization primitives.
2//!
3//! This module provides a pluggable auth surface so curator and strategy vaults
4//! can share the runtime while using different authorization mechanisms.
5//!
6//! The core trait [`AuthAdapter`] allows each chain executor to implement its own
7//! signature verification while sharing the same action kinds and error types.
8
9use templar_vault_kernel::{Address, KernelAction};
10
11/// Shared authorization class for an action.
12#[templar_vault_macros::vault_derive(borsh, serde)]
13#[derive(Clone, Copy, PartialEq, Eq)]
14pub enum AuthPolicyClass {
15    /// User-facing/public action (no special role requirement).
16    Public,
17    /// Sentinel/emergency-governance privileged action.
18    Sentinel,
19    /// Allocator-level privileged action.
20    Allocator,
21    /// Emergency allocator path (allocator + emergency role on some executors).
22    AllocatorEmergency,
23    /// Curator/owner-only privileged action.
24    Curator,
25}
26
27/// Canonical shared policy class for an action.
28#[inline]
29#[must_use]
30pub const fn canonical_policy_class(action: ActionKind) -> AuthPolicyClass {
31    match action {
32        ActionKind::Deposit
33        | ActionKind::RequestWithdraw
34        | ActionKind::AtomicWithdraw
35        | ActionKind::AtomicRedeem => AuthPolicyClass::Public,
36        ActionKind::ExecuteWithdraw
37        | ActionKind::BeginAllocating
38        | ActionKind::FinishAllocating
39        | ActionKind::SyncExternalAssets
40        | ActionKind::RebalanceWithdraw
41        | ActionKind::BeginRefreshing
42        | ActionKind::FinishRefreshing
43        | ActionKind::SettlePayout
44        | ActionKind::RefreshFees => AuthPolicyClass::Allocator,
45        ActionKind::Pause | ActionKind::SetRestrictions => AuthPolicyClass::Sentinel,
46        ActionKind::AbortAllocating
47        | ActionKind::AbortWithdrawing
48        | ActionKind::AbortRefreshing => AuthPolicyClass::AllocatorEmergency,
49        ActionKind::ManualReconcile | ActionKind::EmergencyReset | ActionKind::PolicyAdmin => {
50            AuthPolicyClass::Curator
51        }
52    }
53}
54
55/// Boundary executor policy class for an action.
56#[inline]
57#[must_use]
58pub const fn boundary_policy_class(action: ActionKind) -> AuthPolicyClass {
59    canonical_policy_class(action)
60}
61
62#[inline]
63#[must_use]
64pub const fn allowed_while_paused(action: ActionKind) -> bool {
65    matches!(
66        action,
67        ActionKind::Pause
68            | ActionKind::SetRestrictions
69            | ActionKind::AbortAllocating
70            | ActionKind::AbortWithdrawing
71            | ActionKind::AbortRefreshing
72            | ActionKind::ManualReconcile
73            | ActionKind::EmergencyReset
74    )
75}
76
77/// Kinds of actions that require authorization.
78#[templar_vault_macros::vault_derive(borsh, serde)]
79#[derive(Clone, Copy, PartialEq, Eq)]
80pub enum ActionKind {
81    /// User deposit action.
82    Deposit,
83    /// User withdraw request.
84    RequestWithdraw,
85    /// Execute pending withdrawal.
86    ExecuteWithdraw,
87    /// Pause/unpause the vault.
88    Pause,
89    /// Set kernel restrictions (pause/allowlist/denylist).
90    SetRestrictions,
91    /// Curator-only policy/state administration outside kernel restrictions.
92    PolicyAdmin,
93    /// Begin allocation operation.
94    BeginAllocating,
95    /// Finish allocation operation.
96    FinishAllocating,
97    /// Sync external assets.
98    SyncExternalAssets,
99    RebalanceWithdraw,
100    /// Begin refresh operation.
101    BeginRefreshing,
102    /// Finish refresh operation.
103    FinishRefreshing,
104    /// Abort allocation.
105    AbortAllocating,
106    /// Abort withdrawal.
107    AbortWithdrawing,
108    /// Abort refresh.
109    AbortRefreshing,
110    /// Settle payout.
111    SettlePayout,
112    /// Refresh fees.
113    RefreshFees,
114    /// Privileged manual reconciliation of external assets.
115    ManualReconcile,
116    /// Emergency reset to force-idle a stuck vault.
117    EmergencyReset,
118    /// Atomic withdraw (by assets, idle-only fast path).
119    AtomicWithdraw,
120    AtomicRedeem,
121}
122
123impl ActionKind {
124    /// Returns true if this action requires privileged access under the canonical policy.
125    #[inline]
126    #[must_use]
127    pub const fn is_privileged(&self) -> bool {
128        !matches!(canonical_policy_class(*self), AuthPolicyClass::Public)
129    }
130}
131
132impl From<&KernelAction> for ActionKind {
133    #[inline]
134    fn from(action: &KernelAction) -> Self {
135        match action {
136            KernelAction::BeginAllocating { .. } => Self::BeginAllocating,
137            KernelAction::Deposit { .. } => Self::Deposit,
138            KernelAction::AtomicWithdraw { .. } => Self::AtomicWithdraw,
139            KernelAction::AtomicRedeem { .. } => Self::AtomicRedeem,
140            KernelAction::RequestWithdraw { .. } => Self::RequestWithdraw,
141            KernelAction::ExecuteWithdraw { .. } => Self::ExecuteWithdraw,
142            KernelAction::BeginRefreshing { .. } => Self::BeginRefreshing,
143            KernelAction::FinishAllocating { .. } => Self::FinishAllocating,
144            KernelAction::SyncExternalAssets { .. } => Self::SyncExternalAssets,
145            KernelAction::RebalanceWithdraw { .. } => Self::RebalanceWithdraw,
146            KernelAction::FinishRefreshing { .. } => Self::FinishRefreshing,
147            KernelAction::AbortRefreshing { .. } => Self::AbortRefreshing,
148            KernelAction::SettlePayout { .. } => Self::SettlePayout,
149            KernelAction::AbortAllocating { .. } => Self::AbortAllocating,
150            KernelAction::AbortWithdrawing { .. } => Self::AbortWithdrawing,
151            KernelAction::RefreshFees { .. } => Self::RefreshFees,
152            KernelAction::Pause { .. } => Self::Pause,
153            KernelAction::EmergencyReset => Self::EmergencyReset,
154        }
155    }
156}
157
158impl From<KernelAction> for ActionKind {
159    #[inline]
160    fn from(action: KernelAction) -> Self {
161        Self::from(&action)
162    }
163}
164
165#[templar_vault_macros::vault_derive]
166#[derive(Clone, Copy, PartialEq, Eq)]
167pub enum Caller {
168    Admin,
169    Curator,
170    Sentinel,
171    Allocator,
172    User,
173}
174
175#[templar_vault_macros::vault_derive]
176#[derive(Clone, PartialEq, Eq)]
177pub enum AuthError {
178    NotAuthorized {
179        caller: Caller,
180        action: ActionKind,
181    },
182    InvalidProof,
183    MissingRole {
184        action: ActionKind,
185        policy_class: AuthPolicyClass,
186    },
187    VaultPaused,
188}
189
190/// Result type for auth operations.
191pub type AuthResult<T> = Result<T, AuthError>;
192
193/// Pluggable authorization adapter interface.
194///
195/// Curator vaults use RBAC checks while strategy vaults use Merkle proof
196/// verification against a globally updatable root.
197pub trait AuthAdapter {
198    /// Authorize an action for a caller.
199    fn authorize(
200        &self,
201        action: ActionKind,
202        caller: Address,
203        proof: Option<&[u8]>,
204    ) -> AuthResult<()>;
205
206    /// Check if the vault is currently paused.
207    fn is_paused(&self) -> bool;
208}