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}