Skip to main content

miden_usdcx/account/xreserve/builder/
error.rs

1//! The error type the faucet-account builder returns
2//! ([`XReserveStablecoinBuilderError`]).
3//!
4//! The variants describe wiring the builder refuses to compose.
5
6use core::fmt;
7
8use miden_protocol::errors::{AccountError, StorageMapError};
9use miden_standards::account::auth::NetworkAccountNoteAllowlistError;
10use miden_standards::account::faucets::FungibleFaucetError;
11use miden_standards::account::policies::{BurnPolicyError, MintPolicyError};
12use miden_tx::NotePricingError;
13
14use super::{
15    ATTESTATION_MINT_POLICY_PROC_PATH,
16    MIN_BURN_SIZE_FLOOR,
17    XRESERVE_BURN_POLICY_PROC_PATH,
18};
19
20/// Errors returned while composing the xUSDC faucet account.
21#[derive(Debug)]
22pub enum XReserveStablecoinBuilderError {
23    /// The fixed-identity USDCx
24    /// [`FungibleFaucet`](miden_standards::account::faucets::FungibleFaucet) could not be
25    /// constructed from the supplied supply parameters (the crate-root `build_faucet_account`
26    /// path). Carries the stock faucet error.
27    FaucetComposition(FungibleFaucetError),
28    /// The production `AuthNetworkAccount` auth component could not be assembled from the
29    /// note-script allowlist (the crate-root `build_account` path). Carries the stock allowlist
30    /// error.
31    NetworkAuth(NetworkAccountNoteAllowlistError),
32    /// The composed faucet [`Account`](miden_protocol::account::Account) could not be built from
33    /// the component set (the crate-root `build_account` path). Carries the stock account
34    /// error.
35    AccountComposition(AccountError),
36    /// The xUSDC fee schedule could not be priced from the supplied network fee parameters.
37    FeePricing(NotePricingError),
38    /// The supplied `xreserve` component does not export the attestation mint policy procedure
39    /// (assembly/path drift). Carries the expected path for diagnosis.
40    AttestationPolicyProcNotFound,
41    /// The burn policy component does not export the expected procedure.
42    BurnPolicyProcNotFound,
43    /// The requested `min_burn_amount` is below [`MIN_BURN_SIZE_FLOOR`]
44    /// (= 1). The stock `MinBurnAmount` policy asserts only `min <= amount` and its stock setter
45    /// accepts `0`, so a sub-floor seed would silently allow zero-amount burns;
46    /// rejected at construction (the post-deploy twin is the `XReserveMinBurnAmountNote`
47    /// factory's floor refusal). Carries the offending value.
48    MinBurnSizeBelowFloor(u64),
49    /// A `blocklist_manager_holders` member (a seeded `BLK_MANAGER` member) collides with
50    /// `ADMIN`, `ATTEST_ADMIN`, `DOM_PAUSER` or `DOM_UNPAUSER`. The transfer-blocklist
51    /// administrators must be external entities with no other faucet-admin capability.
52    /// `collides_with` names the offending role.
53    BlocklistManagerNotIsolated { collides_with: &'static str },
54    /// A `pauser_holders` member collides with another role's holder. A pause holder must hold
55    /// no other role, or a single signer gains a high-consequence power. `collides_with` names
56    /// the offending role.
57    PauserNotIsolated { collides_with: &'static str },
58    /// A role lists the same member twice; each holder appears once per role.
59    DuplicateRoleMember { role: &'static str },
60    /// The build-seeded attester allowlist lists a key twice. Carries the storage-map error.
61    AttesterAllowlist(StorageMapError),
62    /// The mint-policy descriptor rejected its construction (`MintPolicy::custom` validates
63    /// the root against the supplied companion components).
64    MintPolicy(MintPolicyError),
65    /// The burn-policy descriptor rejected its construction — the burn-slot twin of
66    /// [`Self::MintPolicy`].
67    BurnPolicy(BurnPolicyError),
68}
69
70impl fmt::Display for XReserveStablecoinBuilderError {
71    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72        match self {
73            Self::FaucetComposition(_) => {
74                write!(f, "the fixed-identity USDCx faucet could not be constructed")
75            },
76            Self::NetworkAuth(_) => {
77                write!(f, "the production network-account auth component could not be assembled")
78            },
79            Self::AccountComposition(_) => {
80                write!(f, "the composed faucet account could not be built")
81            },
82            Self::FeePricing(_) => write!(f, "the xUSDC fee schedule could not be priced"),
83            Self::AttestationPolicyProcNotFound => write!(
84                f,
85                "the xreserve component does not export the attestation mint policy procedure \
86                 '{ATTESTATION_MINT_POLICY_PROC_PATH}'"
87            ),
88            Self::BurnPolicyProcNotFound => write!(
89                f,
90                "the burn-policy component does not export the burn policy procedure \
91                 '{XRESERVE_BURN_POLICY_PROC_PATH}'"
92            ),
93            Self::MinBurnSizeBelowFloor(value) => write!(
94                f,
95                "min_burn_amount {value} is below the construction floor \
96                 {MIN_BURN_SIZE_FLOOR}"
97            ),
98            Self::BlocklistManagerNotIsolated { collides_with } => write!(
99                f,
100                "a BLK_MANAGER holder (transfer-blocklist administrator) must be an external entity \
101                 with no other faucet-admin capability, but one collides with the {collides_with} — \
102                 F4-reversal two-way capability isolation is violated"
103            ),
104            Self::PauserNotIsolated { collides_with } => write!(
105                f,
106                "a DOM_PAUSER holder must hold no other role, but one collides with {collides_with}"
107            ),
108            Self::DuplicateRoleMember { role } => {
109                write!(f, "the {role} role lists the same member twice")
110            },
111            Self::AttesterAllowlist(_) => {
112                write!(f, "the build-seeded attester allowlist lists a key twice")
113            },
114            Self::MintPolicy(_) => write!(f, "mint policy descriptor construction failed"),
115            Self::BurnPolicy(_) => write!(f, "burn policy descriptor construction failed"),
116        }
117    }
118}
119
120impl core::error::Error for XReserveStablecoinBuilderError {
121    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
122        match self {
123            Self::MintPolicy(source) => Some(source),
124            Self::BurnPolicy(source) => Some(source),
125            Self::FaucetComposition(source) => Some(source),
126            Self::NetworkAuth(source) => Some(source),
127            Self::AccountComposition(source) => Some(source),
128            Self::FeePricing(source) => Some(source),
129            Self::AttesterAllowlist(source) => Some(source),
130            _ => None,
131        }
132    }
133}
134
135impl From<MintPolicyError> for XReserveStablecoinBuilderError {
136    fn from(source: MintPolicyError) -> Self {
137        Self::MintPolicy(source)
138    }
139}
140
141impl From<BurnPolicyError> for XReserveStablecoinBuilderError {
142    fn from(source: BurnPolicyError) -> Self {
143        Self::BurnPolicy(source)
144    }
145}
146
147impl From<NetworkAccountNoteAllowlistError> for XReserveStablecoinBuilderError {
148    fn from(source: NetworkAccountNoteAllowlistError) -> Self {
149        Self::NetworkAuth(source)
150    }
151}
152
153impl From<NotePricingError> for XReserveStablecoinBuilderError {
154    fn from(source: NotePricingError) -> Self {
155        Self::FeePricing(source)
156    }
157}