diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fdf3d6dbc..ab0c8af14d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -82,6 +82,8 @@ - [BREAKING] Changed `native_account::remove_asset` to return the asset value remaining in the vault instead of the removed value ([#2626](https://github.com/0xMiden/protocol/pull/2626)). - Implemented `TransactionEventId::event_name` and `Host::resolve_event` for better VM diagnostics during even handler failures ([#2628](https://github.com/0xMiden/protocol/pull/2628)). - Added `FixedWidthString` for fixed-width UTF-8 string storage in `miden-standards` (`miden::standards::utils::string`). ([#2633](https://github.com/0xMiden/protocol/pull/2633)) +- [BREAKING] Changed mint and burn policy management into standalone generic `PolicyManager` components under `account::policies::{mint,burn}` ([#2821](https://github.com/0xMiden/protocol/pull/2821)). + ### Changes diff --git a/crates/miden-agglayer/build.rs b/crates/miden-agglayer/build.rs index 96e333d6e7..1f86367cc9 100644 --- a/crates/miden-agglayer/build.rs +++ b/crates/miden-agglayer/build.rs @@ -16,8 +16,9 @@ use miden_protocol::account::{ }; use miden_protocol::transaction::TransactionKernel; use miden_standards::account::auth::NoAuth; -use miden_standards::account::burn_policies::BurnOwnerControlled; -use miden_standards::account::mint_policies::MintOwnerControlled; +use miden_standards::account::policies::burn::owner_controlled::Config as BurnConfig; +use miden_standards::account::policies::mint::owner_controlled::Config as MintConfig; +use miden_standards::account::policies::{burn, mint}; // CONSTANTS // ================================================================================================ @@ -256,8 +257,15 @@ fn generate_agglayer_constants( components.push(AccountComponent::from( miden_standards::account::access::Ownable2Step::new(dummy_owner), )); - components.push(AccountComponent::from(MintOwnerControlled::owner_only())); - components.push(AccountComponent::from(BurnOwnerControlled::allow_all())); + // Mirror the component order used by `create_agglayer_faucet_builder` in lib.rs so + // the compile-time code commitment matches the one computed at runtime. + components.push(mint::PolicyManager::owner_controlled(MintConfig::OwnerOnly).into()); + components.push(mint::owner_controlled::OwnerOnly.into()); + // Burn policy manager: active = `owner_only` (burns locked by default), `allow_all` + // is also allowed so the owner can open burns at runtime via `set_burn_policy`. + components.push(burn::PolicyManager::owner_controlled(BurnConfig::OwnerOnly).into()); + components.push(burn::owner_controlled::OwnerOnly.into()); + components.push(burn::AllowAll.into()); } // use `AccountCode` to merge codes of agglayer and authentication components diff --git a/crates/miden-agglayer/src/faucet.rs b/crates/miden-agglayer/src/faucet.rs index 9865e60e4f..bb837cade7 100644 --- a/crates/miden-agglayer/src/faucet.rs +++ b/crates/miden-agglayer/src/faucet.rs @@ -16,9 +16,8 @@ use miden_protocol::account::{ use miden_protocol::asset::TokenSymbol; use miden_protocol::errors::AccountIdError; use miden_standards::account::access::Ownable2Step; -use miden_standards::account::burn_policies::BurnOwnerControlled; use miden_standards::account::faucets::{FungibleFaucetError, TokenMetadata}; -use miden_standards::account::mint_policies::MintOwnerControlled; +use miden_standards::account::policies::{burn, mint}; use miden_utils_sync::LazyLock; use thiserror::Error; @@ -90,8 +89,7 @@ static METADATA_HASH_HI_SLOT_NAME: LazyLock = LazyLock::new(|| /// /// This component re-exports `network_fungible::mint_and_send`, which requires: /// - [`Ownable2Step`]: Provides ownership data (bridge account ID as owner). -/// - [`miden_standards::account::mint_policies::MintOwnerControlled`]: Provides mint policy -/// management. +/// - [`miden_standards::account::policies::mint::PolicyManager`]: Provides mint policy management. /// /// These must be added as separate components when building the faucet account. #[derive(Debug, Clone)] @@ -365,12 +363,12 @@ impl AggLayerFaucet { &*METADATA_HASH_HI_SLOT_NAME, TokenMetadata::metadata_slot(), Ownable2Step::slot_name(), - MintOwnerControlled::active_policy_proc_root_slot(), - MintOwnerControlled::allowed_policy_proc_roots_slot(), - MintOwnerControlled::policy_authority_slot(), - BurnOwnerControlled::active_policy_proc_root_slot(), - BurnOwnerControlled::allowed_policy_proc_roots_slot(), - BurnOwnerControlled::policy_authority_slot(), + mint::PolicyManager::active_policy_slot(), + mint::PolicyManager::allowed_policies_slot(), + mint::PolicyManager::policy_authority_slot(), + burn::PolicyManager::active_policy_slot(), + burn::PolicyManager::allowed_policies_slot(), + burn::PolicyManager::policy_authority_slot(), ] } } diff --git a/crates/miden-agglayer/src/lib.rs b/crates/miden-agglayer/src/lib.rs index 8731f64aa5..40322ddd63 100644 --- a/crates/miden-agglayer/src/lib.rs +++ b/crates/miden-agglayer/src/lib.rs @@ -18,8 +18,9 @@ use miden_protocol::note::NoteScript; use miden_protocol::vm::Program; use miden_standards::account::access::Ownable2Step; use miden_standards::account::auth::NoAuth; -use miden_standards::account::burn_policies::BurnOwnerControlled; -use miden_standards::account::mint_policies::MintOwnerControlled; +use miden_standards::account::policies::burn::owner_controlled::Config as BurnConfig; +use miden_standards::account::policies::mint::owner_controlled::Config as MintConfig; +use miden_standards::account::policies::{burn, mint}; use miden_utils_sync::LazyLock; pub mod b2agg_note; @@ -208,10 +209,11 @@ pub fn create_existing_bridge_account( /// The builder includes: /// - The `AggLayerFaucet` component (conversion metadata + token metadata). /// - The `Ownable2Step` component (bridge account ID as owner for mint authorization). -/// - The `MintOwnerControlled` component (mint policy management required by -/// `network_fungible::mint_and_send`). -/// - The `BurnOwnerControlled` component (burn policy management required by -/// `basic_fungible::burn`). +/// - The `mint::PolicyManager` + `mint::owner_controlled::OwnerOnly` components (mint policy +/// management and the `owner_only` mint policy required by `network_fungible::mint_and_send`). +/// - The `burn::PolicyManager` + `burn::owner_controlled::OwnerOnly` + `burn::AllowAll` components +/// (burn policy management with `owner_only` as the active policy and `allow_all` also registered +/// as allowed). #[allow(clippy::too_many_arguments)] fn create_agglayer_faucet_builder( seed: Word, @@ -241,8 +243,14 @@ fn create_agglayer_faucet_builder( .storage_mode(AccountStorageMode::Network) .with_component(agglayer_component) .with_component(Ownable2Step::new(bridge_account_id)) - .with_component(MintOwnerControlled::owner_only()) - .with_component(BurnOwnerControlled::owner_only()) + .with_component(mint::PolicyManager::owner_controlled(MintConfig::OwnerOnly)) + .with_component(mint::owner_controlled::OwnerOnly) + // Burn policy manager: active = `owner_only` (burns locked by default); `allow_all` is + // also registered in the allowed list so the owner can open burns at runtime via + // `set_burn_policy`. + .with_component(burn::PolicyManager::owner_controlled(BurnConfig::OwnerOnly)) + .with_component(burn::owner_controlled::OwnerOnly) + .with_component(burn::AllowAll) } /// Creates a new agglayer faucet account with the specified configuration. diff --git a/crates/miden-standards/asm/account_components/burn_policies/auth_controlled.masm b/crates/miden-standards/asm/account_components/burn_policies/auth_controlled.masm deleted file mode 100644 index 16591f026b..0000000000 --- a/crates/miden-standards/asm/account_components/burn_policies/auth_controlled.masm +++ /dev/null @@ -1,7 +0,0 @@ -# The MASM code of the Burn Policy Auth Controlled Account Component. -# -# See the `BurnAuthControlled` Rust type's documentation for more details. - -pub use ::miden::standards::burn_policies::allow_all -pub use ::miden::standards::burn_policies::policy_manager::set_burn_policy -pub use ::miden::standards::burn_policies::policy_manager::get_burn_policy diff --git a/crates/miden-standards/asm/account_components/burn_policies/owner_controlled.masm b/crates/miden-standards/asm/account_components/burn_policies/owner_controlled.masm deleted file mode 100644 index d2bd9f07c4..0000000000 --- a/crates/miden-standards/asm/account_components/burn_policies/owner_controlled.masm +++ /dev/null @@ -1,11 +0,0 @@ -# The MASM code of the Burn Policy Owner Controlled Account Component. -# -# See the `OwnerControlled` Rust type's documentation for more details. - -# Re-export `allow_all` from `miden::standards::burn_policies` so the -# faucet can switch the active burn policy to allow-all via `set_burn_policy`. -# The auth-controlled component uses the same standards procedure. -pub use ::miden::standards::burn_policies::allow_all -pub use ::miden::standards::burn_policies::owner_controlled::owner_only -pub use ::miden::standards::burn_policies::policy_manager::set_burn_policy -pub use ::miden::standards::burn_policies::policy_manager::get_burn_policy diff --git a/crates/miden-standards/asm/account_components/mint_policies/auth_controlled.masm b/crates/miden-standards/asm/account_components/mint_policies/auth_controlled.masm deleted file mode 100644 index c7c9a41af6..0000000000 --- a/crates/miden-standards/asm/account_components/mint_policies/auth_controlled.masm +++ /dev/null @@ -1,7 +0,0 @@ -# The MASM code of the Mint Policy Auth Controlled Account Component. -# -# See the `MintAuthControlled` Rust type's documentation for more details. - -pub use ::miden::standards::mint_policies::allow_all -pub use ::miden::standards::mint_policies::policy_manager::set_mint_policy -pub use ::miden::standards::mint_policies::policy_manager::get_mint_policy diff --git a/crates/miden-standards/asm/account_components/mint_policies/owner_controlled.masm b/crates/miden-standards/asm/account_components/mint_policies/owner_controlled.masm deleted file mode 100644 index cc21f8f0de..0000000000 --- a/crates/miden-standards/asm/account_components/mint_policies/owner_controlled.masm +++ /dev/null @@ -1,7 +0,0 @@ -# The MASM code of the Mint Policy Owner Controlled Account Component. -# -# See the `OwnerControlled` Rust type's documentation for more details. - -pub use ::miden::standards::mint_policies::owner_controlled::owner_only -pub use ::miden::standards::mint_policies::policy_manager::set_mint_policy -pub use ::miden::standards::mint_policies::policy_manager::get_mint_policy diff --git a/crates/miden-standards/asm/account_components/policies/burn/mod.masm b/crates/miden-standards/asm/account_components/policies/burn/mod.masm new file mode 100644 index 0000000000..c523586072 --- /dev/null +++ b/crates/miden-standards/asm/account_components/policies/burn/mod.masm @@ -0,0 +1,6 @@ +# The MASM code of the `allow_all` Burn Policy Account Component (auth-controlled family). +# +# Exposes the `allow_all` procedure so its MAST root can be registered as the active +# (or allowed) policy on a `BurnPolicyManager`. Storage-free. + +pub use ::miden::standards::policies::burn::allow_all diff --git a/crates/miden-standards/asm/account_components/policies/burn/owner_controlled/owner_only.masm b/crates/miden-standards/asm/account_components/policies/burn/owner_controlled/owner_only.masm new file mode 100644 index 0000000000..aff7e0e7ec --- /dev/null +++ b/crates/miden-standards/asm/account_components/policies/burn/owner_controlled/owner_only.masm @@ -0,0 +1,6 @@ +# The MASM code of the `owner_only` Burn Policy Account Component (owner-controlled family). +# +# Exposes the `owner_only` procedure so its MAST root can be registered as the active +# (or allowed) policy on a `BurnPolicyManager`. Storage-free. + +pub use ::miden::standards::policies::burn::owner_controlled::owner_only diff --git a/crates/miden-standards/asm/account_components/policies/burn/policy_manager.masm b/crates/miden-standards/asm/account_components/policies/burn/policy_manager.masm new file mode 100644 index 0000000000..16bec7ef2b --- /dev/null +++ b/crates/miden-standards/asm/account_components/policies/burn/policy_manager.masm @@ -0,0 +1,9 @@ +# The MASM code of the Burn Policy Manager Account Component. +# +# Owns the three policy-manager storage slots (authority, active_policy_proc_root, +# allowed_policy_proc_roots) and exposes the management procedures. Pair with any +# burn policy component whose procedure root is registered in the allowed-policies map. + +pub use ::miden::standards::policies::burn::policy_manager::set_burn_policy +pub use ::miden::standards::policies::burn::policy_manager::get_burn_policy +pub use ::miden::standards::policies::burn::policy_manager::execute_burn_policy diff --git a/crates/miden-standards/asm/account_components/policies/mint/mod.masm b/crates/miden-standards/asm/account_components/policies/mint/mod.masm new file mode 100644 index 0000000000..4f5269df3f --- /dev/null +++ b/crates/miden-standards/asm/account_components/policies/mint/mod.masm @@ -0,0 +1,6 @@ +# The MASM code of the `allow_all` Mint Policy Account Component (auth-controlled family). +# +# Exposes the `allow_all` procedure so its MAST root can be registered as the active +# (or allowed) policy on a `MintPolicyManager`. Storage-free. + +pub use ::miden::standards::policies::mint::allow_all diff --git a/crates/miden-standards/asm/account_components/policies/mint/owner_controlled/owner_only.masm b/crates/miden-standards/asm/account_components/policies/mint/owner_controlled/owner_only.masm new file mode 100644 index 0000000000..3d5046a778 --- /dev/null +++ b/crates/miden-standards/asm/account_components/policies/mint/owner_controlled/owner_only.masm @@ -0,0 +1,6 @@ +# The MASM code of the `owner_only` Mint Policy Account Component (owner-controlled family). +# +# Exposes the `owner_only` procedure so its MAST root can be registered as the active +# (or allowed) policy on a `MintPolicyManager`. Storage-free. + +pub use ::miden::standards::policies::mint::owner_controlled::owner_only diff --git a/crates/miden-standards/asm/account_components/policies/mint/policy_manager.masm b/crates/miden-standards/asm/account_components/policies/mint/policy_manager.masm new file mode 100644 index 0000000000..c0e41151b0 --- /dev/null +++ b/crates/miden-standards/asm/account_components/policies/mint/policy_manager.masm @@ -0,0 +1,9 @@ +# The MASM code of the Mint Policy Manager Account Component. +# +# Owns the three policy-manager storage slots (authority, active_policy_proc_root, +# allowed_policy_proc_roots) and exposes the management procedures. Pair with any +# mint policy component whose procedure root is registered in the allowed-policies map. + +pub use ::miden::standards::policies::mint::policy_manager::set_mint_policy +pub use ::miden::standards::policies::mint::policy_manager::get_mint_policy +pub use ::miden::standards::policies::mint::policy_manager::execute_mint_policy diff --git a/crates/miden-standards/asm/standards/faucets/basic_fungible.masm b/crates/miden-standards/asm/standards/faucets/basic_fungible.masm index 9e14890fb5..4f311420db 100644 --- a/crates/miden-standards/asm/standards/faucets/basic_fungible.masm +++ b/crates/miden-standards/asm/standards/faucets/basic_fungible.masm @@ -7,7 +7,7 @@ # ================================================================================================= use miden::standards::faucets -use miden::standards::mint_policies::policy_manager +use miden::standards::policies::mint::policy_manager # PROCEDURES # ================================================================================================= diff --git a/crates/miden-standards/asm/standards/faucets/mod.masm b/crates/miden-standards/asm/standards/faucets/mod.masm index f121361689..26c42671b0 100644 --- a/crates/miden-standards/asm/standards/faucets/mod.masm +++ b/crates/miden-standards/asm/standards/faucets/mod.masm @@ -4,7 +4,7 @@ use miden::protocol::faucet use miden::protocol::native_account use miden::protocol::output_note use miden::protocol::asset -use miden::standards::burn_policies::policy_manager +use miden::standards::policies::burn::policy_manager use miden::protocol::asset::FUNGIBLE_ASSET_MAX_AMOUNT use miden::standards::metadata::fungible_faucet::TOKEN_METADATA_SLOT diff --git a/crates/miden-standards/asm/standards/faucets/network_fungible.masm b/crates/miden-standards/asm/standards/faucets/network_fungible.masm index f8d6a4c17b..02a6973c54 100644 --- a/crates/miden-standards/asm/standards/faucets/network_fungible.masm +++ b/crates/miden-standards/asm/standards/faucets/network_fungible.masm @@ -5,7 +5,7 @@ # ================================================================================================= use miden::standards::faucets -use miden::standards::mint_policies::policy_manager +use miden::standards::policies::mint::policy_manager # PUBLIC INTERFACE # ================================================================================================ diff --git a/crates/miden-standards/asm/standards/burn_policies/mod.masm b/crates/miden-standards/asm/standards/policies/burn/mod.masm similarity index 100% rename from crates/miden-standards/asm/standards/burn_policies/mod.masm rename to crates/miden-standards/asm/standards/policies/burn/mod.masm diff --git a/crates/miden-standards/asm/standards/burn_policies/owner_controlled.masm b/crates/miden-standards/asm/standards/policies/burn/owner_controlled/mod.masm similarity index 100% rename from crates/miden-standards/asm/standards/burn_policies/owner_controlled.masm rename to crates/miden-standards/asm/standards/policies/burn/owner_controlled/mod.masm diff --git a/crates/miden-standards/asm/standards/burn_policies/policy_manager.masm b/crates/miden-standards/asm/standards/policies/burn/policy_manager.masm similarity index 100% rename from crates/miden-standards/asm/standards/burn_policies/policy_manager.masm rename to crates/miden-standards/asm/standards/policies/burn/policy_manager.masm diff --git a/crates/miden-standards/asm/standards/mint_policies/mod.masm b/crates/miden-standards/asm/standards/policies/mint/mod.masm similarity index 100% rename from crates/miden-standards/asm/standards/mint_policies/mod.masm rename to crates/miden-standards/asm/standards/policies/mint/mod.masm diff --git a/crates/miden-standards/asm/standards/mint_policies/owner_controlled.masm b/crates/miden-standards/asm/standards/policies/mint/owner_controlled/mod.masm similarity index 100% rename from crates/miden-standards/asm/standards/mint_policies/owner_controlled.masm rename to crates/miden-standards/asm/standards/policies/mint/owner_controlled/mod.masm diff --git a/crates/miden-standards/asm/standards/mint_policies/policy_manager.masm b/crates/miden-standards/asm/standards/policies/mint/policy_manager.masm similarity index 100% rename from crates/miden-standards/asm/standards/mint_policies/policy_manager.masm rename to crates/miden-standards/asm/standards/policies/mint/policy_manager.masm diff --git a/crates/miden-standards/src/account/burn_policies/auth_controlled.rs b/crates/miden-standards/src/account/burn_policies/auth_controlled.rs deleted file mode 100644 index 42b9dd08a3..0000000000 --- a/crates/miden-standards/src/account/burn_policies/auth_controlled.rs +++ /dev/null @@ -1,162 +0,0 @@ -use miden_protocol::Word; -use miden_protocol::account::component::{ - AccountComponentMetadata, - StorageSchema, - StorageSlotSchema, -}; -use miden_protocol::account::{AccountComponent, AccountType, StorageSlot, StorageSlotName}; - -use super::BurnPolicyAuthority; -use crate::account::components::burn_auth_controlled_library; -use crate::account::policy_manager::auth_controlled_initial_storage_slots; -use crate::procedure_digest; - -// BURN POLICY AUTH CONTROLLED -// ================================================================================================ - -// Initialize the digest of the `allow_all` procedure of the burn auth-controlled policy component -// only once. -procedure_digest!( - ALLOW_ALL_POLICY_ROOT, - BurnAuthControlled::NAME, - BurnAuthControlled::ALLOW_ALL_PROC_NAME, - burn_auth_controlled_library -); - -/// Initial policy configuration for the [`BurnAuthControlled`] component. -#[derive(Debug, Clone, Copy, Default)] -pub enum BurnAuthControlledConfig { - /// Sets the initial policy to `allow_all`. - #[default] - AllowAll, - /// Sets a custom initial policy root. - CustomInitialRoot(Word), -} - -/// An [`AccountComponent`] providing configurable burn-policy management for fungible faucets. -/// -/// It reexports policy procedures from `miden::standards::burn_policies` and manager procedures -/// from `miden::standards::burn_policies::policy_manager`: -/// - `allow_all` -/// - `set_burn_policy` -/// - `get_burn_policy` -/// -/// ## Storage Layout -/// -/// - [`Self::active_policy_proc_root_slot`]: Procedure root of the active burn policy. -/// - [`Self::allowed_policy_proc_roots_slot`]: Set of allowed burn policy procedure roots. -/// - [`Self::policy_authority_slot`]: Policy authority mode -/// ([`BurnPolicyAuthority::AuthControlled`] = tx auth, [`BurnPolicyAuthority::OwnerControlled`] = -/// external owner). -#[derive(Debug, Clone, Copy)] -pub struct BurnAuthControlled { - pub(crate) initial_policy_root: Word, -} - -impl BurnAuthControlled { - // CONSTANTS - // -------------------------------------------------------------------------------------------- - - /// The name of the component. - pub const NAME: &'static str = "miden::standards::components::burn_policies::auth_controlled"; - - const ALLOW_ALL_PROC_NAME: &str = "allow_all"; - - // PUBLIC ACCESSORS - // -------------------------------------------------------------------------------------------- - - /// Creates a new [`BurnAuthControlled`] component from the provided configuration. - pub fn new(policy: BurnAuthControlledConfig) -> Self { - let initial_policy_root = match policy { - BurnAuthControlledConfig::AllowAll => Self::allow_all_policy_root(), - BurnAuthControlledConfig::CustomInitialRoot(root) => root, - }; - - Self { initial_policy_root } - } - - /// Creates a new [`BurnAuthControlled`] component with `allow_all` policy. - pub fn allow_all() -> Self { - Self::new(BurnAuthControlledConfig::AllowAll) - } - - /// Returns the [`StorageSlotName`] where the active burn policy procedure root is stored. - pub fn active_policy_proc_root_slot() -> &'static StorageSlotName { - super::active_policy_proc_root_slot_name() - } - - /// Returns the [`StorageSlotName`] where allowed policy roots are stored. - pub fn allowed_policy_proc_roots_slot() -> &'static StorageSlotName { - super::allowed_policy_proc_roots_slot_name() - } - - /// Returns the storage slot schema for the active burn policy root. - pub fn active_policy_proc_root_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - super::active_policy_proc_root_slot_schema() - } - - /// Returns the storage slot schema for the allowed policy roots map. - pub fn allowed_policy_proc_roots_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - super::allowed_policy_proc_roots_slot_schema() - } - - /// Returns the [`StorageSlotName`] containing policy authority mode. - pub fn policy_authority_slot() -> &'static StorageSlotName { - BurnPolicyAuthority::slot() - } - - /// Returns the storage slot schema for policy authority mode. - pub fn policy_authority_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - super::policy_authority_slot_schema() - } - - /// Policy authority slot with this component's fixed mode - /// ([`BurnPolicyAuthority::AuthControlled`]). - pub fn policy_authority_value_slot() -> StorageSlot { - StorageSlot::from(BurnPolicyAuthority::AuthControlled) - } - - /// Returns the default `allow_all` policy procedure root (MAST digest). - pub fn allow_all_policy_root() -> Word { - *ALLOW_ALL_POLICY_ROOT - } - - /// Returns the policy authority used by this component. - pub fn burn_policy_authority(&self) -> BurnPolicyAuthority { - BurnPolicyAuthority::AuthControlled - } -} - -impl Default for BurnAuthControlled { - fn default() -> Self { - Self::allow_all() - } -} - -impl From for AccountComponent { - fn from(auth_controlled: BurnAuthControlled) -> Self { - let slots = auth_controlled_initial_storage_slots( - auth_controlled.initial_policy_root, - BurnAuthControlled::active_policy_proc_root_slot(), - BurnAuthControlled::allowed_policy_proc_roots_slot(), - BurnAuthControlled::policy_authority_value_slot(), - BurnAuthControlled::allow_all_policy_root(), - ); - - let storage_schema = StorageSchema::new(vec![ - BurnAuthControlled::active_policy_proc_root_slot_schema(), - BurnAuthControlled::allowed_policy_proc_roots_slot_schema(), - BurnAuthControlled::policy_authority_slot_schema(), - ]) - .expect("storage schema should be valid"); - - let metadata = - AccountComponentMetadata::new(BurnAuthControlled::NAME, [AccountType::FungibleFaucet]) - .with_description("Burn policy auth controlled component for fungible faucets") - .with_storage_schema(storage_schema); - - AccountComponent::new(burn_auth_controlled_library(), slots, metadata).expect( - "burn policy auth controlled component should satisfy the requirements of a valid account component", - ) - } -} diff --git a/crates/miden-standards/src/account/burn_policies/mod.rs b/crates/miden-standards/src/account/burn_policies/mod.rs deleted file mode 100644 index 97c25e46c4..0000000000 --- a/crates/miden-standards/src/account/burn_policies/mod.rs +++ /dev/null @@ -1,101 +0,0 @@ -use miden_protocol::Word; -use miden_protocol::account::component::{FeltSchema, SchemaType, StorageSlotSchema}; -use miden_protocol::account::{StorageSlot, StorageSlotName}; -use miden_protocol::utils::sync::LazyLock; - -mod auth_controlled; -mod owner_controlled; - -pub use auth_controlled::{BurnAuthControlled, BurnAuthControlledConfig}; -pub use owner_controlled::{BurnOwnerControlled, BurnOwnerControlledConfig}; - -static POLICY_AUTHORITY_SLOT_NAME: LazyLock = LazyLock::new(|| { - StorageSlotName::new("miden::standards::burn_policy_manager::policy_authority") - .expect("storage slot name should be valid") -}); - -static ACTIVE_POLICY_PROC_ROOT_SLOT_NAME: LazyLock = LazyLock::new(|| { - StorageSlotName::new("miden::standards::burn_policy_manager::active_policy_proc_root") - .expect("storage slot name should be valid") -}); - -static ALLOWED_POLICY_PROC_ROOTS_SLOT_NAME: LazyLock = LazyLock::new(|| { - StorageSlotName::new("miden::standards::burn_policy_manager::allowed_policy_proc_roots") - .expect("storage slot name should be valid") -}); - -/// Active / allowed policy root slot names shared by auth-controlled and owner-controlled -/// components. -fn active_policy_proc_root_slot_name() -> &'static StorageSlotName { - &ACTIVE_POLICY_PROC_ROOT_SLOT_NAME -} - -fn allowed_policy_proc_roots_slot_name() -> &'static StorageSlotName { - &ALLOWED_POLICY_PROC_ROOTS_SLOT_NAME -} - -/// Shared storage layout for burn policy manager slots (auth- and owner-controlled components). -pub(super) fn active_policy_proc_root_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - ACTIVE_POLICY_PROC_ROOT_SLOT_NAME.clone(), - StorageSlotSchema::value("Active burn policy procedure root", SchemaType::native_word()), - ) -} - -pub(super) fn allowed_policy_proc_roots_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - ALLOWED_POLICY_PROC_ROOTS_SLOT_NAME.clone(), - StorageSlotSchema::map( - "Allowed burn policy procedure roots", - SchemaType::native_word(), - SchemaType::native_word(), - ), - ) -} - -pub(super) fn policy_authority_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - POLICY_AUTHORITY_SLOT_NAME.clone(), - StorageSlotSchema::value( - "Burn policy authority", - [ - FeltSchema::u8("burn_policy_authority"), - FeltSchema::new_void(), - FeltSchema::new_void(), - FeltSchema::new_void(), - ], - ), - ) -} - -/// Identifies which authority is allowed to manage the active burn policy for a faucet. -/// -/// This value is stored in the policy authority slot so the account can distinguish whether burn -/// policy updates are governed by authentication component logic or by the account owner. -#[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum BurnPolicyAuthority { - /// Burn policy changes are authorized by the account's authentication component logic. - AuthControlled = 0, - /// Burn policy changes are authorized by the external account owner. - OwnerControlled = 1, -} - -impl BurnPolicyAuthority { - /// Returns the [`StorageSlotName`] containing the burn policy authority mode. - pub fn slot() -> &'static StorageSlotName { - &POLICY_AUTHORITY_SLOT_NAME - } -} - -impl From for Word { - fn from(value: BurnPolicyAuthority) -> Self { - Word::from([value as u8, 0, 0, 0]) - } -} - -impl From for StorageSlot { - fn from(value: BurnPolicyAuthority) -> Self { - StorageSlot::with_value(BurnPolicyAuthority::slot().clone(), value.into()) - } -} diff --git a/crates/miden-standards/src/account/burn_policies/owner_controlled.rs b/crates/miden-standards/src/account/burn_policies/owner_controlled.rs deleted file mode 100644 index 5722e8258c..0000000000 --- a/crates/miden-standards/src/account/burn_policies/owner_controlled.rs +++ /dev/null @@ -1,215 +0,0 @@ -use alloc::vec::Vec; - -use miden_protocol::Word; -use miden_protocol::account::component::{ - AccountComponentMetadata, - StorageSchema, - StorageSlotSchema, -}; -use miden_protocol::account::{ - AccountComponent, - AccountType, - StorageMap, - StorageMapKey, - StorageSlot, - StorageSlotName, -}; - -use super::{BurnAuthControlled, BurnPolicyAuthority}; -use crate::account::components::burn_owner_controlled_library; -use crate::procedure_digest; - -// BURN POLICY OWNER CONTROLLED -// ================================================================================================ - -// Initialize the digest of the `owner_only` procedure of the burn owner-controlled policy component -// only once. -procedure_digest!( - OWNER_ONLY_POLICY_ROOT, - BurnOwnerControlled::NAME, - BurnOwnerControlled::OWNER_ONLY_PROC_NAME, - burn_owner_controlled_library -); - -/// Initial policy configuration for the [`BurnOwnerControlled`] component. -#[derive(Debug, Clone, Copy, Default)] -pub enum BurnOwnerControlledConfig { - /// Sets the initial policy to `allow_all`. - #[default] - AllowAll, - /// Sets the initial policy to `owner_only`. - OwnerOnly, - /// Sets a custom initial policy root. - CustomInitialRoot(Word), -} - -/// An [`AccountComponent`] providing configurable burn-policy management for fungible faucets. -/// -/// It reexports policy procedures from `miden::standards::burn_policies` and manager procedures -/// from `miden::standards::burn_policies::policy_manager`: -/// - `allow_all` -/// - `owner_only` -/// - `set_burn_policy` -/// - `get_burn_policy` -/// -/// ## Storage Layout -/// -/// - [`Self::active_policy_proc_root_slot`]: Procedure root of the active burn policy. -/// - [`Self::allowed_policy_proc_roots_slot`]: Set of allowed burn policy procedure roots. -/// - [`Self::policy_authority_slot`]: Policy authority mode -/// ([`BurnPolicyAuthority::AuthControlled`] = tx auth, [`BurnPolicyAuthority::OwnerControlled`] = -/// external owner). -#[derive(Debug, Clone, Copy)] -pub struct BurnOwnerControlled { - initial_policy_root: Word, -} - -impl BurnOwnerControlled { - // CONSTANTS - // -------------------------------------------------------------------------------------------- - - /// The name of the component. - pub const NAME: &'static str = "miden::standards::components::burn_policies::owner_controlled"; - - const OWNER_ONLY_PROC_NAME: &str = "owner_only"; - - // PUBLIC ACCESSORS - // -------------------------------------------------------------------------------------------- - - /// Creates a new [`BurnOwnerControlled`] component from the provided configuration. - pub fn new(policy: BurnOwnerControlledConfig) -> Self { - let initial_policy_root = match policy { - BurnOwnerControlledConfig::AllowAll => Self::allow_all_policy_root(), - BurnOwnerControlledConfig::OwnerOnly => Self::owner_only_policy_root(), - BurnOwnerControlledConfig::CustomInitialRoot(root) => root, - }; - - Self { initial_policy_root } - } - - /// Creates a new [`BurnOwnerControlled`] component with `allow_all` policy as default. - pub fn allow_all() -> Self { - Self::new(BurnOwnerControlledConfig::AllowAll) - } - - /// Creates a new [`BurnOwnerControlled`] component with owner-only policy. - pub fn owner_only() -> Self { - Self::new(BurnOwnerControlledConfig::OwnerOnly) - } - - /// Returns the [`StorageSlotName`] where the active burn policy procedure root is stored. - pub fn active_policy_proc_root_slot() -> &'static StorageSlotName { - super::active_policy_proc_root_slot_name() - } - - /// Returns the [`StorageSlotName`] where allowed policy roots are stored. - pub fn allowed_policy_proc_roots_slot() -> &'static StorageSlotName { - super::allowed_policy_proc_roots_slot_name() - } - - /// Returns the storage slot schema for the active burn policy root. - pub fn active_policy_proc_root_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - super::active_policy_proc_root_slot_schema() - } - - /// Returns the storage slot schema for the allowed policy roots map. - pub fn allowed_policy_proc_roots_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - super::allowed_policy_proc_roots_slot_schema() - } - - /// Returns the [`StorageSlotName`] containing policy authority mode. - pub fn policy_authority_slot() -> &'static StorageSlotName { - BurnPolicyAuthority::slot() - } - - /// Returns the storage slot schema for policy authority mode. - pub fn policy_authority_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - super::policy_authority_slot_schema() - } - - /// Policy authority slot with this component's fixed mode - /// ([`BurnPolicyAuthority::OwnerControlled`]). - pub fn policy_authority_value_slot() -> StorageSlot { - StorageSlot::from(BurnPolicyAuthority::OwnerControlled) - } - - /// Returns the default `allow_all` policy procedure root (MAST digest). - pub fn allow_all_policy_root() -> Word { - BurnAuthControlled::allow_all_policy_root() - } - - /// Returns the default `owner_only` policy procedure root (MAST digest). - pub fn owner_only_policy_root() -> Word { - *OWNER_ONLY_POLICY_ROOT - } - - /// Returns the policy authority used by this component. - pub fn burn_policy_authority(&self) -> BurnPolicyAuthority { - BurnPolicyAuthority::OwnerControlled - } - - /// Returns the [`AccountComponentMetadata`] for this component. - pub fn component_metadata() -> AccountComponentMetadata { - let storage_schema = StorageSchema::new(vec![ - BurnOwnerControlled::active_policy_proc_root_slot_schema(), - BurnOwnerControlled::allowed_policy_proc_roots_slot_schema(), - BurnOwnerControlled::policy_authority_slot_schema(), - ]) - .expect("storage schema should be valid"); - - AccountComponentMetadata::new(BurnOwnerControlled::NAME, [AccountType::FungibleFaucet]) - .with_description("Burn policy owner controlled component for fungible faucets") - .with_storage_schema(storage_schema) - } - - fn initial_storage_slots(&self) -> Vec { - let initial_policy_root = self.initial_policy_root; - let allow_all_procedure_root = Self::allow_all_policy_root(); - let owner_only_procedure_root = Self::owner_only_policy_root(); - let allowed_policy_flag = Word::from([1u32, 0, 0, 0]); - let mut allowed_policy_entries = vec![ - (StorageMapKey::from_raw(allow_all_procedure_root), allowed_policy_flag), - (StorageMapKey::from_raw(owner_only_procedure_root), allowed_policy_flag), - ]; - - if initial_policy_root != allow_all_procedure_root - && initial_policy_root != owner_only_procedure_root - { - allowed_policy_entries - .push((StorageMapKey::from_raw(initial_policy_root), allowed_policy_flag)); - } - - let allowed_policy_proc_roots = StorageMap::with_entries(allowed_policy_entries) - .expect("allowed burn policy roots should have unique keys"); - - vec![ - StorageSlot::with_value( - Self::active_policy_proc_root_slot().clone(), - initial_policy_root, - ), - StorageSlot::with_map( - Self::allowed_policy_proc_roots_slot().clone(), - allowed_policy_proc_roots, - ), - Self::policy_authority_value_slot(), - ] - } -} - -impl Default for BurnOwnerControlled { - fn default() -> Self { - Self::allow_all() - } -} - -impl From for AccountComponent { - fn from(burn_owner_controlled: BurnOwnerControlled) -> Self { - let slots = burn_owner_controlled.initial_storage_slots(); - - let metadata = BurnOwnerControlled::component_metadata(); - - AccountComponent::new(burn_owner_controlled_library(), slots, metadata).expect( - "burn policy owner controlled component should satisfy the requirements of a valid account component", - ) - } -} diff --git a/crates/miden-standards/src/account/components/mod.rs b/crates/miden-standards/src/account/components/mod.rs index e8a8bea866..e0f9732bbe 100644 --- a/crates/miden-standards/src/account/components/mod.rs +++ b/crates/miden-standards/src/account/components/mod.rs @@ -106,44 +106,60 @@ static FUNGIBLE_TOKEN_METADATA_LIBRARY: LazyLock = LazyLock::new(|| { Library::read_from_bytes(bytes).expect("Shipped Fungible Token Metadata library is well-formed") }); -// Initialize the Mint Policy Owner Controlled library only once. -static MINT_POLICY_OWNER_CONTROLLED_LIBRARY: LazyLock = LazyLock::new(|| { +// Initialize the Mint Policy Manager library only once. +static MINT_POLICY_MANAGER_LIBRARY: LazyLock = LazyLock::new(|| { let bytes = include_bytes!(concat!( env!("OUT_DIR"), - "/assets/account_components/mint_policies/owner_controlled.masl" + "/assets/account_components/policies/mint/policy_manager.masl" )); - Library::read_from_bytes(bytes) - .expect("Shipped Mint Policy Owner Controlled library is well-formed") + Library::read_from_bytes(bytes).expect("Shipped Mint Policy Manager library is well-formed") }); -// Initialize the Mint Policy Auth Controlled library only once. -static MINT_POLICY_AUTH_CONTROLLED_LIBRARY: LazyLock = LazyLock::new(|| { +// Initialize the `allow_all` Mint Policy library only once. +static ALLOW_ALL_MINT_POLICY_LIBRARY: LazyLock = LazyLock::new(|| { let bytes = include_bytes!(concat!( env!("OUT_DIR"), - "/assets/account_components/mint_policies/auth_controlled.masl" + "/assets/account_components/policies/mint/mod.masl" )); - Library::read_from_bytes(bytes) - .expect("Shipped Mint Policy Auth Controlled library is well-formed") + Library::read_from_bytes(bytes).expect("Shipped `allow_all` Mint Policy library is well-formed") }); -// Initialize the Burn Policy Owner Controlled library only once. -static BURN_POLICY_OWNER_CONTROLLED_LIBRARY: LazyLock = LazyLock::new(|| { +// Initialize the `owner_only` Mint Policy library only once. +static OWNER_ONLY_MINT_POLICY_LIBRARY: LazyLock = LazyLock::new(|| { let bytes = include_bytes!(concat!( env!("OUT_DIR"), - "/assets/account_components/burn_policies/owner_controlled.masl" + "/assets/account_components/policies/mint/owner_controlled/owner_only.masl" )); Library::read_from_bytes(bytes) - .expect("Shipped Burn Policy Owner Controlled library is well-formed") + .expect("Shipped `owner_only` Mint Policy library is well-formed") +}); + +// Initialize the Burn Policy Manager library only once. +static BURN_POLICY_MANAGER_LIBRARY: LazyLock = LazyLock::new(|| { + let bytes = include_bytes!(concat!( + env!("OUT_DIR"), + "/assets/account_components/policies/burn/policy_manager.masl" + )); + Library::read_from_bytes(bytes).expect("Shipped Burn Policy Manager library is well-formed") +}); + +// Initialize the `allow_all` Burn Policy library only once. +static ALLOW_ALL_BURN_POLICY_LIBRARY: LazyLock = LazyLock::new(|| { + let bytes = include_bytes!(concat!( + env!("OUT_DIR"), + "/assets/account_components/policies/burn/mod.masl" + )); + Library::read_from_bytes(bytes).expect("Shipped `allow_all` Burn Policy library is well-formed") }); -// Initialize the Burn Policy Auth Controlled library only once. -static BURN_POLICY_AUTH_CONTROLLED_LIBRARY: LazyLock = LazyLock::new(|| { +// Initialize the `owner_only` Burn Policy library only once. +static OWNER_ONLY_BURN_POLICY_LIBRARY: LazyLock = LazyLock::new(|| { let bytes = include_bytes!(concat!( env!("OUT_DIR"), - "/assets/account_components/burn_policies/auth_controlled.masl" + "/assets/account_components/policies/burn/owner_controlled/owner_only.masl" )); Library::read_from_bytes(bytes) - .expect("Shipped Burn Policy Auth Controlled library is well-formed") + .expect("Shipped `owner_only` Burn Policy library is well-formed") }); // METADATA LIBRARIES @@ -174,24 +190,34 @@ pub fn fungible_token_metadata_library() -> Library { FUNGIBLE_TOKEN_METADATA_LIBRARY.clone() } -/// Returns the Mint Policy Owner Controlled Library. -pub fn owner_controlled_library() -> Library { - MINT_POLICY_OWNER_CONTROLLED_LIBRARY.clone() +/// Returns the Mint Policy Manager Library. +pub fn mint_policy_manager_library() -> Library { + MINT_POLICY_MANAGER_LIBRARY.clone() +} + +/// Returns the `allow_all` Mint Policy Library. +pub fn allow_all_mint_policy_library() -> Library { + ALLOW_ALL_MINT_POLICY_LIBRARY.clone() +} + +/// Returns the `owner_only` Mint Policy Library. +pub fn owner_only_mint_policy_library() -> Library { + OWNER_ONLY_MINT_POLICY_LIBRARY.clone() } -/// Returns the Mint Policy Auth Controlled Library. -pub fn auth_controlled_library() -> Library { - MINT_POLICY_AUTH_CONTROLLED_LIBRARY.clone() +/// Returns the Burn Policy Manager Library. +pub fn burn_policy_manager_library() -> Library { + BURN_POLICY_MANAGER_LIBRARY.clone() } -/// Returns the Burn Policy Owner Controlled Library. -pub fn burn_owner_controlled_library() -> Library { - BURN_POLICY_OWNER_CONTROLLED_LIBRARY.clone() +/// Returns the `allow_all` Burn Policy Library. +pub fn allow_all_burn_policy_library() -> Library { + ALLOW_ALL_BURN_POLICY_LIBRARY.clone() } -/// Returns the Burn Policy Auth Controlled Library. -pub fn burn_auth_controlled_library() -> Library { - BURN_POLICY_AUTH_CONTROLLED_LIBRARY.clone() +/// Returns the `owner_only` Burn Policy Library. +pub fn owner_only_burn_policy_library() -> Library { + OWNER_ONLY_BURN_POLICY_LIBRARY.clone() } /// Returns the Singlesig Library. diff --git a/crates/miden-standards/src/account/faucets/basic_fungible.rs b/crates/miden-standards/src/account/faucets/basic_fungible.rs index 63a0d49239..bdabaacf7e 100644 --- a/crates/miden-standards/src/account/faucets/basic_fungible.rs +++ b/crates/miden-standards/src/account/faucets/basic_fungible.rs @@ -12,11 +12,10 @@ use miden_protocol::account::{ use super::FungibleFaucetError; use crate::account::AuthMethod; use crate::account::auth::{AuthSingleSigAcl, AuthSingleSigAclConfig}; -use crate::account::burn_policies::BurnAuthControlled; use crate::account::components::basic_fungible_faucet_library; use crate::account::interface::{AccountComponentInterface, AccountInterface, AccountInterfaceExt}; use crate::account::metadata::FungibleTokenMetadata; -use crate::account::mint_policies::MintAuthControlled; +use crate::account::policies::{burn, mint}; use crate::procedure_digest; // BASIC FUNGIBLE FAUCET ACCOUNT COMPONENT @@ -147,8 +146,8 @@ impl TryFrom<&Account> for BasicFungibleFaucet { /// - [`FungibleTokenMetadata`] (token metadata, name, description, etc.) /// - [`BasicFungibleFaucet`] (mint_and_send and burn procedures) /// - [`AuthSingleSigAcl`] -/// - [`MintAuthControlled`] -/// - [`BurnAuthControlled`] +/// - [`mint::PolicyManager`] + [`mint::AllowAll`] (auth-controlled, allow-all mint policy) +/// - [`burn::PolicyManager`] + [`burn::AllowAll`] (auth-controlled, allow-all burn policy) pub fn create_basic_fungible_faucet( init_seed: [u8; 32], metadata: FungibleTokenMetadata, @@ -191,8 +190,10 @@ pub fn create_basic_fungible_faucet( .with_auth_component(auth_component) .with_component(metadata) .with_component(BasicFungibleFaucet) - .with_component(MintAuthControlled::allow_all()) - .with_component(BurnAuthControlled::allow_all()) + .with_component(mint::PolicyManager::auth_controlled()) + .with_component(mint::AllowAll) + .with_component(burn::PolicyManager::auth_controlled()) + .with_component(burn::AllowAll) .build() .map_err(FungibleFaucetError::AccountError)?; diff --git a/crates/miden-standards/src/account/faucets/network_fungible.rs b/crates/miden-standards/src/account/faucets/network_fungible.rs index 829681a0da..14c4430c26 100644 --- a/crates/miden-standards/src/account/faucets/network_fungible.rs +++ b/crates/miden-standards/src/account/faucets/network_fungible.rs @@ -12,11 +12,10 @@ use miden_protocol::account::{ use super::FungibleFaucetError; use crate::account::access::AccessControl; use crate::account::auth::NoAuth; -use crate::account::burn_policies::BurnOwnerControlled; use crate::account::components::network_fungible_faucet_library; use crate::account::interface::{AccountComponentInterface, AccountInterface, AccountInterfaceExt}; use crate::account::metadata::FungibleTokenMetadata; -use crate::account::mint_policies::MintOwnerControlled; +use crate::account::policies::{burn, mint}; use crate::procedure_digest; // NETWORK FUNGIBLE FAUCET ACCOUNT COMPONENT @@ -151,10 +150,12 @@ impl TryFrom<&Account> for NetworkFungibleFaucet { /// - [`AccountStorageMode::Network`] for storage /// - [`NoAuth`] for authentication /// -/// The storage layout of the faucet account is documented on the [`NetworkFungibleFaucet`] and -/// [`MintOwnerControlled`], [`BurnOwnerControlled`], and -/// [`crate::account::access::Ownable2Step`] component types and -/// contains no additional storage slots for its auth ([`NoAuth`]). +/// The storage layout of the faucet account is documented on the [`NetworkFungibleFaucet`], +/// [`mint::PolicyManager`], [`burn::PolicyManager`], and [`crate::account::access::Ownable2Step`] +/// component types. The mint and burn policy components installed alongside them +/// ([`mint::owner_controlled::OwnerOnly`], [`burn::owner_controlled::OwnerOnly`], +/// [`burn::AllowAll`]) are storage-free. The faucet contains no additional storage slots for its +/// auth ([`NoAuth`]). pub fn create_network_fungible_faucet( init_seed: [u8; 32], metadata: FungibleTokenMetadata, @@ -182,8 +183,15 @@ pub fn create_network_fungible_faucet( .with_component(metadata) .with_component(NetworkFungibleFaucet) .with_component(access_control) - .with_component(MintOwnerControlled::owner_only()) - .with_component(BurnOwnerControlled::allow_all()) + .with_component(mint::PolicyManager::owner_controlled( + mint::owner_controlled::Config::OwnerOnly, + )) + .with_component(mint::owner_controlled::OwnerOnly) + .with_component(burn::PolicyManager::owner_controlled( + burn::owner_controlled::Config::AllowAll, + )) + .with_component(burn::owner_controlled::OwnerOnly) + .with_component(burn::AllowAll) .build() .map_err(FungibleFaucetError::AccountError)?; diff --git a/crates/miden-standards/src/account/mint_policies/auth_controlled.rs b/crates/miden-standards/src/account/mint_policies/auth_controlled.rs deleted file mode 100644 index 228dce8672..0000000000 --- a/crates/miden-standards/src/account/mint_policies/auth_controlled.rs +++ /dev/null @@ -1,165 +0,0 @@ -use miden_protocol::Word; -use miden_protocol::account::component::{ - AccountComponentMetadata, - StorageSchema, - StorageSlotSchema, -}; -use miden_protocol::account::{AccountComponent, AccountType, StorageSlot, StorageSlotName}; - -use super::MintPolicyAuthority; -use crate::account::components::auth_controlled_library; -use crate::account::policy_manager::auth_controlled_initial_storage_slots; -use crate::procedure_digest; - -// MINT POLICY AUTH CONTROLLED -// ================================================================================================ - -// Initialize the digest of the `allow_all` procedure of the mint auth-controlled policy component -// only once. -procedure_digest!( - ALLOW_ALL_POLICY_ROOT, - MintAuthControlled::NAME, - MintAuthControlled::ALLOW_ALL_PROC_NAME, - auth_controlled_library -); - -/// Initial policy configuration for the [`MintAuthControlled`] component. -#[derive(Debug, Clone, Copy, Default)] -pub enum MintAuthControlledConfig { - /// Sets the initial policy to `allow_all`. - #[default] - AllowAll, - /// Sets a custom initial policy root. - CustomInitialRoot(Word), -} - -/// An [`AccountComponent`] providing configurable mint-policy management for network faucets. -/// -/// It reexports policy procedures from `miden::standards::mint_policies` and manager procedures -/// from `miden::standards::mint_policies::policy_manager`: -/// - `allow_all` -/// - `set_mint_policy` -/// - `get_mint_policy` -/// -/// ## Storage Layout -/// -/// - [`Self::active_policy_proc_root_slot`]: Procedure root of the active mint policy. -/// - [`Self::allowed_policy_proc_roots_slot`]: Set of allowed mint policy procedure roots. -/// - [`Self::policy_authority_slot`]: Policy authority mode -/// ([`MintPolicyAuthority::AuthControlled`] = tx auth, [`MintPolicyAuthority::OwnerControlled`] = -/// external owner). -#[derive(Debug, Clone, Copy)] -pub struct MintAuthControlled { - pub(crate) initial_policy_root: Word, -} - -impl MintAuthControlled { - // CONSTANTS - // -------------------------------------------------------------------------------------------- - - /// The name of the component. - pub const NAME: &'static str = "miden::standards::components::mint_policies::auth_controlled"; - - const ALLOW_ALL_PROC_NAME: &str = "allow_all"; - - // PUBLIC ACCESSORS - // -------------------------------------------------------------------------------------------- - - /// Creates a new [`MintAuthControlled`] component from the provided configuration. - pub fn new(policy: MintAuthControlledConfig) -> Self { - let initial_policy_root = match policy { - MintAuthControlledConfig::AllowAll => Self::allow_all_policy_root(), - MintAuthControlledConfig::CustomInitialRoot(root) => root, - }; - - Self { initial_policy_root } - } - - /// Creates a new [`MintAuthControlled`] component with `allow_all` policy as - /// default. - pub fn allow_all() -> Self { - Self::new(MintAuthControlledConfig::AllowAll) - } - - /// Returns the [`StorageSlotName`] where the active mint policy procedure root is stored. - pub fn active_policy_proc_root_slot() -> &'static StorageSlotName { - super::active_policy_proc_root_slot_name() - } - - /// Returns the [`StorageSlotName`] where allowed policy roots are stored. - pub fn allowed_policy_proc_roots_slot() -> &'static StorageSlotName { - super::allowed_policy_proc_roots_slot_name() - } - - /// Returns the storage slot schema for the active mint policy root. - pub fn active_policy_proc_root_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - super::active_policy_proc_root_slot_schema() - } - - /// Returns the storage slot schema for the allowed policy roots map. - pub fn allowed_policy_proc_roots_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - super::allowed_policy_proc_roots_slot_schema() - } - - /// Returns the [`StorageSlotName`] containing policy authority mode. - pub fn policy_authority_slot() -> &'static StorageSlotName { - MintPolicyAuthority::slot() - } - - /// Returns the storage slot schema for policy authority mode. - pub fn policy_authority_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - super::policy_authority_slot_schema() - } - - /// Policy authority slot with this component's fixed mode - /// ([`MintPolicyAuthority::AuthControlled`]). - pub fn policy_authority_value_slot() -> StorageSlot { - StorageSlot::from(MintPolicyAuthority::AuthControlled) - } - - /// Returns the default `allow_all` policy procedure root (MAST digest). - pub fn allow_all_policy_root() -> Word { - *ALLOW_ALL_POLICY_ROOT - } - - /// Returns the policy authority used by this component. - pub fn mint_policy_authority(&self) -> MintPolicyAuthority { - MintPolicyAuthority::AuthControlled - } -} - -impl Default for MintAuthControlled { - fn default() -> Self { - Self::allow_all() - } -} - -impl From for AccountComponent { - fn from(auth_controlled: MintAuthControlled) -> Self { - let slots = auth_controlled_initial_storage_slots( - auth_controlled.initial_policy_root, - MintAuthControlled::active_policy_proc_root_slot(), - MintAuthControlled::allowed_policy_proc_roots_slot(), - MintAuthControlled::policy_authority_value_slot(), - MintAuthControlled::allow_all_policy_root(), - ); - - let storage_schema = StorageSchema::new(vec![ - MintAuthControlled::active_policy_proc_root_slot_schema(), - MintAuthControlled::allowed_policy_proc_roots_slot_schema(), - MintAuthControlled::policy_authority_slot_schema(), - ]) - .expect("storage schema should be valid"); - - let metadata = - AccountComponentMetadata::new(MintAuthControlled::NAME, [AccountType::FungibleFaucet]) - .with_description( - "Mint policy auth controlled component for network fungible faucets", - ) - .with_storage_schema(storage_schema); - - AccountComponent::new(auth_controlled_library(), slots, metadata).expect( - "mint policy auth controlled component should satisfy the requirements of a valid account component", - ) - } -} diff --git a/crates/miden-standards/src/account/mint_policies/mod.rs b/crates/miden-standards/src/account/mint_policies/mod.rs deleted file mode 100644 index 675943da48..0000000000 --- a/crates/miden-standards/src/account/mint_policies/mod.rs +++ /dev/null @@ -1,101 +0,0 @@ -use miden_protocol::Word; -use miden_protocol::account::component::{FeltSchema, SchemaType, StorageSlotSchema}; -use miden_protocol::account::{StorageSlot, StorageSlotName}; -use miden_protocol::utils::sync::LazyLock; - -mod auth_controlled; -mod owner_controlled; - -pub use auth_controlled::{MintAuthControlled, MintAuthControlledConfig}; -pub use owner_controlled::{MintOwnerControlled, MintOwnerControlledConfig}; - -static POLICY_AUTHORITY_SLOT_NAME: LazyLock = LazyLock::new(|| { - StorageSlotName::new("miden::standards::mint_policy_manager::policy_authority") - .expect("storage slot name should be valid") -}); - -static ACTIVE_POLICY_PROC_ROOT_SLOT_NAME: LazyLock = LazyLock::new(|| { - StorageSlotName::new("miden::standards::mint_policy_manager::active_policy_proc_root") - .expect("storage slot name should be valid") -}); - -static ALLOWED_POLICY_PROC_ROOTS_SLOT_NAME: LazyLock = LazyLock::new(|| { - StorageSlotName::new("miden::standards::mint_policy_manager::allowed_policy_proc_roots") - .expect("storage slot name should be valid") -}); - -/// Active / allowed policy root slot names shared by auth-controlled and owner-controlled -/// components -fn active_policy_proc_root_slot_name() -> &'static StorageSlotName { - &ACTIVE_POLICY_PROC_ROOT_SLOT_NAME -} - -fn allowed_policy_proc_roots_slot_name() -> &'static StorageSlotName { - &ALLOWED_POLICY_PROC_ROOTS_SLOT_NAME -} - -/// Shared storage layout for mint policy manager slots (auth- and owner-controlled components). -pub(super) fn active_policy_proc_root_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - ACTIVE_POLICY_PROC_ROOT_SLOT_NAME.clone(), - StorageSlotSchema::value("Active mint policy procedure root", SchemaType::native_word()), - ) -} - -pub(super) fn allowed_policy_proc_roots_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - ALLOWED_POLICY_PROC_ROOTS_SLOT_NAME.clone(), - StorageSlotSchema::map( - "Allowed mint policy procedure roots", - SchemaType::native_word(), - SchemaType::native_word(), - ), - ) -} - -pub(super) fn policy_authority_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - POLICY_AUTHORITY_SLOT_NAME.clone(), - StorageSlotSchema::value( - "Mint policy authority", - [ - FeltSchema::u8("mint_policy_authority"), - FeltSchema::new_void(), - FeltSchema::new_void(), - FeltSchema::new_void(), - ], - ), - ) -} - -/// Identifies which authority is allowed to manage the active mint policy for a faucet. -/// -/// This value is stored in the policy authority slot so the account can distinguish whether mint -/// policy updates are governed by authentication component logic or by the account owner. -#[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum MintPolicyAuthority { - /// Mint policy changes are authorized by the account's authentication component logic. - AuthControlled = 0, - /// Mint policy changes are authorized by the external account owner. - OwnerControlled = 1, -} - -impl MintPolicyAuthority { - /// Returns the [`StorageSlotName`] containing the mint policy authority mode. - pub fn slot() -> &'static StorageSlotName { - &POLICY_AUTHORITY_SLOT_NAME - } -} - -impl From for Word { - fn from(value: MintPolicyAuthority) -> Self { - Word::from([value as u8, 0, 0, 0]) - } -} - -impl From for StorageSlot { - fn from(value: MintPolicyAuthority) -> Self { - StorageSlot::with_value(MintPolicyAuthority::slot().clone(), value.into()) - } -} diff --git a/crates/miden-standards/src/account/mint_policies/owner_controlled.rs b/crates/miden-standards/src/account/mint_policies/owner_controlled.rs deleted file mode 100644 index e0a287a84d..0000000000 --- a/crates/miden-standards/src/account/mint_policies/owner_controlled.rs +++ /dev/null @@ -1,196 +0,0 @@ -use alloc::vec::Vec; - -use miden_protocol::Word; -use miden_protocol::account::component::{ - AccountComponentMetadata, - StorageSchema, - StorageSlotSchema, -}; -use miden_protocol::account::{ - AccountComponent, - AccountType, - StorageMap, - StorageMapKey, - StorageSlot, - StorageSlotName, -}; - -use super::MintPolicyAuthority; -use crate::account::components::owner_controlled_library; -use crate::procedure_digest; - -// MINT POLICY OWNER CONTROLLED -// ================================================================================================ - -// Initialize the digest of the `owner_only` procedure of the mint owner-controlled policy component -// only once. -procedure_digest!( - OWNER_ONLY_POLICY_ROOT, - MintOwnerControlled::NAME, - MintOwnerControlled::OWNER_ONLY_PROC_NAME, - owner_controlled_library -); - -/// Initial policy configuration for the [`MintOwnerControlled`] component. -#[derive(Debug, Clone, Copy, Default)] -pub enum MintOwnerControlledConfig { - /// Sets the initial policy to `owner_only`. - #[default] - OwnerOnly, - /// Sets a custom initial policy root. - CustomInitialRoot(Word), -} - -/// An [`AccountComponent`] providing configurable mint-policy management for network faucets. -/// -/// It reexports policy procedures from `miden::standards::mint_policies` and manager procedures -/// from `miden::standards::mint_policies::policy_manager`: -/// - `owner_only` -/// - `set_mint_policy` -/// - `get_mint_policy` -/// -/// ## Storage Layout -/// -/// - [`Self::active_policy_proc_root_slot`]: Procedure root of the active mint policy. -/// - [`Self::allowed_policy_proc_roots_slot`]: Set of allowed mint policy procedure roots. -/// - [`Self::policy_authority_slot`]: Policy authority mode -/// ([`MintPolicyAuthority::AuthControlled`] = tx auth, [`MintPolicyAuthority::OwnerControlled`] = -/// external owner). -#[derive(Debug, Clone, Copy)] -pub struct MintOwnerControlled { - initial_policy_root: Word, -} - -impl MintOwnerControlled { - // CONSTANTS - // -------------------------------------------------------------------------------------------- - - /// The name of the component. - pub const NAME: &'static str = "miden::standards::components::mint_policies::owner_controlled"; - - const OWNER_ONLY_PROC_NAME: &str = "owner_only"; - - // PUBLIC ACCESSORS - // -------------------------------------------------------------------------------------------- - - /// Creates a new [`MintOwnerControlled`] component from the provided configuration. - pub fn new(policy: MintOwnerControlledConfig) -> Self { - let initial_policy_root = match policy { - MintOwnerControlledConfig::OwnerOnly => Self::owner_only_policy_root(), - MintOwnerControlledConfig::CustomInitialRoot(root) => root, - }; - - Self { initial_policy_root } - } - - /// Creates a new [`MintOwnerControlled`] component with owner-only policy as default. - pub fn owner_only() -> Self { - Self::new(MintOwnerControlledConfig::OwnerOnly) - } - - /// Returns the [`StorageSlotName`] where the active mint policy procedure root is stored. - pub fn active_policy_proc_root_slot() -> &'static StorageSlotName { - super::active_policy_proc_root_slot_name() - } - - /// Returns the [`StorageSlotName`] where allowed policy roots are stored. - pub fn allowed_policy_proc_roots_slot() -> &'static StorageSlotName { - super::allowed_policy_proc_roots_slot_name() - } - - /// Returns the storage slot schema for the active mint policy root. - pub fn active_policy_proc_root_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - super::active_policy_proc_root_slot_schema() - } - - /// Returns the storage slot schema for the allowed policy roots map. - pub fn allowed_policy_proc_roots_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - super::allowed_policy_proc_roots_slot_schema() - } - - /// Returns the [`StorageSlotName`] containing policy authority mode. - pub fn policy_authority_slot() -> &'static StorageSlotName { - MintPolicyAuthority::slot() - } - - /// Returns the storage slot schema for policy authority mode. - pub fn policy_authority_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - super::policy_authority_slot_schema() - } - - /// Policy authority slot with this component's fixed mode - /// ([`MintPolicyAuthority::OwnerControlled`]). - pub fn policy_authority_value_slot() -> StorageSlot { - StorageSlot::from(MintPolicyAuthority::OwnerControlled) - } - - /// Returns the default `owner_only` policy procedure root (MAST digest). - pub fn owner_only_policy_root() -> Word { - *OWNER_ONLY_POLICY_ROOT - } - - /// Returns the policy authority used by this component. - pub fn mint_policy_authority(&self) -> MintPolicyAuthority { - MintPolicyAuthority::OwnerControlled - } - - /// Returns the [`AccountComponentMetadata`] for this component. - pub fn component_metadata() -> AccountComponentMetadata { - let storage_schema = StorageSchema::new(vec![ - MintOwnerControlled::active_policy_proc_root_slot_schema(), - MintOwnerControlled::allowed_policy_proc_roots_slot_schema(), - MintOwnerControlled::policy_authority_slot_schema(), - ]) - .expect("storage schema should be valid"); - - AccountComponentMetadata::new(MintOwnerControlled::NAME, [AccountType::FungibleFaucet]) - .with_description("Mint policy owner controlled component for network fungible faucets") - .with_storage_schema(storage_schema) - } - - fn initial_storage_slots(&self) -> Vec { - let initial_policy_root = self.initial_policy_root; - let owner_only_procedure_root = Self::owner_only_policy_root(); - let allowed_policy_flag = Word::from([1u32, 0, 0, 0]); - let mut allowed_policy_entries = - vec![(StorageMapKey::from_raw(owner_only_procedure_root), allowed_policy_flag)]; - - if initial_policy_root != owner_only_procedure_root { - allowed_policy_entries - .push((StorageMapKey::from_raw(initial_policy_root), allowed_policy_flag)); - } - - let allowed_policy_proc_roots = StorageMap::with_entries(allowed_policy_entries) - .expect("allowed mint policy roots should have unique keys"); - - vec![ - StorageSlot::with_value( - Self::active_policy_proc_root_slot().clone(), - initial_policy_root, - ), - StorageSlot::with_map( - Self::allowed_policy_proc_roots_slot().clone(), - allowed_policy_proc_roots, - ), - Self::policy_authority_value_slot(), - ] - } -} - -impl Default for MintOwnerControlled { - fn default() -> Self { - Self::owner_only() - } -} - -impl From for AccountComponent { - fn from(mint_owner_controlled: MintOwnerControlled) -> Self { - let slots = mint_owner_controlled.initial_storage_slots(); - - let metadata = MintOwnerControlled::component_metadata(); - - AccountComponent::new(owner_controlled_library(), slots, metadata).expect( - "mint policy owner controlled component should satisfy the requirements of a valid account component", - ) - } -} diff --git a/crates/miden-standards/src/account/mod.rs b/crates/miden-standards/src/account/mod.rs index e03614bab8..7b6794f3cd 100644 --- a/crates/miden-standards/src/account/mod.rs +++ b/crates/miden-standards/src/account/mod.rs @@ -2,13 +2,11 @@ use super::auth_method::AuthMethod; pub mod access; pub mod auth; -pub mod burn_policies; pub mod components; pub mod faucets; pub mod interface; pub mod metadata; -pub mod mint_policies; -pub mod policy_manager; +pub mod policies; pub mod wallets; pub use metadata::AccountBuilderSchemaCommitmentExt; diff --git a/crates/miden-standards/src/account/policies/burn/allow_all.rs b/crates/miden-standards/src/account/policies/burn/allow_all.rs new file mode 100644 index 0000000000..2f65430d48 --- /dev/null +++ b/crates/miden-standards/src/account/policies/burn/allow_all.rs @@ -0,0 +1,47 @@ +use miden_protocol::Word; +use miden_protocol::account::component::AccountComponentMetadata; +use miden_protocol::account::{AccountComponent, AccountType}; + +use crate::account::components::allow_all_burn_policy_library; +use crate::procedure_digest; + +// ALLOW-ALL BURN POLICY +// ================================================================================================ + +procedure_digest!( + ALLOW_ALL_POLICY_ROOT, + AllowAll::NAME, + AllowAll::PROC_NAME, + allow_all_burn_policy_library +); + +/// The storage-free `allow_all` burn policy account component. +/// +/// Pair with a [`crate::account::policies::burn::PolicyManager`] whose allowed-policies +/// map includes [`AllowAll::root`]. `allow_all` makes burning permissionless (no additional +/// authorization beyond the manager's authority gate). +#[derive(Debug, Clone, Copy, Default)] +pub struct AllowAll; + +impl AllowAll { + /// The name of the component. + pub const NAME: &'static str = "miden::standards::components::policies::burn::mod"; + + const PROC_NAME: &str = "allow_all"; + + /// Returns the MAST root of the `allow_all` burn policy procedure. + pub fn root() -> Word { + *ALLOW_ALL_POLICY_ROOT + } +} + +impl From for AccountComponent { + fn from(_: AllowAll) -> Self { + let metadata = AccountComponentMetadata::new(AllowAll::NAME, [AccountType::FungibleFaucet]) + .with_description("`allow_all` burn policy for fungible faucets"); + + AccountComponent::new(allow_all_burn_policy_library(), vec![], metadata).expect( + "`allow_all` burn policy component should satisfy the requirements of a valid account component", + ) + } +} diff --git a/crates/miden-standards/src/account/policies/burn/manager.rs b/crates/miden-standards/src/account/policies/burn/manager.rs new file mode 100644 index 0000000000..d5823924a2 --- /dev/null +++ b/crates/miden-standards/src/account/policies/burn/manager.rs @@ -0,0 +1,75 @@ +use miden_protocol::account::StorageSlotName; +use miden_protocol::assembly::Library; +use miden_protocol::utils::sync::LazyLock; + +use super::AllowAll; +use super::owner_controlled::{Config, OwnerOnly}; +use crate::account::components::burn_policy_manager_library; +use crate::account::policies::{Burn, PolicyAuthority, PolicyKind, PolicyManager}; + +// STORAGE SLOT NAMES +// ================================================================================================ + +static POLICY_AUTHORITY_SLOT_NAME: LazyLock = LazyLock::new(|| { + StorageSlotName::new("miden::standards::burn_policy_manager::policy_authority") + .expect("storage slot name should be valid") +}); + +static ACTIVE_POLICY_PROC_ROOT_SLOT_NAME: LazyLock = LazyLock::new(|| { + StorageSlotName::new("miden::standards::burn_policy_manager::active_policy_proc_root") + .expect("storage slot name should be valid") +}); + +static ALLOWED_POLICY_PROC_ROOTS_SLOT_NAME: LazyLock = LazyLock::new(|| { + StorageSlotName::new("miden::standards::burn_policy_manager::allowed_policy_proc_roots") + .expect("storage slot name should be valid") +}); + +// POLICY KIND IMPL +// ================================================================================================ + +impl PolicyKind for Burn { + const COMPONENT_NAME: &'static str = + "miden::standards::components::policies::burn::policy_manager"; + const COMPONENT_DESCRIPTION: &'static str = "Burn policy manager for fungible faucets"; + const ACTIVE_POLICY_DESC: &'static str = "Active burn policy procedure root"; + const ALLOWED_POLICIES_DESC: &'static str = "Allowed burn policy procedure roots"; + const AUTHORITY_DESC: &'static str = "Burn policy authority"; + const AUTHORITY_FELT_LABEL: &'static str = "burn_policy_authority"; + + fn library() -> Library { + burn_policy_manager_library() + } + + fn active_policy_slot() -> &'static StorageSlotName { + &ACTIVE_POLICY_PROC_ROOT_SLOT_NAME + } + + fn allowed_policies_slot() -> &'static StorageSlotName { + &ALLOWED_POLICY_PROC_ROOTS_SLOT_NAME + } + + fn policy_authority_slot() -> &'static StorageSlotName { + &POLICY_AUTHORITY_SLOT_NAME + } +} + +// KIND-SPECIFIC CONSTRUCTORS +// ================================================================================================ + +impl PolicyManager { + /// Convenience: an auth-controlled burn policy manager with `allow_all` as the active (and only + /// allowed) policy. + pub fn auth_controlled() -> Self { + Self::new(PolicyAuthority::AuthControlled, AllowAll::root()) + } + + /// Convenience: an owner-controlled burn policy manager. The active policy is chosen by + /// `config`; both `allow_all` and `owner_only` are registered in the allowed-policies list so + /// the owner can switch between them at runtime via `set_burn_policy`. + pub fn owner_controlled(config: Config) -> Self { + Self::new(PolicyAuthority::OwnerControlled, config.initial_policy_root()) + .with_allowed_policy(AllowAll::root()) + .with_allowed_policy(OwnerOnly::root()) + } +} diff --git a/crates/miden-standards/src/account/policies/burn/mod.rs b/crates/miden-standards/src/account/policies/burn/mod.rs new file mode 100644 index 0000000000..73f98401b1 --- /dev/null +++ b/crates/miden-standards/src/account/policies/burn/mod.rs @@ -0,0 +1,16 @@ +//! Burn policies and the burn policy manager. + +mod allow_all; +pub mod manager; +pub mod owner_controlled; + +pub use allow_all::AllowAll; + +pub use super::PolicyAuthority; + +/// The burn policy manager — kind-specific alias for the generic +/// [`super::PolicyManager`] instantiated with [`super::Burn`]. +/// +/// Kind-specific constructors (`auth_controlled`, `owner_controlled`) are defined in +/// [`manager`]. +pub type PolicyManager = super::PolicyManager; diff --git a/crates/miden-standards/src/account/policies/burn/owner_controlled/mod.rs b/crates/miden-standards/src/account/policies/burn/owner_controlled/mod.rs new file mode 100644 index 0000000000..cc1e831492 --- /dev/null +++ b/crates/miden-standards/src/account/policies/burn/owner_controlled/mod.rs @@ -0,0 +1,47 @@ +//! Owner-controlled burn policies. +//! +//! Each policy under this family is intended to be paired with a +//! [`crate::account::policies::burn::PolicyManager`] configured with +//! [`crate::account::policies::burn::PolicyAuthority::OwnerControlled`]. + +mod owner_only; + +use miden_protocol::Word; +pub use owner_only::OwnerOnly; + +use crate::account::policies::burn::AllowAll; + +// CONFIG +// ================================================================================================ + +/// Initial configuration for an owner-controlled +/// [`crate::account::policies::burn::PolicyManager`]. +/// +/// Passed to [`crate::account::policies::burn::PolicyManager::owner_controlled`] to select which +/// policy is active when the faucet is first created. +/// +/// Note: owner-controlled burn managers register BOTH `owner_only` and `allow_all` as allowed +/// policies so the owner can switch between them at runtime via `set_burn_policy`. This enum only +/// selects the **initial active** policy. +#[derive(Debug, Clone, Copy, Default)] +pub enum Config { + /// Active policy = [`AllowAll::root`] (burns open by default). + #[default] + AllowAll, + /// Active policy = [`OwnerOnly::root`] (burns locked to owner). + OwnerOnly, + /// Active policy = the provided root. Must be one of the allowed policy roots registered on + /// the manager. + CustomInitialRoot(Word), +} + +impl Config { + /// Resolves the config into the concrete policy root to install as the active burn policy. + pub fn initial_policy_root(self) -> Word { + match self { + Self::AllowAll => AllowAll::root(), + Self::OwnerOnly => OwnerOnly::root(), + Self::CustomInitialRoot(root) => root, + } + } +} diff --git a/crates/miden-standards/src/account/policies/burn/owner_controlled/owner_only.rs b/crates/miden-standards/src/account/policies/burn/owner_controlled/owner_only.rs new file mode 100644 index 0000000000..91285401b1 --- /dev/null +++ b/crates/miden-standards/src/account/policies/burn/owner_controlled/owner_only.rs @@ -0,0 +1,51 @@ +use miden_protocol::Word; +use miden_protocol::account::component::AccountComponentMetadata; +use miden_protocol::account::{AccountComponent, AccountType}; + +use crate::account::components::owner_only_burn_policy_library; +use crate::procedure_digest; + +// OWNER-ONLY BURN POLICY +// ================================================================================================ + +procedure_digest!( + OWNER_ONLY_POLICY_ROOT, + OwnerOnly::NAME, + OwnerOnly::PROC_NAME, + owner_only_burn_policy_library +); + +/// The storage-free `owner_only` burn policy account component (owner-controlled family). +/// +/// Pair with a [`crate::account::policies::burn::PolicyManager`] whose allowed-policies +/// map includes [`OwnerOnly::root`]. When active, only the account owner (as recorded by the +/// `Ownable2Step` component) may trigger burn operations. +#[derive(Debug, Clone, Copy, Default)] +pub struct OwnerOnly; + +impl OwnerOnly { + /// The name of the component. + pub const NAME: &'static str = + "miden::standards::components::policies::burn::owner_controlled::owner_only"; + + const PROC_NAME: &str = "owner_only"; + + /// Returns the MAST root of the `owner_only` burn policy procedure. + pub fn root() -> Word { + *OWNER_ONLY_POLICY_ROOT + } +} + +impl From for AccountComponent { + fn from(_: OwnerOnly) -> Self { + let metadata = + AccountComponentMetadata::new(OwnerOnly::NAME, [AccountType::FungibleFaucet]) + .with_description( + "`owner_only` burn policy (owner-controlled family) for fungible faucets", + ); + + AccountComponent::new(owner_only_burn_policy_library(), vec![], metadata).expect( + "`owner_only` burn policy component should satisfy the requirements of a valid account component", + ) + } +} diff --git a/crates/miden-standards/src/account/policies/mint/allow_all.rs b/crates/miden-standards/src/account/policies/mint/allow_all.rs new file mode 100644 index 0000000000..d7afc48186 --- /dev/null +++ b/crates/miden-standards/src/account/policies/mint/allow_all.rs @@ -0,0 +1,47 @@ +use miden_protocol::Word; +use miden_protocol::account::component::AccountComponentMetadata; +use miden_protocol::account::{AccountComponent, AccountType}; + +use crate::account::components::allow_all_mint_policy_library; +use crate::procedure_digest; + +// ALLOW-ALL MINT POLICY +// ================================================================================================ + +procedure_digest!( + ALLOW_ALL_POLICY_ROOT, + AllowAll::NAME, + AllowAll::PROC_NAME, + allow_all_mint_policy_library +); + +/// The storage-free `allow_all` mint policy account component. +/// +/// Pair with a [`crate::account::policies::mint::PolicyManager`] whose allowed-policies +/// map includes [`AllowAll::root`]. `allow_all` makes minting permissionless (no additional +/// authorization beyond the manager's authority gate). +#[derive(Debug, Clone, Copy, Default)] +pub struct AllowAll; + +impl AllowAll { + /// The name of the component. + pub const NAME: &'static str = "miden::standards::components::policies::mint::mod"; + + const PROC_NAME: &str = "allow_all"; + + /// Returns the MAST root of the `allow_all` mint policy procedure. + pub fn root() -> Word { + *ALLOW_ALL_POLICY_ROOT + } +} + +impl From for AccountComponent { + fn from(_: AllowAll) -> Self { + let metadata = AccountComponentMetadata::new(AllowAll::NAME, [AccountType::FungibleFaucet]) + .with_description("`allow_all` mint policy for fungible faucets"); + + AccountComponent::new(allow_all_mint_policy_library(), vec![], metadata).expect( + "`allow_all` mint policy component should satisfy the requirements of a valid account component", + ) + } +} diff --git a/crates/miden-standards/src/account/policies/mint/manager.rs b/crates/miden-standards/src/account/policies/mint/manager.rs new file mode 100644 index 0000000000..a831627c46 --- /dev/null +++ b/crates/miden-standards/src/account/policies/mint/manager.rs @@ -0,0 +1,74 @@ +use miden_protocol::account::StorageSlotName; +use miden_protocol::assembly::Library; +use miden_protocol::utils::sync::LazyLock; + +use super::AllowAll; +use super::owner_controlled::{Config, OwnerOnly}; +use crate::account::components::mint_policy_manager_library; +use crate::account::policies::{Mint, PolicyAuthority, PolicyKind, PolicyManager}; + +// STORAGE SLOT NAMES +// ================================================================================================ + +static POLICY_AUTHORITY_SLOT_NAME: LazyLock = LazyLock::new(|| { + StorageSlotName::new("miden::standards::mint_policy_manager::policy_authority") + .expect("storage slot name should be valid") +}); + +static ACTIVE_POLICY_PROC_ROOT_SLOT_NAME: LazyLock = LazyLock::new(|| { + StorageSlotName::new("miden::standards::mint_policy_manager::active_policy_proc_root") + .expect("storage slot name should be valid") +}); + +static ALLOWED_POLICY_PROC_ROOTS_SLOT_NAME: LazyLock = LazyLock::new(|| { + StorageSlotName::new("miden::standards::mint_policy_manager::allowed_policy_proc_roots") + .expect("storage slot name should be valid") +}); + +// POLICY KIND IMPL +// ================================================================================================ + +impl PolicyKind for Mint { + const COMPONENT_NAME: &'static str = + "miden::standards::components::policies::mint::policy_manager"; + const COMPONENT_DESCRIPTION: &'static str = "Mint policy manager for fungible faucets"; + const ACTIVE_POLICY_DESC: &'static str = "Active mint policy procedure root"; + const ALLOWED_POLICIES_DESC: &'static str = "Allowed mint policy procedure roots"; + const AUTHORITY_DESC: &'static str = "Mint policy authority"; + const AUTHORITY_FELT_LABEL: &'static str = "mint_policy_authority"; + + fn library() -> Library { + mint_policy_manager_library() + } + + fn active_policy_slot() -> &'static StorageSlotName { + &ACTIVE_POLICY_PROC_ROOT_SLOT_NAME + } + + fn allowed_policies_slot() -> &'static StorageSlotName { + &ALLOWED_POLICY_PROC_ROOTS_SLOT_NAME + } + + fn policy_authority_slot() -> &'static StorageSlotName { + &POLICY_AUTHORITY_SLOT_NAME + } +} + +// KIND-SPECIFIC CONSTRUCTORS +// ================================================================================================ + +impl PolicyManager { + /// Convenience: an auth-controlled mint policy manager with `allow_all` as the active (and only + /// allowed) policy. + pub fn auth_controlled() -> Self { + Self::new(PolicyAuthority::AuthControlled, AllowAll::root()) + } + + /// Convenience: an owner-controlled mint policy manager. The active policy is chosen by + /// `config`; [`OwnerOnly::root`] is always registered in the allowed-policies list so the + /// owner can switch to it at runtime if a different active policy was chosen initially. + pub fn owner_controlled(config: Config) -> Self { + Self::new(PolicyAuthority::OwnerControlled, config.initial_policy_root()) + .with_allowed_policy(OwnerOnly::root()) + } +} diff --git a/crates/miden-standards/src/account/policies/mint/mod.rs b/crates/miden-standards/src/account/policies/mint/mod.rs new file mode 100644 index 0000000000..9f94f7e61d --- /dev/null +++ b/crates/miden-standards/src/account/policies/mint/mod.rs @@ -0,0 +1,16 @@ +//! Mint policies and the mint policy manager. + +mod allow_all; +pub mod manager; +pub mod owner_controlled; + +pub use allow_all::AllowAll; + +pub use super::PolicyAuthority; + +/// The mint policy manager — kind-specific alias for the generic +/// [`super::PolicyManager`] instantiated with [`super::Mint`]. +/// +/// Kind-specific constructors (`auth_controlled`, `owner_controlled`) are defined in +/// [`manager`]. +pub type PolicyManager = super::PolicyManager; diff --git a/crates/miden-standards/src/account/policies/mint/owner_controlled/mod.rs b/crates/miden-standards/src/account/policies/mint/owner_controlled/mod.rs new file mode 100644 index 0000000000..e4eaa13d07 --- /dev/null +++ b/crates/miden-standards/src/account/policies/mint/owner_controlled/mod.rs @@ -0,0 +1,39 @@ +//! Owner-controlled mint policies. +//! +//! Each policy under this family is intended to be paired with a +//! [`crate::account::policies::mint::PolicyManager`] configured with +//! [`crate::account::policies::mint::PolicyAuthority::OwnerControlled`]. + +mod owner_only; + +use miden_protocol::Word; +pub use owner_only::OwnerOnly; + +// CONFIG +// ================================================================================================ + +/// Initial configuration for an owner-controlled +/// [`crate::account::policies::mint::PolicyManager`]. +/// +/// Passed to [`crate::account::policies::mint::PolicyManager::owner_controlled`] to select which +/// policy is active when the faucet is first created. Future owner-controlled mint policies will +/// show up here as additional variants. +#[derive(Debug, Clone, Copy, Default)] +pub enum Config { + /// Active policy = [`OwnerOnly::root`] (mint gated by the account owner). + #[default] + OwnerOnly, + /// Active policy = the provided root. Must be one of the allowed policy roots registered on + /// the manager. + CustomInitialRoot(Word), +} + +impl Config { + /// Resolves the config into the concrete policy root to install as the active mint policy. + pub fn initial_policy_root(self) -> Word { + match self { + Self::OwnerOnly => OwnerOnly::root(), + Self::CustomInitialRoot(root) => root, + } + } +} diff --git a/crates/miden-standards/src/account/policies/mint/owner_controlled/owner_only.rs b/crates/miden-standards/src/account/policies/mint/owner_controlled/owner_only.rs new file mode 100644 index 0000000000..e009ab5a81 --- /dev/null +++ b/crates/miden-standards/src/account/policies/mint/owner_controlled/owner_only.rs @@ -0,0 +1,51 @@ +use miden_protocol::Word; +use miden_protocol::account::component::AccountComponentMetadata; +use miden_protocol::account::{AccountComponent, AccountType}; + +use crate::account::components::owner_only_mint_policy_library; +use crate::procedure_digest; + +// OWNER-ONLY MINT POLICY +// ================================================================================================ + +procedure_digest!( + OWNER_ONLY_POLICY_ROOT, + OwnerOnly::NAME, + OwnerOnly::PROC_NAME, + owner_only_mint_policy_library +); + +/// The storage-free `owner_only` mint policy account component (owner-controlled family). +/// +/// Pair with a [`crate::account::policies::mint::PolicyManager`] whose allowed-policies +/// map includes [`OwnerOnly::root`]. When active, only the account owner (as recorded by the +/// `Ownable2Step` component) may trigger mint operations. +#[derive(Debug, Clone, Copy, Default)] +pub struct OwnerOnly; + +impl OwnerOnly { + /// The name of the component. + pub const NAME: &'static str = + "miden::standards::components::policies::mint::owner_controlled::owner_only"; + + const PROC_NAME: &str = "owner_only"; + + /// Returns the MAST root of the `owner_only` mint policy procedure. + pub fn root() -> Word { + *OWNER_ONLY_POLICY_ROOT + } +} + +impl From for AccountComponent { + fn from(_: OwnerOnly) -> Self { + let metadata = + AccountComponentMetadata::new(OwnerOnly::NAME, [AccountType::FungibleFaucet]) + .with_description( + "`owner_only` mint policy (owner-controlled family) for fungible faucets", + ); + + AccountComponent::new(owner_only_mint_policy_library(), vec![], metadata).expect( + "`owner_only` mint policy component should satisfy the requirements of a valid account component", + ) + } +} diff --git a/crates/miden-standards/src/account/policies/mod.rs b/crates/miden-standards/src/account/policies/mod.rs new file mode 100644 index 0000000000..6151dc375a --- /dev/null +++ b/crates/miden-standards/src/account/policies/mod.rs @@ -0,0 +1,270 @@ +//! Mint and burn policy account components and their policy managers. +//! +//! Policies are the procedures that gate minting and burning of tokens. Each side ([`mint`], +//! [`burn`]) exposes: +//! - A [`PolicyManager`] (via the kind-specific type aliases [`mint::PolicyManager`] / +//! [`burn::PolicyManager`]) that owns the three manager storage slots and the `set_*_policy` / +//! `get_*_policy` / `execute_*_policy` procedures. +//! - Storage-free policy components (e.g. `mint::AllowAll`, `mint::owner_controlled::OwnerOnly`) +//! that install a specific policy procedure on the account. +//! +//! A faucet installs the manager together with at least one policy component whose procedure root +//! is registered in the manager's allowed-policies map. +//! +//! The manager itself is a single generic struct [`PolicyManager`] where `K` is either +//! [`Mint`] or [`Burn`]. The [`PolicyKind`] trait encapsulates the kind-specific static data +//! (library, storage slot names, component name, schema labels). Shared construction logic lives +//! on `impl PolicyManager`; kind-specific constructors (`auth_controlled`, +//! `owner_controlled`) live on `impl PolicyManager` and `impl PolicyManager`. + +use alloc::vec::Vec; +use core::marker::PhantomData; + +use miden_protocol::Word; +use miden_protocol::account::component::{ + AccountComponentMetadata, + FeltSchema, + SchemaType, + StorageSchema, + StorageSlotSchema, +}; +use miden_protocol::account::{ + AccountComponent, + AccountType, + StorageMap, + StorageMapKey, + StorageSlot, + StorageSlotName, +}; +use miden_protocol::assembly::Library; + +pub mod burn; +pub mod mint; + +// MARKERS +// ================================================================================================ + +/// Marker type selecting the mint side of the policy manager. +#[derive(Debug, Clone, Copy)] +pub struct Mint; + +/// Marker type selecting the burn side of the policy manager. +#[derive(Debug, Clone, Copy)] +pub struct Burn; + +// POLICY AUTHORITY +// ================================================================================================ + +/// Identifies which authority is allowed to manage the active policy for a faucet. +/// +/// Shared between mint and burn policy managers — the authority slot stores the same encoding +/// (`0` = `AuthControlled`, `1` = `OwnerControlled`) regardless of side. +#[repr(u8)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PolicyAuthority { + /// Policy changes are authorized by the account's authentication component logic. + AuthControlled = 0, + /// Policy changes are authorized by the external account owner. + OwnerControlled = 1, +} + +impl From for Word { + fn from(value: PolicyAuthority) -> Self { + Word::from([value as u8, 0, 0, 0]) + } +} + +// POLICY KIND TRAIT +// ================================================================================================ + +/// Kind-specific static data for a [`PolicyManager`]. +/// +/// Implementors are the [`Mint`] and [`Burn`] marker types. The trait carries only static +/// constants / function lookups (library, storage slot names, component metadata) — no +/// "business logic"; kind-specific constructors live in inherent impls on +/// `PolicyManager` / `PolicyManager`. +pub trait PolicyKind: Copy { + /// Component name used in `AccountComponentMetadata`. + const COMPONENT_NAME: &'static str; + /// Component description used in `AccountComponentMetadata`. + const COMPONENT_DESCRIPTION: &'static str; + + /// Schema label for the active-policy storage slot. + const ACTIVE_POLICY_DESC: &'static str; + /// Schema label for the allowed-policies storage slot. + const ALLOWED_POLICIES_DESC: &'static str; + /// Schema label for the policy-authority storage slot. + const AUTHORITY_DESC: &'static str; + /// Felt label on the authority slot (e.g. `"mint_policy_authority"`). + const AUTHORITY_FELT_LABEL: &'static str; + + /// Compiled MASM library for this kind's policy manager component. + fn library() -> Library; + + /// Storage slot name holding the active policy procedure root. + fn active_policy_slot() -> &'static StorageSlotName; + /// Storage slot name holding the allowed policy procedure roots map. + fn allowed_policies_slot() -> &'static StorageSlotName; + /// Storage slot name holding the policy authority mode. + fn policy_authority_slot() -> &'static StorageSlotName; +} + +// POLICY MANAGER (generic) +// ================================================================================================ + +/// An [`AccountComponent`] that owns the three policy-manager storage slots and the manager +/// procedures for its [`PolicyKind`]. +/// +/// Users typically interact via the kind-specific aliases [`mint::PolicyManager`] and +/// [`burn::PolicyManager`]. Kind-specific constructors (`auth_controlled`, `owner_controlled`) +/// live in those sides' inherent impls. +/// +/// ## Storage layout +/// +/// - [`Self::active_policy_slot`]: Procedure root of the active policy. +/// - [`Self::allowed_policies_slot`]: Map of allowed policy procedure roots. +/// - [`Self::policy_authority_slot`]: [`PolicyAuthority`] mode. +#[derive(Debug, Clone)] +pub struct PolicyManager { + authority: PolicyAuthority, + active_policy: Word, + allowed_policies: Vec, + _kind: PhantomData, +} + +impl PolicyManager { + // CONSTRUCTORS + // -------------------------------------------------------------------------------------------- + + /// Creates a new manager with the given authority and active policy root. The active policy is + /// automatically added to the allowed-policies list. + pub fn new(authority: PolicyAuthority, active_policy: Word) -> Self { + Self { + authority, + active_policy, + allowed_policies: vec![active_policy], + _kind: PhantomData, + } + } + + /// Registers an additional policy root in the allowed-policies list. + pub fn with_allowed_policy(mut self, policy_root: Word) -> Self { + if !self.allowed_policies.contains(&policy_root) { + self.allowed_policies.push(policy_root); + } + self + } + + // ACCESSORS + // -------------------------------------------------------------------------------------------- + + /// Returns the authority used by this manager. + pub fn authority(&self) -> PolicyAuthority { + self.authority + } + + /// Returns the active policy procedure root. + pub fn active_policy(&self) -> Word { + self.active_policy + } + + /// Returns the allowed policy procedure roots. + pub fn allowed_policies(&self) -> &[Word] { + &self.allowed_policies + } + + /// Returns the [`StorageSlotName`] where the active policy procedure root is stored. + pub fn active_policy_slot() -> &'static StorageSlotName { + K::active_policy_slot() + } + + /// Returns the [`StorageSlotName`] where allowed policy roots are stored. + pub fn allowed_policies_slot() -> &'static StorageSlotName { + K::allowed_policies_slot() + } + + /// Returns the [`StorageSlotName`] containing the policy authority mode. + pub fn policy_authority_slot() -> &'static StorageSlotName { + K::policy_authority_slot() + } + + /// Returns the storage slot schema for the active policy root. + pub fn active_policy_slot_schema() -> (StorageSlotName, StorageSlotSchema) { + ( + K::active_policy_slot().clone(), + StorageSlotSchema::value(K::ACTIVE_POLICY_DESC, SchemaType::native_word()), + ) + } + + /// Returns the storage slot schema for the allowed policy roots map. + pub fn allowed_policies_slot_schema() -> (StorageSlotName, StorageSlotSchema) { + ( + K::allowed_policies_slot().clone(), + StorageSlotSchema::map( + K::ALLOWED_POLICIES_DESC, + SchemaType::native_word(), + SchemaType::native_word(), + ), + ) + } + + /// Returns the storage slot schema for the policy authority mode. + pub fn policy_authority_slot_schema() -> (StorageSlotName, StorageSlotSchema) { + ( + K::policy_authority_slot().clone(), + StorageSlotSchema::value( + K::AUTHORITY_DESC, + [ + FeltSchema::u8(K::AUTHORITY_FELT_LABEL), + FeltSchema::new_void(), + FeltSchema::new_void(), + FeltSchema::new_void(), + ], + ), + ) + } + + /// Returns the [`AccountComponentMetadata`] for this component. + pub fn component_metadata() -> AccountComponentMetadata { + let storage_schema = StorageSchema::new(vec![ + Self::active_policy_slot_schema(), + Self::allowed_policies_slot_schema(), + Self::policy_authority_slot_schema(), + ]) + .expect("storage schema should be valid"); + + AccountComponentMetadata::new(K::COMPONENT_NAME, [AccountType::FungibleFaucet]) + .with_description(K::COMPONENT_DESCRIPTION) + .with_storage_schema(storage_schema) + } + + fn initial_storage_slots(&self) -> Vec { + let allowed_flag = Word::from([1u32, 0, 0, 0]); + let entries: Vec<_> = self + .allowed_policies + .iter() + .map(|root| (StorageMapKey::from_raw(*root), allowed_flag)) + .collect(); + let allowed_map = StorageMap::with_entries(entries) + .expect("allowed policy roots should have unique keys"); + + vec![ + StorageSlot::with_value(K::active_policy_slot().clone(), self.active_policy), + StorageSlot::with_map(K::allowed_policies_slot().clone(), allowed_map), + StorageSlot::with_value(K::policy_authority_slot().clone(), self.authority.into()), + ] + } +} + +impl From> for AccountComponent { + fn from(manager: PolicyManager) -> Self { + AccountComponent::new( + K::library(), + manager.initial_storage_slots(), + PolicyManager::::component_metadata(), + ) + .expect( + "policy manager component should satisfy the requirements of a valid account component", + ) + } +} diff --git a/crates/miden-standards/src/account/policy_manager/mod.rs b/crates/miden-standards/src/account/policy_manager/mod.rs deleted file mode 100644 index bb48f72b26..0000000000 --- a/crates/miden-standards/src/account/policy_manager/mod.rs +++ /dev/null @@ -1,37 +0,0 @@ -use alloc::vec::Vec; - -use miden_protocol::Word; -use miden_protocol::account::{StorageMap, StorageMapKey, StorageSlot, StorageSlotName}; - -/// Builds the three storage slots for an auth-controlled policy manager component. -/// -/// `active_slot` / `allowed_slot` are storage **names**. `allow_all_procedure_root` is the -/// MAST root of the built-in `allow_all` procedure (map key when seeding `allowed_slot`), not -/// a slot. -/// -/// used by mint and burn auth-controlled account components. -pub(crate) fn auth_controlled_initial_storage_slots( - initial_policy_root: Word, - active_slot: &StorageSlotName, - allowed_slot: &StorageSlotName, - authority_slot: StorageSlot, - allow_all_procedure_root: Word, -) -> Vec { - let allowed_policy_flag = Word::from([1u32, 0, 0, 0]); - let mut allowed_policy_entries = - vec![(StorageMapKey::from_raw(allow_all_procedure_root), allowed_policy_flag)]; - - if initial_policy_root != allow_all_procedure_root { - allowed_policy_entries - .push((StorageMapKey::from_raw(initial_policy_root), allowed_policy_flag)); - } - - let allowed_policy_proc_roots = StorageMap::with_entries(allowed_policy_entries) - .expect("allowed policy roots should have unique keys"); - - vec![ - StorageSlot::with_value(active_slot.clone(), initial_policy_root), - StorageSlot::with_map(allowed_slot.clone(), allowed_policy_proc_roots), - authority_slot, - ] -} diff --git a/crates/miden-testing/src/mock_chain/chain_builder.rs b/crates/miden-testing/src/mock_chain/chain_builder.rs index a29f6d2ab1..cba0724834 100644 --- a/crates/miden-testing/src/mock_chain/chain_builder.rs +++ b/crates/miden-testing/src/mock_chain/chain_builder.rs @@ -48,18 +48,15 @@ use miden_protocol::testing::random_secret_key::random_secret_key; use miden_protocol::transaction::{OrderedTransactionHeaders, RawOutputNote, TransactionKernel}; use miden_protocol::{MAX_OUTPUT_NOTES_PER_BATCH, Word}; use miden_standards::account::access::Ownable2Step; -use miden_standards::account::burn_policies::{BurnAuthControlled, BurnOwnerControlled}; use miden_standards::account::faucets::{BasicFungibleFaucet, NetworkFungibleFaucet}; use miden_standards::account::metadata::{ FungibleTokenMetadata, FungibleTokenMetadataBuilder, TokenName, }; -use miden_standards::account::mint_policies::{ - MintAuthControlled, - MintOwnerControlled, - MintOwnerControlledConfig, -}; +use miden_standards::account::policies::burn::owner_controlled::Config as BurnConfig; +use miden_standards::account::policies::mint::owner_controlled::Config as MintConfig; +use miden_standards::account::policies::{burn, mint}; use miden_standards::account::wallets::BasicWallet; use miden_standards::note::{P2idNote, P2ideNote, P2ideNoteStorage, SwapNote}; use miden_standards::testing::account_component::MockAccountComponent; @@ -349,8 +346,10 @@ impl MockChainBuilder { let account_builder = AccountBuilder::new(self.rng.random()) .storage_mode(AccountStorageMode::Public) .account_type(AccountType::FungibleFaucet) - .with_component(MintAuthControlled::allow_all()) - .with_component(BurnAuthControlled::allow_all()) + .with_component(mint::PolicyManager::auth_controlled()) + .with_component(mint::AllowAll) + .with_component(burn::PolicyManager::auth_controlled()) + .with_component(burn::AllowAll) .with_component(metadata) .with_component(BasicFungibleFaucet); @@ -386,8 +385,10 @@ impl MockChainBuilder { .storage_mode(AccountStorageMode::Public) .with_component(metadata) .with_component(BasicFungibleFaucet) - .with_component(MintAuthControlled::allow_all()) - .with_component(BurnAuthControlled::allow_all()) + .with_component(mint::PolicyManager::auth_controlled()) + .with_component(mint::AllowAll) + .with_component(burn::PolicyManager::auth_controlled()) + .with_component(burn::AllowAll) .account_type(AccountType::FungibleFaucet); self.add_account_from_builder(auth_method, account_builder, AccountState::Exists) @@ -396,13 +397,16 @@ impl MockChainBuilder { /// Adds an existing [`NetworkFungibleFaucet`] account to the initial chain state. /// /// Network fungible faucets always use `AccountStorageMode::Network` and `Auth::NoAuth`. + /// + /// `mint_policy` selects the initial active mint policy on the faucet. The installed + /// [`mint::PolicyManager`] is always owner-controlled. pub fn add_existing_network_faucet( &mut self, token_symbol: &str, max_supply: u64, owner_account_id: AccountId, token_supply: Option, - mint_policy: MintOwnerControlledConfig, + mint_policy: MintConfig, ) -> anyhow::Result { let token_supply = token_supply.unwrap_or(0); let name = TokenName::new(token_symbol)?; @@ -424,8 +428,11 @@ impl MockChainBuilder { .with_component(metadata) .with_component(NetworkFungibleFaucet) .with_component(Ownable2Step::new(owner_account_id)) - .with_component(MintOwnerControlled::new(mint_policy)) - .with_component(BurnOwnerControlled::allow_all()) + .with_component(mint::PolicyManager::owner_controlled(mint_policy)) + .with_component(mint::owner_controlled::OwnerOnly) + .with_component(burn::PolicyManager::owner_controlled(BurnConfig::AllowAll)) + .with_component(burn::owner_controlled::OwnerOnly) + .with_component(burn::AllowAll) .account_type(AccountType::FungibleFaucet); // Network faucets always use IncrNonce auth (no authentication) @@ -445,8 +452,11 @@ impl MockChainBuilder { .with_component(metadata) .with_component(NetworkFungibleFaucet) .with_component(Ownable2Step::new(owner_account_id)) - .with_component(MintOwnerControlled::new(MintOwnerControlledConfig::OwnerOnly)) - .with_component(BurnOwnerControlled::allow_all()) + .with_component(mint::PolicyManager::owner_controlled(MintConfig::OwnerOnly)) + .with_component(mint::owner_controlled::OwnerOnly) + .with_component(burn::PolicyManager::owner_controlled(BurnConfig::AllowAll)) + .with_component(burn::owner_controlled::OwnerOnly) + .with_component(burn::AllowAll) .account_type(AccountType::FungibleFaucet); self.add_account_from_builder(Auth::IncrNonce, account_builder, AccountState::Exists) diff --git a/crates/miden-testing/tests/agglayer/bridge_out.rs b/crates/miden-testing/tests/agglayer/bridge_out.rs index 4e928a0d11..2397791a54 100644 --- a/crates/miden-testing/tests/agglayer/bridge_out.rs +++ b/crates/miden-testing/tests/agglayer/bridge_out.rs @@ -19,7 +19,7 @@ use miden_protocol::asset::{Asset, FungibleAsset}; use miden_protocol::note::{NoteAssets, NoteType}; use miden_protocol::transaction::RawOutputNote; use miden_standards::account::faucets::TokenMetadata; -use miden_standards::account::mint_policies::MintOwnerControlledConfig; +use miden_standards::account::policies::mint::owner_controlled::Config as MintConfig; use miden_standards::note::StandardNote; use miden_testing::{Auth, MockChain, assert_transaction_executor_error}; use miden_tx::utils::hex_to_bytes; @@ -381,7 +381,7 @@ async fn b2agg_note_reclaim_scenario() -> anyhow::Result<()> { 1000, faucet_owner_account_id, Some(100), - MintOwnerControlledConfig::OwnerOnly, + MintConfig::OwnerOnly, )?; // Create a bridge admin account @@ -499,7 +499,7 @@ async fn b2agg_note_non_target_account_cannot_consume() -> anyhow::Result<()> { 1000, faucet_owner_account_id, Some(100), - MintOwnerControlledConfig::OwnerOnly, + MintConfig::OwnerOnly, )?; // Create a bridge admin account diff --git a/crates/miden-testing/tests/scripts/faucet.rs b/crates/miden-testing/tests/scripts/faucet.rs index 1ca817fce5..036f15858d 100644 --- a/crates/miden-testing/tests/scripts/faucet.rs +++ b/crates/miden-testing/tests/scripts/faucet.rs @@ -29,10 +29,10 @@ use miden_protocol::testing::account_id::ACCOUNT_ID_PRIVATE_SENDER; use miden_protocol::transaction::{ExecutedTransaction, RawOutputNote}; use miden_protocol::{Felt, Word}; use miden_standards::account::access::Ownable2Step; -use miden_standards::account::burn_policies::BurnOwnerControlled; use miden_standards::account::faucets::{BasicFungibleFaucet, NetworkFungibleFaucet}; use miden_standards::account::metadata::FungibleTokenMetadata; -use miden_standards::account::mint_policies::MintOwnerControlledConfig; +use miden_standards::account::policies::burn; +use miden_standards::account::policies::mint::owner_controlled::Config as MintConfig; use miden_standards::code_builder::CodeBuilder; use miden_standards::errors::standards::{ ERR_BURN_POLICY_ROOT_NOT_ALLOWED, @@ -154,7 +154,7 @@ async fn execute_faucet_note_script( fn create_set_burn_policy_note_script(policy_root: Word) -> String { format!( r#" - use miden::standards::burn_policies::policy_manager + use miden::standards::policies::burn::policy_manager begin padw padw padw @@ -593,7 +593,7 @@ async fn network_faucet_mint() -> anyhow::Result<()> { max_supply, faucet_owner_account_id, Some(token_supply), - MintOwnerControlledConfig::OwnerOnly, + MintConfig::OwnerOnly, )?; // Create a target account to consume the minted note @@ -713,7 +713,7 @@ async fn test_network_faucet_owner_can_mint() -> anyhow::Result<()> { 1000, owner_account_id, Some(50), - MintOwnerControlledConfig::OwnerOnly, + MintConfig::OwnerOnly, )?; let target_account = builder.add_existing_wallet(Auth::IncrNonce)?; let mock_chain = builder.build()?; @@ -767,7 +767,7 @@ async fn test_network_faucet_set_policy_rejects_non_allowed_root() -> anyhow::Re 1000, owner_account_id, Some(0), - MintOwnerControlledConfig::OwnerOnly, + MintConfig::OwnerOnly, )?; let mock_chain = builder.build()?; @@ -775,7 +775,7 @@ async fn test_network_faucet_set_policy_rejects_non_allowed_root() -> anyhow::Re let invalid_policy_root = NetworkFungibleFaucet::mint_and_send_digest(); let set_policy_note_script = format!( r#" - use miden::standards::mint_policies::policy_manager->policy_manager + use miden::standards::policies::mint::policy_manager->policy_manager begin repeat.12 push.0 end @@ -817,7 +817,7 @@ async fn test_network_faucet_set_burn_policy_rejects_non_allowed_root() -> anyho 1000, owner_account_id, Some(0), - MintOwnerControlledConfig::OwnerOnly, + MintConfig::OwnerOnly, )?; let mock_chain = builder.build()?; @@ -863,7 +863,7 @@ async fn test_network_faucet_non_owner_cannot_mint() -> anyhow::Result<()> { 1000, owner_account_id, Some(50), - MintOwnerControlledConfig::OwnerOnly, + MintConfig::OwnerOnly, )?; let target_account = builder.add_existing_wallet(Auth::IncrNonce)?; let mock_chain = builder.build()?; @@ -920,7 +920,7 @@ async fn test_network_faucet_owner_storage() -> anyhow::Result<()> { 1000, owner_account_id, Some(50), - MintOwnerControlledConfig::OwnerOnly, + MintConfig::OwnerOnly, )?; let _mock_chain = builder.build()?; @@ -963,7 +963,7 @@ async fn test_network_faucet_transfer_ownership() -> anyhow::Result<()> { 1000, initial_owner_account_id, Some(50), - MintOwnerControlledConfig::OwnerOnly, + MintConfig::OwnerOnly, )?; let target_account = builder.add_existing_wallet(Auth::IncrNonce)?; @@ -1116,7 +1116,7 @@ async fn test_network_faucet_only_owner_can_transfer() -> anyhow::Result<()> { 1000, owner_account_id, Some(50), - MintOwnerControlledConfig::OwnerOnly, + MintConfig::OwnerOnly, )?; let mock_chain = builder.build()?; @@ -1183,7 +1183,7 @@ async fn test_network_faucet_renounce_ownership() -> anyhow::Result<()> { 1000, owner_account_id, Some(50), - MintOwnerControlledConfig::OwnerOnly, + MintConfig::OwnerOnly, )?; // Check stored value before renouncing @@ -1309,13 +1309,12 @@ fn test_network_faucet_contains_default_burn_policy_root() -> anyhow::Result<()> 200, owner_account_id, Some(100), - MintOwnerControlledConfig::OwnerOnly, + MintConfig::OwnerOnly, )?; - let stored_root = - faucet.storage().get_item(BurnOwnerControlled::active_policy_proc_root_slot())?; + let stored_root = faucet.storage().get_item(burn::PolicyManager::active_policy_slot())?; - assert_eq!(stored_root, BurnOwnerControlled::allow_all_policy_root()); + assert_eq!(stored_root, burn::AllowAll::root()); assert!(faucet.code().has_procedure(stored_root)); Ok(()) @@ -1338,7 +1337,7 @@ async fn network_faucet_burn() -> anyhow::Result<()> { 200, faucet_owner_account_id, Some(100), - MintOwnerControlledConfig::OwnerOnly, + MintConfig::OwnerOnly, )?; let burn_amount = 100u64; @@ -1411,10 +1410,10 @@ async fn test_network_faucet_non_owner_cannot_burn_when_owner_only_policy_active 200, owner_account_id, Some(100), - MintOwnerControlledConfig::OwnerOnly, + MintConfig::OwnerOnly, )?; let set_policy_note_script = - create_set_burn_policy_note_script(BurnOwnerControlled::owner_only_policy_root()); + create_set_burn_policy_note_script(burn::owner_controlled::OwnerOnly::root()); let mut rng = RandomCoin::new([Felt::from(500u32); 4].into()); let set_policy_note = NoteBuilder::new(owner_account_id, &mut rng) .note_type(NoteType::Private) @@ -1469,10 +1468,10 @@ async fn test_network_faucet_owner_can_burn_when_owner_only_policy_active() -> a 200, owner_account_id, Some(100), - MintOwnerControlledConfig::OwnerOnly, + MintConfig::OwnerOnly, )?; let set_policy_note_script = - create_set_burn_policy_note_script(BurnOwnerControlled::owner_only_policy_root()); + create_set_burn_policy_note_script(burn::owner_controlled::OwnerOnly::root()); let mut rng = RandomCoin::new([Felt::from(510u32); 4].into()); let set_policy_note = NoteBuilder::new(owner_account_id, &mut rng) .note_type(NoteType::Private) @@ -1535,7 +1534,7 @@ async fn test_mint_note_output_note_types(#[case] note_type: NoteType) -> anyhow 1000, faucet_owner_account_id, Some(50), - MintOwnerControlledConfig::OwnerOnly, + MintConfig::OwnerOnly, )?; let target_account = builder.add_existing_wallet(Auth::IncrNonce)?;