Skip to main content

miden_usdcx/account/xreserve/
admin_authority.rs

1//! [`XReserveAdminAuthority`] — the account-wide authority configuration for the faucet's admin
2//! surface, expressed as a per-procedure role assignment over the standard manager components.
3//!
4//! Pause, unpause, attester administration and the transfer blocklist each have a dedicated role.
5//! Under [`Authority`]'s RBAC mode, each gated procedure's root selects its role; an unassigned
6//! procedure falls back to `ADMIN`. Every role is initially administered directly by `ADMIN`.
7//!
8//! This type takes no arguments: the five roots come from the shipped managers and faucet
9//! extension, and the role symbols are fixed, so callers cannot misconfigure the assignment.
10//!
11//! Two conversions make it usable: into the [`Authority`] configuration it describes, and into the
12//! [`AccountComponent`] that carries it into an account.
13//!
14//! Installed by
15//! [`XReserveStablecoinBuilder::build_components`][crate::account::xreserve::XReserveStablecoinBuilder::build_components]
16//! as the account's only authority component. One consequence is worth stating where a reader will
17//! look for it: administrator membership is account-bound, and it is the account's ONLY authority
18//! handle — the faucet installs no ownership component, so nothing else can move authority over the
19//! unmapped setters. Rotating it is a grant to the incoming account then a revoke from the
20//! outgoing one, both through the standard role-action note.
21
22use std::collections::BTreeMap;
23
24use miden_protocol::account::{AccountComponent, AccountProcedureRoot, RoleSymbol};
25use miden_standards::account::access::{Authority, PausableManager};
26use miden_standards::account::policies::BlocklistManager;
27
28use super::{
29    ATTEST_ADMIN_ROLE,
30    BLK_MANAGER_ROLE,
31    DOM_PAUSER_ROLE,
32    DOM_UNPAUSER_ROLE,
33    XRESERVE_SET_ATTESTER_PROC_PATH,
34    XReserveFaucetExtension,
35};
36
37/// Dedicated-role procedures: pause, unpause, set_attester, block and unblock.
38const ROLE_GATED_PROCEDURE_COUNT: usize = 5;
39
40/// The faucet's account-wide RBAC authority with five dedicated procedure assignments.
41///
42/// `DOM_PAUSER` gates pause, `DOM_UNPAUSER` gates unpause, `ATTEST_ADMIN` gates set_attester,
43/// and `BLK_MANAGER` gates block/unblock. Every other authority-gated procedure resolves to ADMIN.
44#[derive(Debug, Clone, PartialEq, Eq)]
45pub struct XReserveAdminAuthority {
46    procedure_roles: BTreeMap<AccountProcedureRoot, RoleSymbol>,
47}
48
49impl XReserveAdminAuthority {
50    /// Builds the faucet's authority configuration.
51    ///
52    /// Takes no arguments on purpose: the assignment is a property of the faucet's admin model, not
53    /// a deployment parameter, so it cannot be misconfigured by a caller.
54    pub fn new() -> Self {
55        let pauser = RoleSymbol::new(DOM_PAUSER_ROLE)
56            .expect("the Domain pauser role symbol is a fixed valid symbol");
57        let unpauser = RoleSymbol::new(DOM_UNPAUSER_ROLE)
58            .expect("the Domain unpauser role symbol is a fixed valid symbol");
59        let attest_admin = RoleSymbol::new(ATTEST_ADMIN_ROLE)
60            .expect("the attester administrator role symbol is a fixed valid symbol");
61        let set_attester_root = XReserveFaucetExtension::code()
62            .get_procedure_root_by_path(XRESERVE_SET_ATTESTER_PROC_PATH)
63            .expect("the shipped faucet extension exports set_attester");
64        let blocklist_manager = RoleSymbol::new(BLK_MANAGER_ROLE)
65            .expect("the blocklist administrator role symbol is a fixed valid symbol");
66
67        let procedure_roles = BTreeMap::from([
68            (PausableManager::pause_root(), pauser),
69            (PausableManager::unpause_root(), unpauser),
70            (set_attester_root, attest_admin),
71            (BlocklistManager::block_account_root(), blocklist_manager.clone()),
72            (BlocklistManager::unblock_account_root(), blocklist_manager),
73        ]);
74        assert_eq!(
75            procedure_roles.len(),
76            ROLE_GATED_PROCEDURE_COUNT,
77            "the five gated procedures must be five distinct roots",
78        );
79
80        Self { procedure_roles }
81    }
82
83    /// The role required to invoke each role-gated procedure, keyed by the procedure's root.
84    pub fn procedure_roles(&self) -> &BTreeMap<AccountProcedureRoot, RoleSymbol> {
85        &self.procedure_roles
86    }
87}
88
89impl Default for XReserveAdminAuthority {
90    fn default() -> Self {
91        Self::new()
92    }
93}
94
95impl From<XReserveAdminAuthority> for Authority {
96    fn from(authority: XReserveAdminAuthority) -> Self {
97        Authority::RbacControlled {
98            procedure_roles: authority.procedure_roles,
99        }
100    }
101}
102
103impl From<XReserveAdminAuthority> for AccountComponent {
104    fn from(authority: XReserveAdminAuthority) -> Self {
105        Authority::from(authority).into()
106    }
107}