diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 232b4fe46f..98c1a32839 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -42,6 +42,23 @@ - **Commit authorship:** Always commit as Claude, not as the user. Use: `git -c user.name="Claude (Opus)" -c user.email="noreply@anthropic.com" -c commit.gpgsign=false commit -m "message"` - **Commit frequency:** Always commit at the end of each task. Avoid single commits that span multiple unrelated changes. - **Responding to PR review:** When addressing review feedback on a pushed PR, add new commits on top of the branch (e.g. `fix: address review comments`). NEVER amend, squash, or otherwise rewrite already-pushed commits to incorporate review changes, and NEVER force-push the branch to do so - this destroys the diff reviewers rely on to see what changed since their review. The only time a force-push is acceptable is when the branch must be rebased onto an updated base (or a PR lower in a stack changed); that is a base update, not a review response, and should be called out explicitly. +- **Never post to GitHub unprompted:** Never run `gh pr comment`, `gh pr review`, `gh issue comment`, or `git push` unless explicitly asked in that message. When asked to draft review text, output it in chat for the user to paste - never post it. + +## Scope Discipline + +- Implement the minimum that satisfies the request. Do not add helper abstractions, config knobs, extra bounds/limits, fallback lookups, or "while I was here" refactors. +- Prefer stdlib primitives over hand-rolled equivalents (e.g. `Read::take` over a custom limited reader). +- If extra work seems warranted, list it as a suggestion at the end instead of implementing it. + +## Explain vs. Act + +- When asked "why", "how does X work", or "explain", answer read-only: use Read/Grep only, make no edits and run no build commands unless asked. +- Cite file:line evidence for each claim rather than summarizing from memory. +- When told code has changed outside the session, re-read the files from disk instead of relying on earlier copies. + +## Build & Formatting + +- Formatting must pass nightly rustfmt: run `make format` (i.e. `cargo +nightly fmt --all`) before claiming work is done. Non-nightly formatting fails CI on import ordering. ## Output Formatting diff --git a/CHANGELOG.md b/CHANGELOG.md index 06709798bb..35dc686cc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,6 +59,7 @@ - [BREAKING] Added the `miden::standards::expiration` MASM module with `apply_default` and used it to apply a default 20-block transaction expiration limit to the standard allowlist and blocklist transfer policies and the fee manager's `estimate_note_fee` procedure ([#3512](https://github.com/0xMiden/protocol/pull/3512)). - [BREAKING] Extracted the shared `MastForestScript` type and `MastForestScriptError` backing `NoteScript` / `TransactionScript`, moving `TransactionScript` into `transaction::script` ([#3516](https://github.com/0xMiden/protocol/pull/3516)). - Documented the RBAC freeze-only actor pattern on `Authority` and added test coverage pinning that a `FREEZER` can trip the emergency switch but can never unfreeze the account ([#3520](https://github.com/0xMiden/protocol/pull/3520)). +- [BREAKING] Moved account component metadata from Rust into a `[package.metadata.account-component]` table in each component's `miden-project.toml`, embedding it into the compiled `.masp` package and removing the now-redundant `*_slot_schema` accessors ([#3587](https://github.com/0xMiden/protocol/pull/3587)). - [BREAKING] Replaced the dedicated AggLayer faucet account component with the standard `FungibleFaucet`. `AggLayerFaucet` is now a stateless namespace, `AgglayerFaucetError` and the `miden-agglayer-faucet` MASM package were removed, `AggLayerFaucet::account_builder` and `create_existing_agglayer_faucet` take a token name, and `account_builder` now takes `TokenName` / `TokenSymbol` / `AssetAmount` rather than `&str` / `Felt` ([#3525](https://github.com/0xMiden/protocol/pull/3525)). - [BREAKING] Updated `NoteScript::from_package` and `TransactionScript::from_package` to reject executable packages with the new `MastForestScriptError::ExecutablePackage`, so scripts are identified only by their `@note_script` / `@transaction_script` attribute ([#3528](https://github.com/0xMiden/protocol/pull/3528)). - [BREAKING] Updated `AccountComponent::from_package` to take `Package` by value ([#3528](https://github.com/0xMiden/protocol/pull/3528)). diff --git a/Cargo.lock b/Cargo.lock index 1f3298f245..4e389e8b62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2802,6 +2802,7 @@ dependencies = [ "miden-package-registry", "miden-project", "regex", + "toml", "walkdir", ] diff --git a/Cargo.toml b/Cargo.toml index b4de174a07..308198a6bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -92,5 +92,6 @@ serde_json = { default-features = false, version = "1.0" } syn = { features = ["full"], version = "2" } thiserror = { default-features = false, version = "2.0" } tokio = { default-features = false, features = ["sync"], version = "1" } +toml = { version = "1.0" } tonic = { default-features = false, version = "0.14" } walkdir = { version = "2.5" } diff --git a/crates/miden-agglayer/asm/components/bridge/miden-project.toml b/crates/miden-agglayer/asm/components/bridge/miden-project.toml index 4b44161db2..dc6bf06d05 100644 --- a/crates/miden-agglayer/asm/components/bridge/miden-project.toml +++ b/crates/miden-agglayer/asm/components/bridge/miden-project.toml @@ -12,3 +12,8 @@ miden-agglayer.workspace = true miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "AggLayer bridge" +name = "agglayer::bridge" +version = "1.0.0" diff --git a/crates/miden-agglayer/build.rs b/crates/miden-agglayer/build.rs index 106c01d360..597469a7a9 100644 --- a/crates/miden-agglayer/build.rs +++ b/crates/miden-agglayer/build.rs @@ -16,6 +16,7 @@ use miden_protocol::ProtocolLib; use miden_protocol::account::{AccountCode, AccountComponent, AccountComponentMetadata}; use miden_protocol::note::NoteScriptRoot; use miden_protocol::transaction::TransactionKernel; +use miden_protocol::utils::serde::Serializable; use miden_protocol_build_utils::{ ErrorModule, PROJECT_MANIFEST, @@ -85,6 +86,7 @@ fn main() -> Result<()> { source_dir.join(ASM_COMPONENTS_DIR).join(PROJECT_MANIFEST), &mut registry, &target_dir.join(ASM_COMPONENTS_DIR), + |metadata| Ok(AccountComponentMetadata::from_toml(metadata).into_diagnostic()?.to_bytes()), )?; // generate agglayer specific constants diff --git a/crates/miden-agglayer/src/bridge.rs b/crates/miden-agglayer/src/bridge.rs index e8bcf56348..e5d8ec32fd 100644 --- a/crates/miden-agglayer/src/bridge.rs +++ b/crates/miden-agglayer/src/bridge.rs @@ -864,8 +864,8 @@ pub enum AgglayerBridgeError { /// Creates an AggLayer Bridge component with the specified storage slots. fn bridge_component(storage_slots: Vec) -> AccountComponent { let package = agglayer_bridge_component_package(); - let metadata = AccountComponentMetadata::new("agglayer::bridge") - .with_description("Bridge component for AggLayer"); + let metadata = AccountComponentMetadata::try_from(&package) + .expect("shipped bridge package should declare account component metadata"); AccountComponent::new(package, storage_slots, metadata) .expect("bridge component should satisfy the requirements of a valid account component") diff --git a/crates/miden-protocol-build-utils/Cargo.toml b/crates/miden-protocol-build-utils/Cargo.toml index 1a3494b234..76f156f229 100644 --- a/crates/miden-protocol-build-utils/Cargo.toml +++ b/crates/miden-protocol-build-utils/Cargo.toml @@ -23,4 +23,5 @@ miden-mast-package = { features = ["std"], workspace = true } miden-package-registry = { features = ["std"], workspace = true } miden-project = { features = ["serde", "std"], workspace = true } regex = { workspace = true } +toml = { workspace = true } walkdir = { workspace = true } diff --git a/crates/miden-protocol-build-utils/src/lib.rs b/crates/miden-protocol-build-utils/src/lib.rs index 85adf791f5..3b416825db 100644 --- a/crates/miden-protocol-build-utils/src/lib.rs +++ b/crates/miden-protocol-build-utils/src/lib.rs @@ -14,7 +14,7 @@ use miden_assembly::debuginfo::{DefaultSourceManager, SourceManager, SourceManag use miden_assembly::diagnostics::{IntoDiagnostic, Result}; use miden_assembly::{Assembler, ProjectTargetSelector, Report}; use miden_core::events::EventId; -use miden_mast_package::Package; +use miden_mast_package::{Package, Section, SectionId}; use miden_package_registry::InMemoryPackageRegistry; use miden_project::Workspace; use regex::Regex; @@ -32,6 +32,10 @@ pub const PROJECT_MANIFEST: &str = "miden-project.toml"; /// information; consumers can strip it as needed. pub const BUILD_PROFILE: &str = "dev"; +/// Name of the custom manifest table declaring the metadata of an account component, i.e. +/// `[package.metadata.account-component]`. +const COMPONENT_METADATA_TABLE: &str = "account-component"; + // PACKAGE ASSEMBLY HELPERS // ================================================================================================ @@ -57,10 +61,16 @@ pub fn assemble_project( /// library target into a library package, writes each package to `target_dir` as a `.masp` file, /// and returns the assembled packages. Members without a library target are skipped. Dependencies /// are resolved against `registry`. +/// +/// If a member declares a `[package.metadata.account-component]` manifest table, the table is +/// passed to `encode_account_component_metadata` as a TOML document and the returned bytes are +/// embedded in the package as its [`SectionId::ACCOUNT_COMPONENT_METADATA`] section. Members +/// without the table are assembled as-is. pub fn assemble_workspace( manifest_path: impl AsRef, registry: &mut InMemoryPackageRegistry, target_dir: &Path, + encode_account_component_metadata: fn(&str) -> Result>, ) -> Result>> { let source_manager: Arc = Arc::new(DefaultSourceManager::default()); let manifest = source_manager.load_file(manifest_path.as_ref()).into_diagnostic()?; @@ -76,10 +86,19 @@ pub fn assemble_workspace( continue; } - let package = assembler + let mut package = assembler .clone() .for_project(member.clone(), registry)? .assemble(ProjectTargetSelector::Library, BUILD_PROFILE)?; + + if let Some(metadata) = component_metadata_toml(member)? { + let section = Section::new( + SectionId::ACCOUNT_COMPONENT_METADATA, + encode_account_component_metadata(&metadata)?, + ); + Arc::make_mut(&mut package).sections.push(section); + } + package.write_masp_file(target_dir).into_diagnostic()?; packages.push(package); } @@ -87,6 +106,26 @@ pub fn assemble_workspace( Ok(packages) } +/// Returns the `[package.metadata.account-component]` table of `package`'s manifest as a standalone +/// TOML document, or `None` if the manifest does not declare one. +fn component_metadata_toml(package: &miden_project::Package) -> Result> { + let table = package.metadata().iter().find_map(|(name, table)| { + let name: &str = name; + (name == COMPONENT_METADATA_TABLE).then_some(table) + }); + let Some(table) = table else { + return Ok(None); + }; + + let mut document = toml::Table::new(); + for (key, value) in table.iter() { + let key: &str = key; + document.insert(key.to_string(), (**value).clone()); + } + + toml::to_string(&document).into_diagnostic().map(Some) +} + // ERROR CONSTANTS EXTRACTION // ================================================================================================ diff --git a/crates/miden-protocol/Cargo.toml b/crates/miden-protocol/Cargo.toml index ab8cdd9358..dcc2758c17 100644 --- a/crates/miden-protocol/Cargo.toml +++ b/crates/miden-protocol/Cargo.toml @@ -55,7 +55,7 @@ rand_xoshiro = { default-features = false, optional = true, version = "0.8" } semver = { features = ["serde"], version = "1.0" } serde = { features = ["derive"], optional = true, workspace = true } thiserror = { workspace = true } -toml = { optional = true, version = "1.0" } +toml = { optional = true, workspace = true } # for SecretKey generation rand_chacha = { optional = true, workspace = true } diff --git a/crates/miden-standards/Cargo.toml b/crates/miden-standards/Cargo.toml index 708017be39..f2724a2460 100644 --- a/crates/miden-standards/Cargo.toml +++ b/crates/miden-standards/Cargo.toml @@ -34,7 +34,7 @@ thiserror = { workspace = true } miden-assembly = { features = ["std"], workspace = true } miden-core-lib = { workspace = true } miden-package-registry = { features = ["resolver", "std"], workspace = true } -miden-protocol = { workspace = true } +miden-protocol = { features = ["std"], workspace = true } miden-protocol-build-utils = { workspace = true } [dev-dependencies] diff --git a/crates/miden-standards/asm/components/access/authority/miden-project.toml b/crates/miden-standards/asm/components/access/authority/miden-project.toml index ddad0eb2ca..42c595a2cb 100644 --- a/crates/miden-standards/asm/components/access/authority/miden-project.toml +++ b/crates/miden-standards/asm/components/access/authority/miden-project.toml @@ -11,3 +11,32 @@ path = "authority.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Account-wide authority gating state-mutating operations behind auth-only, owner-based, or RBAC checks" +name = "miden::standards::access::authority" +version = "1.0.0" + +[[package.metadata.account-component.storage.slots]] +description = "Per-procedure role assignment (procedure root -> role symbol)" +name = "miden::standards::access::authority::procedure_roles" +type = { key = "word", value = "miden::standards::access::role_symbol" } + +[[package.metadata.account-component.storage.slots]] +description = "Authority configuration" +name = "miden::standards::access::authority::authority_config" + +# Word layout: [authority, is_frozen, 0, 0] +[[package.metadata.account-component.storage.slots.type]] +name = "authority" +type = "u8" + +[[package.metadata.account-component.storage.slots.type]] +name = "is_frozen" +type = "u8" + +[[package.metadata.account-component.storage.slots.type]] +type = "void" + +[[package.metadata.account-component.storage.slots.type]] +type = "void" diff --git a/crates/miden-standards/asm/components/access/ownable2step/miden-project.toml b/crates/miden-standards/asm/components/access/ownable2step/miden-project.toml index e8f72f31bd..4dd025c6d2 100644 --- a/crates/miden-standards/asm/components/access/ownable2step/miden-project.toml +++ b/crates/miden-standards/asm/components/access/ownable2step/miden-project.toml @@ -11,3 +11,25 @@ path = "ownable2step.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Two-step ownership management" +name = "miden::standards::access::ownable2step" +version = "1.0.0" + +[[package.metadata.account-component.storage.slots]] +description = "Ownership data (owner and nominated owner)" +name = "miden::standards::access::ownable2step::owner_config" + +# Word layout: [owner_suffix, owner_prefix, nominated_suffix, nominated_prefix] +[[package.metadata.account-component.storage.slots.type]] +name = "owner_suffix" + +[[package.metadata.account-component.storage.slots.type]] +name = "owner_prefix" + +[[package.metadata.account-component.storage.slots.type]] +name = "nominated_suffix" + +[[package.metadata.account-component.storage.slots.type]] +name = "nominated_prefix" diff --git a/crates/miden-standards/asm/components/access/pausable/miden-project.toml b/crates/miden-standards/asm/components/access/pausable/miden-project.toml index 591d36899f..42ffc7bbd8 100644 --- a/crates/miden-standards/asm/components/access/pausable/miden-project.toml +++ b/crates/miden-standards/asm/components/access/pausable/miden-project.toml @@ -11,3 +11,14 @@ path = "pausable.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Pause switch for blocking the account's state-mutating operations" +name = "miden::standards::access::pausable" +version = "1.0.0" + +[[package.metadata.account-component.storage.slots]] +default-value = "false" +description = "Whether the account is paused" +name = "miden::standards::access::pausable::is_paused" +type = "bool" diff --git a/crates/miden-standards/asm/components/access/pausable_manager/miden-project.toml b/crates/miden-standards/asm/components/access/pausable_manager/miden-project.toml index e580145a3b..f38be654d6 100644 --- a/crates/miden-standards/asm/components/access/pausable_manager/miden-project.toml +++ b/crates/miden-standards/asm/components/access/pausable_manager/miden-project.toml @@ -11,3 +11,8 @@ path = "pausable_manager.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Authority-gated pause / unpause admin procedures; requires the Pausable and Authority companion components" +name = "miden::standards::access::pausable::manager" +version = "1.0.0" diff --git a/crates/miden-standards/asm/components/access/rbac/miden-project.toml b/crates/miden-standards/asm/components/access/rbac/miden-project.toml index 5cd01d77dd..48982e30ca 100644 --- a/crates/miden-standards/asm/components/access/rbac/miden-project.toml +++ b/crates/miden-standards/asm/components/access/rbac/miden-project.toml @@ -11,3 +11,18 @@ path = "rbac.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Role-based access control" +name = "miden::standards::access::rbac" +version = "1.0.0" + +[[package.metadata.account-component.storage.slots]] +description = "Per-role RBAC configuration (member count and delegated admin role)" +name = "miden::standards::access::rbac::role_config" +type = { key = "miden::standards::access::role_symbol", value = "word" } + +[[package.metadata.account-component.storage.slots]] +description = "Role membership flag indexed by role symbol and account ID" +name = "miden::standards::access::rbac::role_membership" +type = { key = "word", value = "bool" } diff --git a/crates/miden-standards/asm/components/auth/guarded_multisig/miden-project.toml b/crates/miden-standards/asm/components/auth/guarded_multisig/miden-project.toml index 2bf46ff67e..e12f7491b0 100644 --- a/crates/miden-standards/asm/components/auth/guarded_multisig/miden-project.toml +++ b/crates/miden-standards/asm/components/auth/guarded_multisig/miden-project.toml @@ -11,3 +11,57 @@ path = "guarded_multisig.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Multisig authentication with hybrid signature schemes, guarded by a state guardian" +name = "miden::standards::auth::guarded_multisig" +version = "1.0.0" + +[[package.metadata.account-component.storage.slots]] +description = "Guardian public key" +name = "miden::standards::auth::guardian::pub_key" +type = { key = "u32", value = "miden::standards::auth::pub_key" } + +[[package.metadata.account-component.storage.slots]] +description = "Executed transactions" +name = "miden::standards::auth::multisig::executed_transactions" +type = { key = "word", value = "bool" } + +[[package.metadata.account-component.storage.slots]] +description = "Approver public keys" +name = "miden::standards::auth::multisig::approver_public_keys" +type = { key = "u32", value = "miden::standards::auth::pub_key" } + +[[package.metadata.account-component.storage.slots]] +description = "Procedure thresholds" +name = "miden::standards::auth::multisig::procedure_thresholds" +type = { key = "word", value = "u32" } + +[[package.metadata.account-component.storage.slots]] +description = "Guardian scheme ID" +name = "miden::standards::auth::guardian::scheme" +type = { key = "u32", value = "miden::standards::auth::scheme" } + +[[package.metadata.account-component.storage.slots]] +description = "Approver scheme IDs" +name = "miden::standards::auth::multisig::approver_schemes" +type = { key = "u32", value = "miden::standards::auth::scheme" } + +[[package.metadata.account-component.storage.slots]] +description = "Threshold configuration" +name = "miden::standards::auth::multisig::threshold_config" + +# Word layout: [threshold, num_approvers, 0, 0] +[[package.metadata.account-component.storage.slots.type]] +name = "threshold" +type = "u32" + +[[package.metadata.account-component.storage.slots.type]] +name = "num_approvers" +type = "u32" + +[[package.metadata.account-component.storage.slots.type]] +type = "void" + +[[package.metadata.account-component.storage.slots.type]] +type = "void" diff --git a/crates/miden-standards/asm/components/auth/multisig/miden-project.toml b/crates/miden-standards/asm/components/auth/multisig/miden-project.toml index 3613d7f94d..f1c3d752c2 100644 --- a/crates/miden-standards/asm/components/auth/multisig/miden-project.toml +++ b/crates/miden-standards/asm/components/auth/multisig/miden-project.toml @@ -11,3 +11,47 @@ path = "multisig.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Multisig authentication using hybrid signature schemes" +name = "miden::standards::auth::multisig" +version = "1.0.0" + +[[package.metadata.account-component.storage.slots]] +description = "Executed transactions" +name = "miden::standards::auth::multisig::executed_transactions" +type = { key = "word", value = "bool" } + +[[package.metadata.account-component.storage.slots]] +description = "Approver public keys" +name = "miden::standards::auth::multisig::approver_public_keys" +type = { key = "u32", value = "miden::standards::auth::pub_key" } + +[[package.metadata.account-component.storage.slots]] +description = "Procedure thresholds" +name = "miden::standards::auth::multisig::procedure_thresholds" +type = { key = "word", value = "u32" } + +[[package.metadata.account-component.storage.slots]] +description = "Approver scheme IDs" +name = "miden::standards::auth::multisig::approver_schemes" +type = { key = "u32", value = "miden::standards::auth::scheme" } + +[[package.metadata.account-component.storage.slots]] +description = "Threshold configuration" +name = "miden::standards::auth::multisig::threshold_config" + +# Word layout: [threshold, num_approvers, 0, 0] +[[package.metadata.account-component.storage.slots.type]] +name = "threshold" +type = "u32" + +[[package.metadata.account-component.storage.slots.type]] +name = "num_approvers" +type = "u32" + +[[package.metadata.account-component.storage.slots.type]] +type = "void" + +[[package.metadata.account-component.storage.slots.type]] +type = "void" diff --git a/crates/miden-standards/asm/components/auth/multisig_smart/miden-project.toml b/crates/miden-standards/asm/components/auth/multisig_smart/miden-project.toml index 613aacb949..733bf1cd2e 100644 --- a/crates/miden-standards/asm/components/auth/multisig_smart/miden-project.toml +++ b/crates/miden-standards/asm/components/auth/multisig_smart/miden-project.toml @@ -11,3 +11,47 @@ path = "multisig_smart.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Multisig authentication with per-procedure smart policies" +name = "miden::standards::auth::multisig_smart" +version = "1.0.0" + +[[package.metadata.account-component.storage.slots]] +description = "Procedure policies" +name = "miden::standards::auth::multisig_smart::procedure_policies" +type = { key = "word", value = "word" } + +[[package.metadata.account-component.storage.slots]] +description = "Executed transactions" +name = "miden::standards::auth::multisig::executed_transactions" +type = { key = "word", value = "bool" } + +[[package.metadata.account-component.storage.slots]] +description = "Approver public keys" +name = "miden::standards::auth::multisig::approver_public_keys" +type = { key = "u32", value = "miden::standards::auth::pub_key" } + +[[package.metadata.account-component.storage.slots]] +description = "Approver scheme IDs" +name = "miden::standards::auth::multisig::approver_schemes" +type = { key = "u32", value = "miden::standards::auth::scheme" } + +[[package.metadata.account-component.storage.slots]] +description = "Threshold configuration" +name = "miden::standards::auth::multisig::threshold_config" + +# Word layout: [threshold, num_approvers, 0, 0] +[[package.metadata.account-component.storage.slots.type]] +name = "threshold" +type = "u32" + +[[package.metadata.account-component.storage.slots.type]] +name = "num_approvers" +type = "u32" + +[[package.metadata.account-component.storage.slots.type]] +type = "void" + +[[package.metadata.account-component.storage.slots.type]] +type = "void" diff --git a/crates/miden-standards/asm/components/auth/network_account/miden-project.toml b/crates/miden-standards/asm/components/auth/network_account/miden-project.toml index d585e98c48..a671b7af2d 100644 --- a/crates/miden-standards/asm/components/auth/network_account/miden-project.toml +++ b/crates/miden-standards/asm/components/auth/network_account/miden-project.toml @@ -11,3 +11,38 @@ path = "network_account.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Authentication for network-owned accounts restricting input notes and transaction scripts to allowlisted script roots, and collecting and paying transaction fees" +name = "miden::standards::auth::network_account" +version = "1.0.0" + +[[package.metadata.account-component.storage.slots]] +description = "Allowed transaction script roots" +name = "miden::standards::auth::network_account::allowed_tx_scripts" +type = { key = "word", value = "bool" } + +[[package.metadata.account-component.storage.slots]] +description = "Active fee policy procedure root" +name = "miden::standards::auth::network_account::active_fee_policy_proc_root" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Whether sponsorships are capped at the fees collected in the same transaction" +name = "miden::standards::auth::network_account::sponsor_at_most_collected_fees" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Allowed fee policy procedure roots" +name = "miden::standards::auth::network_account::allowed_fee_policy_proc_roots" +type = { key = "word", value = "bool" } + +[[package.metadata.account-component.storage.slots]] +description = "ID of the asset fees are charged in" +name = "miden::standards::auth::network_account::fee_asset_id" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Allowed input note script roots" +name = "miden::standards::auth::network_account::allowed_note_scripts" +type = { key = "word", value = "bool" } diff --git a/crates/miden-standards/asm/components/auth/no_auth/miden-project.toml b/crates/miden-standards/asm/components/auth/no_auth/miden-project.toml index 87fe1050b6..a2849ad211 100644 --- a/crates/miden-standards/asm/components/auth/no_auth/miden-project.toml +++ b/crates/miden-standards/asm/components/auth/no_auth/miden-project.toml @@ -11,3 +11,8 @@ path = "no_auth.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Authentication that performs no cryptographic checks" +name = "miden::standards::auth::no_auth" +version = "1.0.0" diff --git a/crates/miden-standards/asm/components/auth/singlesig/miden-project.toml b/crates/miden-standards/asm/components/auth/singlesig/miden-project.toml index 680702d5fe..9671067b21 100644 --- a/crates/miden-standards/asm/components/auth/singlesig/miden-project.toml +++ b/crates/miden-standards/asm/components/auth/singlesig/miden-project.toml @@ -11,3 +11,18 @@ path = "singlesig.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Single-signature authentication using the ECDSA K256 Keccak or Falcon512 Poseidon2 scheme" +name = "miden::standards::auth::singlesig" +version = "1.0.0" + +[[package.metadata.account-component.storage.slots]] +description = "Scheme ID" +name = "miden::standards::auth::singlesig::scheme" +type = "miden::standards::auth::scheme" + +[[package.metadata.account-component.storage.slots]] +description = "Public key commitment" +name = "miden::standards::auth::singlesig::pub_key" +type = "miden::standards::auth::pub_key" diff --git a/crates/miden-standards/asm/components/faucets/fungible_faucet/miden-project.toml b/crates/miden-standards/asm/components/faucets/fungible_faucet/miden-project.toml index 8bc6dd8664..340e5be5b8 100644 --- a/crates/miden-standards/asm/components/faucets/fungible_faucet/miden-project.toml +++ b/crates/miden-standards/asm/components/faucets/fungible_faucet/miden-project.toml @@ -11,3 +11,164 @@ path = "fungible_faucet.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Fungible faucet bundling minting, burning, and token metadata" +name = "miden::standards::faucets::fungible" +version = "1.0.0" + +[[package.metadata.account-component.storage.slots]] +description = "Description chunk 4" +name = "miden::standards::faucets::token_description_4" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "External link chunk 2" +name = "miden::standards::faucets::external_link_2" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "External link chunk 5" +name = "miden::standards::faucets::external_link_5" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Description chunk 2" +name = "miden::standards::faucets::token_description_2" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Logo URI chunk 3" +name = "miden::standards::faucets::logo_uri_3" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Description chunk 0" +name = "miden::standards::faucets::token_description_0" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Logo URI chunk 4" +name = "miden::standards::faucets::logo_uri_4" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Name chunk 1" +name = "miden::standards::faucets::token_name_1" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "External link chunk 3" +name = "miden::standards::faucets::external_link_3" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Logo URI chunk 5" +name = "miden::standards::faucets::logo_uri_5" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Mutability config" +name = "miden::standards::faucets::mutability_config" + +# Word layout: [is_description_mutable, is_logo_uri_mutable, is_external_link_mutable, is_max_supply_mutable] +[[package.metadata.account-component.storage.slots.type]] +name = "is_description_mutable" +type = "bool" + +[[package.metadata.account-component.storage.slots.type]] +name = "is_logo_uri_mutable" +type = "bool" + +[[package.metadata.account-component.storage.slots.type]] +name = "is_external_link_mutable" +type = "bool" + +[[package.metadata.account-component.storage.slots.type]] +name = "is_max_supply_mutable" +type = "bool" + +[[package.metadata.account-component.storage.slots]] +description = "External link chunk 4" +name = "miden::standards::faucets::external_link_4" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Description chunk 3" +name = "miden::standards::faucets::token_description_3" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Logo URI chunk 6" +name = "miden::standards::faucets::logo_uri_6" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Logo URI chunk 0" +name = "miden::standards::faucets::logo_uri_0" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "External link chunk 1" +name = "miden::standards::faucets::external_link_1" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Logo URI chunk 1" +name = "miden::standards::faucets::logo_uri_1" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Description chunk 5" +name = "miden::standards::faucets::token_description_5" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Token config" +name = "miden::standards::faucets::fungible::token_config" + +# Word layout: [token_supply, max_supply, decimals, symbol] +[[package.metadata.account-component.storage.slots.type]] +default-value = "0x0" +name = "token_supply" + +[[package.metadata.account-component.storage.slots.type]] +name = "max_supply" + +[[package.metadata.account-component.storage.slots.type]] +name = "decimals" +type = "u8" + +[[package.metadata.account-component.storage.slots.type]] +name = "symbol" +type = "miden::standards::faucets::fungible::token_symbol" + +[[package.metadata.account-component.storage.slots]] +description = "Description chunk 1" +name = "miden::standards::faucets::token_description_1" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Description chunk 6" +name = "miden::standards::faucets::token_description_6" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Logo URI chunk 2" +name = "miden::standards::faucets::logo_uri_2" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "External link chunk 0" +name = "miden::standards::faucets::external_link_0" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "External link chunk 6" +name = "miden::standards::faucets::external_link_6" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Name chunk 0" +name = "miden::standards::faucets::token_name_0" +type = "word" diff --git a/crates/miden-standards/asm/components/faucets/non_fungible_faucet/miden-project.toml b/crates/miden-standards/asm/components/faucets/non_fungible_faucet/miden-project.toml index 13c536ac39..e455a11295 100644 --- a/crates/miden-standards/asm/components/faucets/non_fungible_faucet/miden-project.toml +++ b/crates/miden-standards/asm/components/faucets/non_fungible_faucet/miden-project.toml @@ -11,3 +11,166 @@ path = "non_fungible_faucet.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Non-fungible faucet bundling minting, burning, asset status, and token metadata" +name = "miden::standards::faucets::non_fungible" +version = "1.0.0" + +[[package.metadata.account-component.storage.slots]] +description = "Description chunk 4" +name = "miden::standards::faucets::token_description_4" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "External link chunk 2" +name = "miden::standards::faucets::external_link_2" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "External link chunk 5" +name = "miden::standards::faucets::external_link_5" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Description chunk 2" +name = "miden::standards::faucets::token_description_2" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Logo URI chunk 3" +name = "miden::standards::faucets::logo_uri_3" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Description chunk 0" +name = "miden::standards::faucets::token_description_0" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Logo URI chunk 4" +name = "miden::standards::faucets::logo_uri_4" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Name chunk 1" +name = "miden::standards::faucets::token_name_1" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "External link chunk 3" +name = "miden::standards::faucets::external_link_3" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Logo URI chunk 5" +name = "miden::standards::faucets::logo_uri_5" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Mutability config" +name = "miden::standards::faucets::mutability_config" + +# Word layout: [is_description_mutable, is_logo_uri_mutable, is_external_link_mutable, is_max_supply_mutable] +[[package.metadata.account-component.storage.slots.type]] +name = "is_description_mutable" +type = "bool" + +[[package.metadata.account-component.storage.slots.type]] +name = "is_logo_uri_mutable" +type = "bool" + +[[package.metadata.account-component.storage.slots.type]] +name = "is_external_link_mutable" +type = "bool" + +[[package.metadata.account-component.storage.slots.type]] +name = "is_max_supply_mutable" +type = "bool" + +[[package.metadata.account-component.storage.slots]] +description = "External link chunk 4" +name = "miden::standards::faucets::external_link_4" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Token symbol" +name = "miden::standards::faucets::non_fungible::symbol" + +# Word layout: [symbol, 0, 0, 0] +[[package.metadata.account-component.storage.slots.type]] +name = "symbol" + +[[package.metadata.account-component.storage.slots.type]] +type = "void" + +[[package.metadata.account-component.storage.slots.type]] +type = "void" + +[[package.metadata.account-component.storage.slots.type]] +type = "void" + +[[package.metadata.account-component.storage.slots]] +description = "Issuance status of each asset (not issued, issued, or burned), keyed by token ID" +name = "miden::standards::faucets::non_fungible::asset_status" +type = { key = "word", value = "felt" } + +[[package.metadata.account-component.storage.slots]] +description = "Description chunk 3" +name = "miden::standards::faucets::token_description_3" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Logo URI chunk 6" +name = "miden::standards::faucets::logo_uri_6" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Logo URI chunk 0" +name = "miden::standards::faucets::logo_uri_0" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "External link chunk 1" +name = "miden::standards::faucets::external_link_1" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Logo URI chunk 1" +name = "miden::standards::faucets::logo_uri_1" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Description chunk 5" +name = "miden::standards::faucets::token_description_5" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Description chunk 1" +name = "miden::standards::faucets::token_description_1" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Description chunk 6" +name = "miden::standards::faucets::token_description_6" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Logo URI chunk 2" +name = "miden::standards::faucets::logo_uri_2" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "External link chunk 0" +name = "miden::standards::faucets::external_link_0" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "External link chunk 6" +name = "miden::standards::faucets::external_link_6" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Name chunk 0" +name = "miden::standards::faucets::token_name_0" +type = "word" diff --git a/crates/miden-standards/asm/components/faucets/policies/burn/allow_all/miden-project.toml b/crates/miden-standards/asm/components/faucets/policies/burn/allow_all/miden-project.toml index 804d8df177..82d207cc71 100644 --- a/crates/miden-standards/asm/components/faucets/policies/burn/allow_all/miden-project.toml +++ b/crates/miden-standards/asm/components/faucets/policies/burn/allow_all/miden-project.toml @@ -11,3 +11,8 @@ path = "allow_all.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "`allow_all` burn policy for fungible faucets" +name = "miden::standards::faucets::policies::burn::allow_all" +version = "1.0.0" diff --git a/crates/miden-standards/asm/components/faucets/policies/burn/min_burn_amount/miden-project.toml b/crates/miden-standards/asm/components/faucets/policies/burn/min_burn_amount/miden-project.toml index 80106dd5aa..99bff7d6b5 100644 --- a/crates/miden-standards/asm/components/faucets/policies/burn/min_burn_amount/miden-project.toml +++ b/crates/miden-standards/asm/components/faucets/policies/burn/min_burn_amount/miden-project.toml @@ -11,3 +11,13 @@ path = "min_burn_amount.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "`min_burn_amount` burn policy for fungible faucets" +name = "miden::standards::faucets::policies::burn::min_burn_amount" +version = "1.0.0" + +[[package.metadata.account-component.storage.slots]] +description = "Minimum burn amount" +name = "miden::standards::faucets::policies::burn::min_burn_amount::min_burn_amount" +type = "word" diff --git a/crates/miden-standards/asm/components/faucets/policies/burn/owner_controlled/owner_only/miden-project.toml b/crates/miden-standards/asm/components/faucets/policies/burn/owner_controlled/owner_only/miden-project.toml index 9aff057242..91a7663ba2 100644 --- a/crates/miden-standards/asm/components/faucets/policies/burn/owner_controlled/owner_only/miden-project.toml +++ b/crates/miden-standards/asm/components/faucets/policies/burn/owner_controlled/owner_only/miden-project.toml @@ -11,3 +11,8 @@ path = "owner_only.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "`owner_only` burn policy (owner-controlled family) for fungible faucets" +name = "miden::standards::faucets::policies::burn::owner_controlled::owner_only" +version = "1.0.0" diff --git a/crates/miden-standards/asm/components/faucets/policies/mint/allow_all/miden-project.toml b/crates/miden-standards/asm/components/faucets/policies/mint/allow_all/miden-project.toml index c19bf42c0c..bcd4e3ee08 100644 --- a/crates/miden-standards/asm/components/faucets/policies/mint/allow_all/miden-project.toml +++ b/crates/miden-standards/asm/components/faucets/policies/mint/allow_all/miden-project.toml @@ -11,3 +11,8 @@ path = "allow_all.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "`allow_all` mint policy for fungible faucets" +name = "miden::standards::faucets::policies::mint::allow_all" +version = "1.0.0" diff --git a/crates/miden-standards/asm/components/faucets/policies/mint/owner_controlled/owner_only/miden-project.toml b/crates/miden-standards/asm/components/faucets/policies/mint/owner_controlled/owner_only/miden-project.toml index 5e59799bbe..3c0f4b830e 100644 --- a/crates/miden-standards/asm/components/faucets/policies/mint/owner_controlled/owner_only/miden-project.toml +++ b/crates/miden-standards/asm/components/faucets/policies/mint/owner_controlled/owner_only/miden-project.toml @@ -11,3 +11,8 @@ path = "owner_only.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "`owner_only` mint policy (owner-controlled family) for fungible faucets" +name = "miden::standards::faucets::policies::mint::owner_controlled::owner_only" +version = "1.0.0" diff --git a/crates/miden-standards/asm/components/faucets/policies/policy_manager/miden-project.toml b/crates/miden-standards/asm/components/faucets/policies/policy_manager/miden-project.toml index 2b882a4c33..5d1fefe52b 100644 --- a/crates/miden-standards/asm/components/faucets/policies/policy_manager/miden-project.toml +++ b/crates/miden-standards/asm/components/faucets/policies/policy_manager/miden-project.toml @@ -11,3 +11,60 @@ path = "policy_manager.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Token policy manager for fungible faucets" +name = "miden::standards::faucets::policies::policy_manager" +version = "1.0.0" + +[[package.metadata.account-component.storage.slots]] +description = "Active receive policy procedure root" +name = "miden::standards::faucets::policies::policy_manager::active_receive_policy_proc_root" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Active send policy procedure root" +name = "miden::standards::faucets::policies::policy_manager::active_send_policy_proc_root" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Active mint policy procedure root" +name = "miden::standards::faucets::policies::policy_manager::active_mint_policy_proc_root" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Active burn policy procedure root" +name = "miden::standards::faucets::policies::policy_manager::active_burn_policy_proc_root" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Allowed send policy procedure roots" +name = "miden::standards::faucets::policies::policy_manager::allowed_send_policy_proc_roots" +type = { key = "word", value = "bool" } + +[[package.metadata.account-component.storage.slots]] +description = "Allowed burn policy procedure roots" +name = "miden::standards::faucets::policies::policy_manager::allowed_burn_policy_proc_roots" +type = { key = "word", value = "bool" } + +[[package.metadata.account-component.storage.slots]] +description = "Allowed receive policy procedure roots" +name = "miden::standards::faucets::policies::policy_manager::allowed_receive_policy_proc_roots" +type = { key = "word", value = "bool" } + +[[package.metadata.account-component.storage.slots]] +description = "Allowed mint policy procedure roots" +name = "miden::standards::faucets::policies::policy_manager::allowed_mint_policy_proc_roots" +type = { key = "word", value = "bool" } + +# Reserved asset-callback slots. They are installed only when at least one send or receive policy +# is configured. +[[package.metadata.account-component.storage.slots]] +description = "Root of the procedure the kernel invokes to enforce the active receive policy" +name = "miden::protocol::faucet::callback::on_before_asset_added_to_account" +type = "word" + +[[package.metadata.account-component.storage.slots]] +description = "Root of the procedure the kernel invokes to enforce the active send policy" +name = "miden::protocol::faucet::callback::on_before_asset_added_to_note" +type = "word" diff --git a/crates/miden-standards/asm/components/faucets/policies/transfer/allow_all/miden-project.toml b/crates/miden-standards/asm/components/faucets/policies/transfer/allow_all/miden-project.toml index 58bf9a6add..7e3f41a608 100644 --- a/crates/miden-standards/asm/components/faucets/policies/transfer/allow_all/miden-project.toml +++ b/crates/miden-standards/asm/components/faucets/policies/transfer/allow_all/miden-project.toml @@ -11,3 +11,8 @@ path = "allow_all.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "`allow_all` transfer policy for callback-enabled faucets" +name = "miden::standards::faucets::policies::transfer::allow_all" +version = "1.0.0" diff --git a/crates/miden-standards/asm/components/faucets/policies/transfer/allowlist/manager/miden-project.toml b/crates/miden-standards/asm/components/faucets/policies/transfer/allowlist/manager/miden-project.toml index dc1d9aafc5..0027ea55c8 100644 --- a/crates/miden-standards/asm/components/faucets/policies/transfer/allowlist/manager/miden-project.toml +++ b/crates/miden-standards/asm/components/faucets/policies/transfer/allowlist/manager/miden-project.toml @@ -11,3 +11,8 @@ path = "manager.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Authority-gated admin wrapping `allowlist::allow_account` / `disallow_account`" +name = "miden::standards::faucets::policies::transfer::allowlist::manager" +version = "1.0.0" diff --git a/crates/miden-standards/asm/components/faucets/policies/transfer/basic_allowlist/miden-project.toml b/crates/miden-standards/asm/components/faucets/policies/transfer/basic_allowlist/miden-project.toml index f167d22fac..b87379ac6d 100644 --- a/crates/miden-standards/asm/components/faucets/policies/transfer/basic_allowlist/miden-project.toml +++ b/crates/miden-standards/asm/components/faucets/policies/transfer/basic_allowlist/miden-project.toml @@ -11,3 +11,13 @@ path = "basic_allowlist.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Transfer policy allowing transfers only to allowlisted accounts" +name = "miden::standards::faucets::policies::transfer::basic_allowlist" +version = "1.0.0" + +[[package.metadata.account-component.storage.slots]] +description = "Whether an account is allowed to receive transfers" +name = "miden::standards::faucets::policies::transfer::allowlist::allowed_accounts" +type = { key = "word", value = "bool" } diff --git a/crates/miden-standards/asm/components/faucets/policies/transfer/basic_blocklist/miden-project.toml b/crates/miden-standards/asm/components/faucets/policies/transfer/basic_blocklist/miden-project.toml index 6a3922705b..82c03b14dc 100644 --- a/crates/miden-standards/asm/components/faucets/policies/transfer/basic_blocklist/miden-project.toml +++ b/crates/miden-standards/asm/components/faucets/policies/transfer/basic_blocklist/miden-project.toml @@ -11,3 +11,13 @@ path = "basic_blocklist.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Transfer policy rejecting transfers to blocklisted accounts" +name = "miden::standards::faucets::policies::transfer::basic_blocklist" +version = "1.0.0" + +[[package.metadata.account-component.storage.slots]] +description = "Whether an account is blocked from receiving transfers" +name = "miden::standards::faucets::policies::transfer::blocklist::blocked_accounts" +type = { key = "word", value = "bool" } diff --git a/crates/miden-standards/asm/components/faucets/policies/transfer/blocklist/manager/miden-project.toml b/crates/miden-standards/asm/components/faucets/policies/transfer/blocklist/manager/miden-project.toml index 40dc0f78ae..d9d536bcf2 100644 --- a/crates/miden-standards/asm/components/faucets/policies/transfer/blocklist/manager/miden-project.toml +++ b/crates/miden-standards/asm/components/faucets/policies/transfer/blocklist/manager/miden-project.toml @@ -11,3 +11,8 @@ path = "manager.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Authority-gated admin wrapping `blocklist::block_account` / `unblock_account`" +name = "miden::standards::faucets::policies::transfer::blocklist::manager" +version = "1.0.0" diff --git a/crates/miden-standards/asm/components/fees/policies/basic_constant_fee/miden-project.toml b/crates/miden-standards/asm/components/fees/policies/basic_constant_fee/miden-project.toml index 46d15befb3..d5fd2b1d45 100644 --- a/crates/miden-standards/asm/components/fees/policies/basic_constant_fee/miden-project.toml +++ b/crates/miden-standards/asm/components/fees/policies/basic_constant_fee/miden-project.toml @@ -11,3 +11,13 @@ path = "basic_constant_fee.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "`basic_constant_fee` fee policy charging a constant per-note-script fee" +name = "miden::standards::fees::policies::basic_constant_fee" +version = "1.0.0" + +[[package.metadata.account-component.storage.slots]] +description = "Fee charged per note script root" +name = "miden::standards::fees::policies::basic_constant_fee::fee_schedule" +type = { key = "word", value = "word" } diff --git a/crates/miden-standards/asm/components/fees/policies/constant_fee_manager/miden-project.toml b/crates/miden-standards/asm/components/fees/policies/constant_fee_manager/miden-project.toml index 71cb38ff27..69d4550e4d 100644 --- a/crates/miden-standards/asm/components/fees/policies/constant_fee_manager/miden-project.toml +++ b/crates/miden-standards/asm/components/fees/policies/constant_fee_manager/miden-project.toml @@ -11,3 +11,13 @@ path = "constant_fee_manager.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Authority-gated `set_note_fee` admin for updating a constant-fee schedule" +name = "miden::standards::fees::policies::constant_fee_manager" +version = "1.0.0" + +[[package.metadata.account-component.storage.slots]] +description = "ID of the fee schedule slot this manager updates" +name = "miden::standards::fees::policies::constant_fee_manager::fee_schedule_slot_id" +type = "word" diff --git a/crates/miden-standards/asm/components/inspection/code_inspection/miden-project.toml b/crates/miden-standards/asm/components/inspection/code_inspection/miden-project.toml index a351a47a6b..7c994a27b9 100644 --- a/crates/miden-standards/asm/components/inspection/code_inspection/miden-project.toml +++ b/crates/miden-standards/asm/components/inspection/code_inspection/miden-project.toml @@ -11,3 +11,8 @@ path = "code_inspection.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Read-only introspection over the account's own code" +name = "miden::standards::inspection::code_inspection" +version = "1.0.0" diff --git a/crates/miden-standards/asm/components/inspection/schema_commitment/miden-project.toml b/crates/miden-standards/asm/components/inspection/schema_commitment/miden-project.toml index 2efc33fb3b..7a9c17c96e 100644 --- a/crates/miden-standards/asm/components/inspection/schema_commitment/miden-project.toml +++ b/crates/miden-standards/asm/components/inspection/schema_commitment/miden-project.toml @@ -11,3 +11,13 @@ path = "schema_commitment.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Exposes a commitment to the account's storage schema" +name = "miden::standards::inspection::storage_schema" +version = "1.0.0" + +[[package.metadata.account-component.storage.slots]] +description = "Commitment to the storage schema of an account" +name = "miden::standards::inspection::storage_schema::commitment" +type = "word" diff --git a/crates/miden-standards/asm/components/note/note_creator/miden-project.toml b/crates/miden-standards/asm/components/note/note_creator/miden-project.toml index 5c429b242d..d63b30f964 100644 --- a/crates/miden-standards/asm/components/note/note_creator/miden-project.toml +++ b/crates/miden-standards/asm/components/note/note_creator/miden-project.toml @@ -11,3 +11,8 @@ path = "note_creator.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Exposes the `create_note` procedure for creating output notes" +name = "miden::standards::note::note_creator" +version = "1.0.0" diff --git a/crates/miden-standards/asm/components/upgrade/manager/miden-project.toml b/crates/miden-standards/asm/components/upgrade/manager/miden-project.toml index 3ead4b763c..783ed2dad3 100644 --- a/crates/miden-standards/asm/components/upgrade/manager/miden-project.toml +++ b/crates/miden-standards/asm/components/upgrade/manager/miden-project.toml @@ -11,3 +11,8 @@ path = "manager.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Exposes the `upgrade` procedure for recording commitments to new account code and storage" +name = "miden::standards::upgrade::manager" +version = "1.0.0" diff --git a/crates/miden-standards/asm/components/wallets/basic_wallet/miden-project.toml b/crates/miden-standards/asm/components/wallets/basic_wallet/miden-project.toml index de9f9a260c..1af2ec0a9f 100644 --- a/crates/miden-standards/asm/components/wallets/basic_wallet/miden-project.toml +++ b/crates/miden-standards/asm/components/wallets/basic_wallet/miden-project.toml @@ -11,3 +11,8 @@ path = "basic_wallet.masm" miden-core.workspace = true miden-protocol.workspace = true miden-standards.workspace = true + +[package.metadata.account-component] +description = "Basic wallet component for receiving and sending assets" +name = "miden::standards::wallets::basic_wallet" +version = "1.0.0" diff --git a/crates/miden-standards/build.rs b/crates/miden-standards/build.rs index 5686d4602c..bd29134509 100644 --- a/crates/miden-standards/build.rs +++ b/crates/miden-standards/build.rs @@ -6,7 +6,9 @@ use miden_assembly::diagnostics::{IntoDiagnostic, Result, WrapErr}; use miden_core_lib::CoreLibrary; use miden_package_registry::{InMemoryPackageRegistry, PackageCache}; use miden_protocol::ProtocolLib; +use miden_protocol::account::component::AccountComponentMetadata; use miden_protocol::transaction::TransactionKernel; +use miden_protocol::utils::serde::Serializable; use miden_protocol_build_utils::{ ErrorModule, PROJECT_MANIFEST, @@ -73,10 +75,13 @@ fn main() -> Result<()> { registry.cache_package(package).into_diagnostic()?; // compile account components (each member of the components workspace becomes its own package) + // and embed each component's manifest metadata into its package. Parsing the metadata here + // makes a malformed schema fail the build instead of the first instantiation. assemble_workspace( source_dir.join(ASM_COMPONENTS_DIR).join(PROJECT_MANIFEST), &mut registry, &target_dir.join(ASM_COMPONENTS_DIR), + |metadata| Ok(AccountComponentMetadata::from_toml(metadata).into_diagnostic()?.to_bytes()), )?; generate_error_constants(&source_dir, &build_dir)?; diff --git a/crates/miden-standards/src/account/access/authority.rs b/crates/miden-standards/src/account/access/authority.rs index 5dbb94e107..6dbe49c17c 100644 --- a/crates/miden-standards/src/account/access/authority.rs +++ b/crates/miden-standards/src/account/access/authority.rs @@ -1,14 +1,7 @@ use alloc::collections::BTreeMap; use alloc::vec; -use miden_protocol::account::component::{ - AccountComponentCode, - AccountComponentMetadata, - FeltSchema, - SchemaType, - StorageSchema, - StorageSlotSchema, -}; +use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{ AccountComponent, AccountProcedureRoot, @@ -25,7 +18,7 @@ use miden_protocol::utils::sync::LazyLock; use miden_protocol::{Felt, Word}; use thiserror::Error; -use crate::account::account_component_code; +use crate::account::{account_component_code, metadata_without_slots, package_metadata}; use crate::procedure_root; // CONSTANTS @@ -259,39 +252,16 @@ impl Authority { } /// Returns the [`AccountComponentMetadata`] for this configuration. + /// + /// The manifest declares the full storage schema, but only [`Authority::RbacControlled`] + /// installs the `procedure_roles` slot; the other authorities drop it from the schema. pub fn component_metadata(&self) -> AccountComponentMetadata { - let mut slots = vec![( - AUTHORITY_SLOT_NAME.clone(), - StorageSlotSchema::value( - "Authority configuration", - [ - FeltSchema::u8("authority"), - FeltSchema::u8("is_frozen"), - FeltSchema::new_void(), - FeltSchema::new_void(), - ], - ), - )]; - + let metadata = package_metadata(Self::code()); if matches!(self, Authority::RbacControlled { .. }) { - slots.push(( - AUTHORITY_PROCEDURE_ROLES_SLOT_NAME.clone(), - StorageSlotSchema::map( - "Per-procedure role assignment (procedure root -> role symbol)", - SchemaType::native_word(), - SchemaType::role_symbol(), - ), - )); + return metadata; } - let storage_schema = StorageSchema::new(slots).expect("storage schema should be valid"); - - AccountComponentMetadata::new(Self::NAME) - .with_description( - "Account-wide authority shared by procedures that gate state-mutating \ - operations behind auth-only, owner-based, or RBAC role-based checks", - ) - .with_storage_schema(storage_schema) + metadata_without_slots(metadata, &[Self::procedure_roles_slot()]) } // PRIVATE HELPERS diff --git a/crates/miden-standards/src/account/access/ownable2step.rs b/crates/miden-standards/src/account/access/ownable2step.rs index 2e828ec80f..3ad31dedde 100644 --- a/crates/miden-standards/src/account/access/ownable2step.rs +++ b/crates/miden-standards/src/account/access/ownable2step.rs @@ -1,10 +1,4 @@ -use miden_protocol::account::component::{ - AccountComponentCode, - AccountComponentMetadata, - FeltSchema, - StorageSchema, - StorageSlotSchema, -}; +use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{ AccountComponent, AccountComponentName, @@ -18,7 +12,7 @@ use miden_protocol::utils::sync::LazyLock; use miden_protocol::{Felt, Word}; use super::account_id_from_felt_pair; -use crate::account::account_component_code; +use crate::account::{account_component_code, package_metadata}; account_component_code!(OWNABLE2STEP_CODE, "miden-standards-access-ownable2step.masp"); @@ -114,22 +108,6 @@ impl Ownable2Step { &OWNER_CONFIG_SLOT_NAME } - /// Returns the storage slot schema for the ownership configuration slot. - pub fn slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - Self::slot_name().clone(), - StorageSlotSchema::value( - "Ownership data (owner and nominated owner)", - [ - FeltSchema::felt("owner_suffix"), - FeltSchema::felt("owner_prefix"), - FeltSchema::felt("nominated_suffix"), - FeltSchema::felt("nominated_prefix"), - ], - ), - ) - } - /// Returns the current owner, or `None` if ownership has been renounced. pub fn owner(&self) -> Option { self.owner @@ -160,12 +138,7 @@ impl Ownable2Step { /// Returns the [`AccountComponentMetadata`] for this component. pub fn component_metadata() -> AccountComponentMetadata { - let storage_schema = - StorageSchema::new([Self::slot_schema()]).expect("storage schema should be valid"); - - AccountComponentMetadata::new(Self::NAME) - .with_description("Two-step ownership management component") - .with_storage_schema(storage_schema) + package_metadata(Self::code()) } } diff --git a/crates/miden-standards/src/account/access/pausable/manager.rs b/crates/miden-standards/src/account/access/pausable/manager.rs index b3d73b3849..1babafcd0d 100644 --- a/crates/miden-standards/src/account/access/pausable/manager.rs +++ b/crates/miden-standards/src/account/access/pausable/manager.rs @@ -1,7 +1,7 @@ use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{AccountComponent, AccountProcedureRoot}; -use crate::account::account_component_code; +use crate::account::{account_component_code, package_metadata}; use crate::procedure_root; // PAUSABLE MANAGER COMPONENT @@ -71,15 +71,16 @@ impl PausableManager { pub fn unpause_root() -> AccountProcedureRoot { *PAUSABLE_MANAGER_UNPAUSE } + + /// Returns the [`AccountComponentMetadata`] for this component. + pub fn component_metadata() -> AccountComponentMetadata { + package_metadata(Self::code()) + } } impl From for AccountComponent { fn from(_: PausableManager) -> Self { - let metadata = AccountComponentMetadata::new(PausableManager::NAME).with_description( - "PausableManager: pause / unpause admin procedures gated by the account-wide \ - Authority component. Requires the Pausable companion component for storage and the \ - Authority component for auth dispatch.", - ); + let metadata = PausableManager::component_metadata(); AccountComponent::new(PausableManager::code().clone(), vec![], metadata).expect( "pausable manager component should satisfy the requirements of a valid account component", diff --git a/crates/miden-standards/src/account/access/pausable/mod.rs b/crates/miden-standards/src/account/access/pausable/mod.rs index fe5b70dc4e..e76eb7331a 100644 --- a/crates/miden-standards/src/account/access/pausable/mod.rs +++ b/crates/miden-standards/src/account/access/pausable/mod.rs @@ -1,9 +1,5 @@ -use miden_protocol::account::component::{ - AccountComponentCode, - AccountComponentMetadata, - StorageSchema, - StorageSlotSchema, -}; +use miden_protocol::Word; +use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{ AccountComponent, AccountProcedureRoot, @@ -11,9 +7,8 @@ use miden_protocol::account::{ StorageSlotName, }; use miden_protocol::utils::sync::LazyLock; -use miden_protocol::{Felt, Word}; -use crate::account::account_component_code; +use crate::account::{account_component_code, package_metadata}; use crate::procedure_root; mod manager; @@ -87,17 +82,6 @@ impl PausableStorage { &IS_PAUSED_SLOT_NAME } - /// Schema entry for the pause flag slot (documentation / tooling). - pub fn is_paused_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - Self::is_paused_slot().clone(), - StorageSlotSchema::value( - "Pause flag word; zero is unpaused, canonical paused encoding is [1,0,0,0]", - [Felt::ZERO; 4], - ), - ) - } - /// Returns the pause-flag [`Word`] for the captured state. pub fn to_word(&self) -> Word { if self.state { @@ -165,19 +149,16 @@ impl Pausable { pub fn is_paused_root() -> AccountProcedureRoot { *PAUSABLE_IS_PAUSED_ROOT } + + /// Returns the [`AccountComponentMetadata`] for this component. + pub fn component_metadata() -> AccountComponentMetadata { + package_metadata(Self::code()) + } } impl From for AccountComponent { fn from(pausable: Pausable) -> Self { - let storage_schema = StorageSchema::new([PausableStorage::is_paused_slot_schema()]) - .expect("storage schema should be valid"); - - let metadata = AccountComponentMetadata::new(Pausable::NAME) - .with_description( - "Pausable: installs the `is_paused` storage slot and exposes \ - `is_paused` view.", - ) - .with_storage_schema(storage_schema); + let metadata = Pausable::component_metadata(); AccountComponent::new(Pausable::code().clone(), vec![pausable.0.into_slot()], metadata) .expect( diff --git a/crates/miden-standards/src/account/access/rbac.rs b/crates/miden-standards/src/account/access/rbac.rs index edbd513a91..95b73da16a 100644 --- a/crates/miden-standards/src/account/access/rbac.rs +++ b/crates/miden-standards/src/account/access/rbac.rs @@ -2,13 +2,7 @@ use alloc::collections::{BTreeMap, BTreeSet}; use alloc::vec; use alloc::vec::Vec; -use miden_protocol::account::component::{ - AccountComponentCode, - AccountComponentMetadata, - SchemaType, - StorageSchema, - StorageSlotSchema, -}; +use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{ AccountComponent, AccountComponentName, @@ -22,7 +16,7 @@ use miden_protocol::account::{ use miden_protocol::utils::sync::LazyLock; use miden_protocol::{Felt, Word}; -use crate::account::account_component_code; +use crate::account::{account_component_code, package_metadata}; account_component_code!(RBAC_CODE, "miden-standards-access-rbac.masp"); @@ -351,41 +345,9 @@ impl RoleBasedAccessControl { &ROLE_MEMBERSHIP_SLOT_NAME } - /// Returns the schema entry for the per-role config map. - pub fn role_config_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - Self::role_config_slot().clone(), - StorageSlotSchema::map( - "Per-role RBAC configuration (member count and delegated admin role)", - SchemaType::role_symbol(), - SchemaType::native_word(), - ), - ) - } - - /// Returns the schema entry for the per-role membership map. - pub fn role_membership_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - Self::role_membership_slot().clone(), - StorageSlotSchema::map( - "Role membership flag indexed by role symbol and account ID", - SchemaType::native_word(), - SchemaType::native_word(), - ), - ) - } - /// Returns the [`AccountComponentMetadata`] describing this component. pub fn component_metadata() -> AccountComponentMetadata { - let storage_schema = StorageSchema::new(vec![ - Self::role_config_slot_schema(), - Self::role_membership_slot_schema(), - ]) - .expect("storage schema should be valid"); - - AccountComponentMetadata::new(Self::NAME) - .with_description("Role-based access control component") - .with_storage_schema(storage_schema) + package_metadata(Self::code()) } } diff --git a/crates/miden-standards/src/account/auth/guarded_multisig.rs b/crates/miden-standards/src/account/auth/guarded_multisig.rs index 837b6b14f5..a1682d5213 100644 --- a/crates/miden-standards/src/account/auth/guarded_multisig.rs +++ b/crates/miden-standards/src/account/auth/guarded_multisig.rs @@ -3,13 +3,7 @@ use alloc::vec::Vec; use miden_protocol::Word; use miden_protocol::account::auth::{AuthScheme, PublicKeyCommitment}; -use miden_protocol::account::component::{ - AccountComponentCode, - AccountComponentMetadata, - SchemaType, - StorageSchema, - StorageSlotSchema, -}; +use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{ AccountComponent, AccountComponentName, @@ -24,7 +18,7 @@ use miden_protocol::utils::sync::LazyLock; use super::multisig::{AuthMultisig, AuthMultisigConfig}; use super::{Approver, ApproverSet}; -use crate::account::account_component_code; +use crate::account::{account_component_code, package_metadata}; account_component_code!(GUARDED_MULTISIG_CODE, "miden-standards-auth-guarded-multisig.masp"); @@ -82,29 +76,8 @@ impl GuardianConfig { &GUARDIAN_SCHEME_ID_SLOT_NAME } - fn public_key_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - Self::public_key_slot().clone(), - StorageSlotSchema::map( - "Guardian public keys", - SchemaType::u32(), - SchemaType::pub_key(), - ), - ) - } - - fn auth_scheme_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - Self::scheme_id_slot().clone(), - StorageSlotSchema::map( - "Guardian scheme IDs", - SchemaType::u32(), - SchemaType::auth_scheme(), - ), - ) - } - - fn into_component_parts(self) -> (Vec, Vec<(StorageSlotName, StorageSlotSchema)>) { + /// Returns the storage slots holding the guardian's public key and signature scheme. + fn into_slots(self) -> Vec { let mut storage_slots = Vec::with_capacity(2); // Guardian public key slot (map: [0, 0, 0, 0] -> pubkey) @@ -125,9 +98,7 @@ impl GuardianConfig { StorageMap::with_entries(guardian_scheme_id_entries).unwrap(), )); - let slot_metadata = vec![Self::public_key_slot_schema(), Self::auth_scheme_slot_schema()]; - - (storage_slots, slot_metadata) + storage_slots } } @@ -275,60 +246,9 @@ impl AuthGuardedMultisig { GuardianConfig::scheme_id_slot() } - /// Returns the storage slot schema for the threshold configuration slot. - pub fn threshold_config_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - AuthMultisig::threshold_config_slot_schema() - } - - /// Returns the storage slot schema for the approver public keys slot. - pub fn approver_public_keys_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - AuthMultisig::approver_public_keys_slot_schema() - } - - // Returns the storage slot schema for the approver scheme IDs slot. - pub fn approver_auth_scheme_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - AuthMultisig::approver_auth_scheme_slot_schema() - } - - /// Returns the storage slot schema for the executed transactions slot. - pub fn executed_transactions_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - AuthMultisig::executed_transactions_slot_schema() - } - - /// Returns the storage slot schema for the procedure thresholds slot. - pub fn procedure_thresholds_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - AuthMultisig::procedure_thresholds_slot_schema() - } - - /// Returns the storage slot schema for the guardian public key slot. - pub fn guardian_public_key_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - GuardianConfig::public_key_slot_schema() - } - - /// Returns the storage slot schema for the guardian scheme IDs slot. - pub fn guardian_auth_scheme_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - GuardianConfig::auth_scheme_slot_schema() - } - /// Returns the [`AccountComponentMetadata`] for this component. pub fn component_metadata() -> AccountComponentMetadata { - let storage_schema = StorageSchema::new([ - Self::threshold_config_slot_schema(), - Self::approver_public_keys_slot_schema(), - Self::approver_auth_scheme_slot_schema(), - Self::executed_transactions_slot_schema(), - Self::procedure_thresholds_slot_schema(), - Self::guardian_public_key_slot_schema(), - Self::guardian_auth_scheme_slot_schema(), - ]) - .expect("storage schema should be valid"); - - AccountComponentMetadata::new(Self::NAME) - .with_description( - "Guarded multisig authentication component integrated \ - with a state guardian using hybrid signature schemes", - ) - .with_storage_schema(storage_schema) + package_metadata(Self::code()) } } @@ -336,25 +256,11 @@ impl From for AccountComponent { fn from(multisig: AuthGuardedMultisig) -> Self { let AuthGuardedMultisig { multisig, guardian_config } = multisig; let multisig_component = AccountComponent::from(multisig); - let (guardian_slots, guardian_slot_metadata) = guardian_config.into_component_parts(); let mut storage_slots = multisig_component.storage_slots().to_vec(); - storage_slots.extend(guardian_slots); - - let mut slot_schemas: Vec<(StorageSlotName, StorageSlotSchema)> = multisig_component - .storage_schema() - .iter() - .map(|(slot_name, slot_schema)| (slot_name.clone(), slot_schema.clone())) - .collect(); - slot_schemas.extend(guardian_slot_metadata); - - let storage_schema = - StorageSchema::new(slot_schemas).expect("storage schema should be valid"); + storage_slots.extend(guardian_config.into_slots()); - let metadata = AccountComponentMetadata::new(AuthGuardedMultisig::NAME) - .with_description(multisig_component.metadata().description()) - .with_version(multisig_component.metadata().version().clone()) - .with_storage_schema(storage_schema); + let metadata = AuthGuardedMultisig::component_metadata(); AccountComponent::new(AuthGuardedMultisig::code().clone(), storage_slots, metadata).expect( "Guarded multisig auth component should satisfy the requirements of a valid \ diff --git a/crates/miden-standards/src/account/auth/multisig.rs b/crates/miden-standards/src/account/auth/multisig.rs index 1b81416a66..baea8bb782 100644 --- a/crates/miden-standards/src/account/auth/multisig.rs +++ b/crates/miden-standards/src/account/auth/multisig.rs @@ -1,14 +1,7 @@ use alloc::collections::BTreeMap; use alloc::vec::Vec; -use miden_protocol::account::component::{ - AccountComponentCode, - AccountComponentMetadata, - FeltSchema, - SchemaType, - StorageSchema, - StorageSlotSchema, -}; +use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{ AccountComponent, AccountComponentName, @@ -25,7 +18,7 @@ use miden_protocol::utils::sync::LazyLock; use miden_protocol::{EMPTY_WORD, Felt, WORD_SIZE, Word, ZERO}; use super::{Approver, ApproverSet, FeeConversionInfo}; -use crate::account::account_component_code; +use crate::account::{account_component_code, package_metadata}; use crate::procedure_root; account_component_code!(MULTISIG_CODE, "miden-standards-auth-multisig.masp"); @@ -318,84 +311,9 @@ impl AuthMultisig { &PROCEDURE_THRESHOLDS_SLOT_NAME } - /// Returns the storage slot schema for the threshold configuration slot. - pub fn threshold_config_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - Self::threshold_config_slot().clone(), - StorageSlotSchema::value( - "Threshold configuration", - [ - FeltSchema::u32("threshold"), - FeltSchema::u32("num_approvers"), - FeltSchema::new_void(), - FeltSchema::new_void(), - ], - ), - ) - } - - /// Returns the storage slot schema for the approver public keys slot. - pub fn approver_public_keys_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - Self::approver_public_keys_slot().clone(), - StorageSlotSchema::map( - "Approver public keys", - SchemaType::u32(), - SchemaType::pub_key(), - ), - ) - } - - // Returns the storage slot schema for the approver scheme IDs slot. - pub fn approver_auth_scheme_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - Self::approver_scheme_ids_slot().clone(), - StorageSlotSchema::map( - "Approver scheme IDs", - SchemaType::u32(), - SchemaType::auth_scheme(), - ), - ) - } - - /// Returns the storage slot schema for the executed transactions slot. - pub fn executed_transactions_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - Self::executed_transactions_slot().clone(), - StorageSlotSchema::map( - "Executed transactions", - SchemaType::native_word(), - SchemaType::native_word(), - ), - ) - } - - /// Returns the storage slot schema for the procedure thresholds slot. - pub fn procedure_thresholds_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - Self::procedure_thresholds_slot().clone(), - StorageSlotSchema::map( - "Procedure thresholds", - SchemaType::native_word(), - SchemaType::u32(), - ), - ) - } - /// Returns the [`AccountComponentMetadata`] for this component. pub fn component_metadata() -> AccountComponentMetadata { - let storage_schema = StorageSchema::new([ - Self::threshold_config_slot_schema(), - Self::approver_public_keys_slot_schema(), - Self::approver_auth_scheme_slot_schema(), - Self::executed_transactions_slot_schema(), - Self::procedure_thresholds_slot_schema(), - ]) - .expect("storage schema should be valid"); - - AccountComponentMetadata::new(Self::NAME) - .with_description("Multisig authentication component using hybrid signature schemes") - .with_storage_schema(storage_schema) + package_metadata(Self::code()) } } diff --git a/crates/miden-standards/src/account/auth/multisig_smart/component.rs b/crates/miden-standards/src/account/auth/multisig_smart/component.rs index 6950b226dc..8a20e4ea69 100644 --- a/crates/miden-standards/src/account/auth/multisig_smart/component.rs +++ b/crates/miden-standards/src/account/auth/multisig_smart/component.rs @@ -1,13 +1,7 @@ use alloc::vec::Vec; use miden_protocol::Word; -use miden_protocol::account::component::{ - AccountComponentCode, - AccountComponentMetadata, - SchemaType, - StorageSchema, - StorageSlotSchema, -}; +use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{ AccountComponent, AccountProcedureRoot, @@ -29,8 +23,8 @@ use super::super::multisig::{ THRESHOLD_CONFIG_SLOT_NAME, }; use super::ProcedurePolicy; -use crate::account::account_component_code; -use crate::account::auth::{Approver, ApproverSet, AuthMultisig}; +use crate::account::auth::{Approver, ApproverSet}; +use crate::account::{account_component_code, package_metadata}; use crate::procedure_root; account_component_code!(MULTISIG_SMART_CODE, "miden-standards-auth-multisig-smart.masp"); @@ -195,31 +189,9 @@ impl AuthMultisigSmart { &PROCEDURE_POLICIES_SLOT_NAME } - pub fn threshold_config_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - AuthMultisig::threshold_config_slot_schema() - } - - pub fn approver_public_keys_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - AuthMultisig::approver_public_keys_slot_schema() - } - - pub fn approver_auth_scheme_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - AuthMultisig::approver_auth_scheme_slot_schema() - } - - pub fn executed_transactions_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - AuthMultisig::executed_transactions_slot_schema() - } - - pub fn procedure_policies_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - Self::procedure_policies_slot().clone(), - StorageSlotSchema::map( - "Procedure policies", - SchemaType::native_word(), - SchemaType::native_word(), - ), - ) + /// Returns the [`AccountComponentMetadata`] for this component. + pub fn component_metadata() -> AccountComponentMetadata { + package_metadata(Self::code()) } } @@ -273,18 +245,7 @@ impl From for AccountComponent { procedure_policies, )); - let storage_schema = StorageSchema::new(vec![ - AuthMultisigSmart::threshold_config_slot_schema(), - AuthMultisigSmart::approver_public_keys_slot_schema(), - AuthMultisigSmart::approver_auth_scheme_slot_schema(), - AuthMultisigSmart::executed_transactions_slot_schema(), - AuthMultisigSmart::procedure_policies_slot_schema(), - ]) - .expect("storage schema should be valid"); - - let metadata = AccountComponentMetadata::new(AuthMultisigSmart::NAME) - .with_description("Multisig smart authentication component") - .with_storage_schema(storage_schema); + let metadata = AuthMultisigSmart::component_metadata(); AccountComponent::new(AuthMultisigSmart::code().clone(), storage_slots, metadata).expect( "multisig smart component should satisfy the requirements of a valid account component", diff --git a/crates/miden-standards/src/account/auth/network_account/auth_network_account.rs b/crates/miden-standards/src/account/auth/network_account/auth_network_account.rs index 505e853c2c..27f08fcd9c 100644 --- a/crates/miden-standards/src/account/auth/network_account/auth_network_account.rs +++ b/crates/miden-standards/src/account/auth/network_account/auth_network_account.rs @@ -1,12 +1,7 @@ use alloc::collections::BTreeSet; use alloc::vec; -use miden_protocol::account::component::{ - AccountComponentCode, - AccountComponentMetadata, - StorageSchema, - StorageSlotSchema, -}; +use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{ AccountComponent, AccountComponentName, @@ -22,8 +17,8 @@ use super::{ NetworkAccountTxScriptAllowlist, SponsorshipPolicy, }; -use crate::account::account_component_code; use crate::account::fees::FeePolicyManager; +use crate::account::{account_component_code, package_metadata}; use crate::note::FeeSponsorshipNote; use crate::note::config::NetworkAccountConfigNote; use crate::procedure_root; @@ -370,48 +365,19 @@ impl AuthNetworkAccount { NetworkAccountNoteAllowlist::slot_name() } - /// Returns the storage slot schema for the note-script allowlist slot. - pub fn allowed_note_scripts_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - NetworkAccountNoteAllowlist::slot_schema() - } - /// Returns the storage slot holding the allowlist of allowed transaction script roots. pub fn allowed_tx_scripts_slot() -> &'static StorageSlotName { NetworkAccountTxScriptAllowlist::slot_name() } - /// Returns the storage slot schema for the tx-script allowlist slot. - pub fn allowed_tx_scripts_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - NetworkAccountTxScriptAllowlist::slot_schema() - } - /// Returns the storage slot holding the sponsorship policy. pub fn sponsorship_policy_slot() -> &'static StorageSlotName { SponsorshipPolicy::slot_name() } - /// Returns the storage slot schema for the sponsorship policy slot. - pub fn sponsorship_policy_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - SponsorshipPolicy::slot_schema() - } - /// Returns the [`AccountComponentMetadata`] for this component. pub fn component_metadata() -> AccountComponentMetadata { - let mut slot_schemas = vec![ - NetworkAccountNoteAllowlist::slot_schema(), - NetworkAccountTxScriptAllowlist::slot_schema(), - SponsorshipPolicy::slot_schema(), - ]; - slot_schemas.extend(FeePolicyManager::slot_schemas()); - let storage_schema = - StorageSchema::new(slot_schemas).expect("storage schema should be valid"); - - AccountComponentMetadata::new(Self::NAME) - .with_description( - "Authentication component that restricts input notes and transaction scripts to \ - fixed allowlists of script roots", - ) - .with_storage_schema(storage_schema) + package_metadata(Self::code()) } } diff --git a/crates/miden-standards/src/account/auth/network_account/note_allowlist.rs b/crates/miden-standards/src/account/auth/network_account/note_allowlist.rs index 4286b0a02c..284fe68491 100644 --- a/crates/miden-standards/src/account/auth/network_account/note_allowlist.rs +++ b/crates/miden-standards/src/account/auth/network_account/note_allowlist.rs @@ -1,6 +1,5 @@ use alloc::collections::BTreeSet; -use miden_protocol::account::component::{SchemaType, StorageSlotSchema}; use miden_protocol::account::{ AccountStorage, StorageMap, @@ -77,18 +76,6 @@ impl NetworkAccountNoteAllowlist { self.allowed_script_roots } - /// Returns the schema entry for the allowlist slot. - pub fn slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - Self::slot_name().clone(), - StorageSlotSchema::map( - "Allowed input note script roots", - SchemaType::native_word(), - SchemaType::native_word(), - ), - ) - } - /// Consumes this allowlist and returns the [`StorageSlot`] suitable for inclusion in an /// [`AccountComponent`](miden_protocol::account::AccountComponent)'s storage layout. pub fn into_storage_slot(self) -> StorageSlot { diff --git a/crates/miden-standards/src/account/auth/network_account/sponsorship_policy.rs b/crates/miden-standards/src/account/auth/network_account/sponsorship_policy.rs index 2d2e1615c6..34e6162cd6 100644 --- a/crates/miden-standards/src/account/auth/network_account/sponsorship_policy.rs +++ b/crates/miden-standards/src/account/auth/network_account/sponsorship_policy.rs @@ -1,4 +1,3 @@ -use miden_protocol::account::component::{SchemaType, StorageSlotSchema}; use miden_protocol::account::{AccountStorage, StorageSlot, StorageSlotContent, StorageSlotName}; use miden_protocol::utils::sync::LazyLock; use miden_protocol::{Felt, Word}; @@ -56,17 +55,6 @@ impl SponsorshipPolicy { &SLOT_NAME } - /// Returns the schema entry for the sponsorship policy slot. - pub fn slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - Self::slot_name().clone(), - StorageSlotSchema::value( - "Whether sponsorships are capped at the fees collected in the same transaction", - SchemaType::native_word(), - ), - ) - } - /// Returns the [`StorageSlot`] encoding this policy, suitable for inclusion in an /// [`AccountComponent`](miden_protocol::account::AccountComponent)'s storage layout. pub fn into_storage_slot(self) -> StorageSlot { diff --git a/crates/miden-standards/src/account/auth/network_account/tx_script_allowlist.rs b/crates/miden-standards/src/account/auth/network_account/tx_script_allowlist.rs index f53ccf181a..c102971b29 100644 --- a/crates/miden-standards/src/account/auth/network_account/tx_script_allowlist.rs +++ b/crates/miden-standards/src/account/auth/network_account/tx_script_allowlist.rs @@ -1,6 +1,5 @@ use alloc::collections::BTreeSet; -use miden_protocol::account::component::{SchemaType, StorageSlotSchema}; use miden_protocol::account::{ AccountStorage, StorageMap, @@ -73,18 +72,6 @@ impl NetworkAccountTxScriptAllowlist { self.allowed_script_roots } - /// Returns the schema entry for the allowlist slot. - pub fn slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - Self::slot_name().clone(), - StorageSlotSchema::map( - "Allowed transaction script roots", - SchemaType::native_word(), - SchemaType::native_word(), - ), - ) - } - /// Extends the set of allowed tx script roots. pub(super) fn extend_script_roots( &mut self, diff --git a/crates/miden-standards/src/account/auth/no_auth.rs b/crates/miden-standards/src/account/auth/no_auth.rs index 4f8e5a1786..0dec0b0670 100644 --- a/crates/miden-standards/src/account/auth/no_auth.rs +++ b/crates/miden-standards/src/account/auth/no_auth.rs @@ -1,7 +1,7 @@ use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{AccountComponent, AccountComponentName}; -use crate::account::account_component_code; +use crate::account::{account_component_code, package_metadata}; account_component_code!(NO_AUTH_CODE, "miden-standards-auth-no-auth.masp"); @@ -44,7 +44,7 @@ impl NoAuth { /// Returns the [`AccountComponentMetadata`] for this component. pub fn component_metadata() -> AccountComponentMetadata { - AccountComponentMetadata::new(Self::NAME).with_description("No authentication component") + package_metadata(Self::code()) } } diff --git a/crates/miden-standards/src/account/auth/singlesig.rs b/crates/miden-standards/src/account/auth/singlesig.rs index 626e740d33..aa0b10a1be 100644 --- a/crates/miden-standards/src/account/auth/singlesig.rs +++ b/crates/miden-standards/src/account/auth/singlesig.rs @@ -1,12 +1,6 @@ use miden_protocol::Word; use miden_protocol::account::auth::{AuthScheme, PublicKey}; -use miden_protocol::account::component::{ - AccountComponentCode, - AccountComponentMetadata, - SchemaType, - StorageSchema, - StorageSlotSchema, -}; +use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{ AccountComponent, AccountComponentName, @@ -17,7 +11,7 @@ use miden_protocol::crypto::dsa::{ecdsa_k256_keccak, falcon512_poseidon2}; use miden_protocol::utils::sync::LazyLock; use super::Approver; -use crate::account::account_component_code; +use crate::account::{account_component_code, package_metadata}; account_component_code!(SINGLESIG_CODE, "miden-standards-auth-singlesig.masp"); @@ -127,34 +121,9 @@ impl AuthSingleSig { &SCHEME_ID_SLOT_NAME } - /// Returns the storage slot schema for the public key slot. - pub fn public_key_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - Self::public_key_slot().clone(), - StorageSlotSchema::value("Public key commitment", SchemaType::pub_key()), - ) - } - /// Returns the storage slot schema for the scheme ID slot. - pub fn auth_scheme_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - Self::scheme_id_slot().clone(), - StorageSlotSchema::value("Scheme ID", SchemaType::auth_scheme()), - ) - } - /// Returns the [`AccountComponentMetadata`] for this component. pub fn component_metadata() -> AccountComponentMetadata { - let storage_schema = StorageSchema::new(vec![ - Self::public_key_slot_schema(), - Self::auth_scheme_slot_schema(), - ]) - .expect("storage schema should be valid"); - - AccountComponentMetadata::new(Self::NAME) - .with_description( - "Authentication component using ECDSA K256 Keccak or Falcon512 Poseidon2 signature scheme", - ) - .with_storage_schema(storage_schema) + package_metadata(Self::code()) } } diff --git a/crates/miden-standards/src/account/faucets/fungible/mod.rs b/crates/miden-standards/src/account/faucets/fungible/mod.rs index 0fd76b4719..79dde74b0b 100644 --- a/crates/miden-standards/src/account/faucets/fungible/mod.rs +++ b/crates/miden-standards/src/account/faucets/fungible/mod.rs @@ -1,13 +1,6 @@ use alloc::vec::Vec; -use miden_protocol::account::component::{ - AccountComponentCode, - AccountComponentMetadata, - FeltSchema, - SchemaType, - StorageSchema, - StorageSlotSchema, -}; +use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{ Account, AccountBuilder, @@ -35,12 +28,12 @@ use super::{ TokenName, }; use crate::account::access::{AccessControl, Authority, Pausable, PausableManager}; -use crate::account::account_component_code; use crate::account::auth::{AuthGuardedMultisig, AuthMultisig, AuthSingleSig, NetworkAccount}; use crate::account::faucets::registers_owner_only_policy; use crate::account::fees::{BasicConstantFeePolicy, FeePolicyManager}; use crate::account::policies::TokenPolicyManager; use crate::account::wallets::BasicWallet; +use crate::account::{account_component_code, package_metadata}; use crate::note::{BurnNote, MintNote}; use crate::procedure_root; @@ -57,9 +50,6 @@ pub(crate) static TOKEN_CONFIG_SLOT: LazyLock = LazyLock::new(| .expect("storage slot name should be valid") }); -/// Schema type string for the token symbol field in the token config slot. -const TOKEN_SYMBOL_TYPE: &str = "miden::standards::faucets::fungible::token_symbol"; - // FUNGIBLE FAUCET ACCOUNT COMPONENT // ================================================================================================ @@ -363,36 +353,9 @@ impl FungibleFaucet { self.metadata.external_link() } - /// Returns the storage slot schema for the token config slot. - pub fn token_config_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - let token_symbol_type = SchemaType::new(TOKEN_SYMBOL_TYPE).expect("valid type"); - ( - Self::token_config_slot().clone(), - StorageSlotSchema::value( - "Token config", - [ - FeltSchema::felt("token_supply").with_default(Felt::ZERO), - FeltSchema::felt("max_supply"), - FeltSchema::u8("decimals"), - FeltSchema::new_typed(token_symbol_type, "symbol"), - ], - ), - ) - } - /// Returns the [`AccountComponentMetadata`] for this component. pub fn component_metadata() -> AccountComponentMetadata { - let mut schema_entries = vec![Self::token_config_slot_schema()]; - schema_entries.extend(TokenMetadata::storage_schema()); - - let storage_schema = - StorageSchema::new(schema_entries).expect("storage schema should be valid"); - - AccountComponentMetadata::new(Self::NAME) - .with_description( - "Fungible faucet component bundling minting, burning, and token metadata", - ) - .with_storage_schema(storage_schema) + package_metadata(Self::code()) } /// Returns the storage slots produced by this faucet (token config word + name + mutability diff --git a/crates/miden-standards/src/account/faucets/non_fungible/mod.rs b/crates/miden-standards/src/account/faucets/non_fungible/mod.rs index 3d5090e19e..74850e319c 100644 --- a/crates/miden-standards/src/account/faucets/non_fungible/mod.rs +++ b/crates/miden-standards/src/account/faucets/non_fungible/mod.rs @@ -1,13 +1,6 @@ use alloc::vec::Vec; -use miden_protocol::account::component::{ - AccountComponentCode, - AccountComponentMetadata, - FeltSchema, - SchemaType, - StorageSchema, - StorageSlotSchema, -}; +use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{ Account, AccountBuilder, @@ -36,11 +29,11 @@ use super::{ TokenName, }; use crate::account::access::{AccessControl, Authority, Pausable, PausableManager}; -use crate::account::account_component_code; use crate::account::auth::{AuthSingleSig, NetworkAccount}; use crate::account::faucets::registers_owner_only_policy; use crate::account::fees::FeePolicyManager; use crate::account::policies::TokenPolicyManager; +use crate::account::{account_component_code, package_metadata}; use crate::note::{BurnNote, MintNote}; use crate::procedure_root; @@ -372,49 +365,9 @@ impl NonFungibleFaucet { AssetStatus::try_from(status_code) } - /// Returns the storage slot schema for the token symbol slot. - pub fn symbol_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - Self::symbol_slot().clone(), - StorageSlotSchema::value( - "Token symbol", - [ - FeltSchema::felt("symbol"), - FeltSchema::new_void(), - FeltSchema::new_void(), - FeltSchema::new_void(), - ], - ), - ) - } - - /// Returns the storage slot schema for the asset-status registry map. - pub fn asset_status_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - Self::asset_status_slot().clone(), - StorageSlotSchema::map( - "Asset status registry. Key is the token ID padded to a word \ - `[token_id_suffix, token_id_prefix, 0, 0]`; value is the status (0 = not issued, \ - 1 = issued, 2 = burned) padded to a word `[status, 0, 0, 0]`.", - SchemaType::native_word(), - SchemaType::native_felt(), - ), - ) - } - /// Returns the [`AccountComponentMetadata`] for this component. pub fn component_metadata() -> AccountComponentMetadata { - let mut schema_entries = vec![Self::symbol_slot_schema(), Self::asset_status_slot_schema()]; - schema_entries.extend(TokenMetadata::storage_schema()); - - let storage_schema = - StorageSchema::new(schema_entries).expect("storage schema should be valid"); - - AccountComponentMetadata::new(Self::NAME) - .with_description( - "Non-fungible faucet component bundling minting, burning, status, and metadata", - ) - .with_storage_schema(storage_schema) + package_metadata(Self::code()) } /// Returns the storage slots produced by this faucet (token symbol word + empty asset-status diff --git a/crates/miden-standards/src/account/faucets/token_metadata.rs b/crates/miden-standards/src/account/faucets/token_metadata.rs index 36096ca15a..fdbe180215 100644 --- a/crates/miden-standards/src/account/faucets/token_metadata.rs +++ b/crates/miden-standards/src/account/faucets/token_metadata.rs @@ -35,7 +35,6 @@ use alloc::vec::Vec; -use miden_protocol::account::component::{FeltSchema, StorageSlotSchema}; use miden_protocol::account::{AccountStorage, StorageSlot, StorageSlotName}; use miden_protocol::utils::sync::LazyLock; use miden_protocol::{Felt, Word}; @@ -403,55 +402,6 @@ impl TokenMetadata { &EXTERNAL_LINK_SLOTS[index] } - /// Returns the storage slot schema entries describing the token metadata layout - /// (name chunks, mutability config, description, logo URI, external link). - /// - /// Embedding components should call this and extend their own schema with the result. - pub fn storage_schema() -> Vec<(StorageSlotName, StorageSlotSchema)> { - let mut entries: Vec<(StorageSlotName, StorageSlotSchema)> = Vec::new(); - - for (i, slot) in NAME_SLOTS.iter().enumerate() { - entries.push(( - slot.clone(), - StorageSlotSchema::value( - alloc::format!("Name chunk {i}"), - core::array::from_fn(|j| FeltSchema::felt(alloc::format!("data_{j}"))), - ), - )); - } - - entries.push(( - MUTABILITY_CONFIG_SLOT.clone(), - StorageSlotSchema::value( - "Mutability config", - [ - FeltSchema::bool("is_description_mutable"), - FeltSchema::bool("is_logo_uri_mutable"), - FeltSchema::bool("is_external_link_mutable"), - FeltSchema::bool("is_max_supply_mutable"), - ], - ), - )); - - for (label, slots) in [ - ("Description", DESCRIPTION_SLOTS.as_slice()), - ("Logo URI", LOGO_URI_SLOTS.as_slice()), - ("External link", EXTERNAL_LINK_SLOTS.as_slice()), - ] { - for (i, slot) in slots.iter().enumerate() { - entries.push(( - slot.clone(), - StorageSlotSchema::value( - alloc::format!("{label} chunk {i}"), - core::array::from_fn(|j| FeltSchema::felt(alloc::format!("data_{j}"))), - ), - )); - } - } - - entries - } - // STORAGE // -------------------------------------------------------------------------------------------- diff --git a/crates/miden-standards/src/account/fees/fee_policy_manager.rs b/crates/miden-standards/src/account/fees/fee_policy_manager.rs index 8b3b3ce202..f5b67884e5 100644 --- a/crates/miden-standards/src/account/fees/fee_policy_manager.rs +++ b/crates/miden-standards/src/account/fees/fee_policy_manager.rs @@ -4,7 +4,6 @@ use alloc::collections::BTreeMap; use alloc::vec::Vec; use miden_protocol::Word; -use miden_protocol::account::component::{SchemaType, StorageSlotSchema}; use miden_protocol::account::{ AccountComponent, AccountId, @@ -143,38 +142,6 @@ impl FeePolicyManager { &FEE_ASSET_ID_SLOT_NAME } - /// Returns the schema entries for the three fee-policy storage slots. - /// - /// These slots are installed by the owning - /// [`AuthNetworkAccount`][crate::account::auth::AuthNetworkAccount] component, whose storage - /// schema includes them. - pub(crate) fn slot_schemas() -> [(StorageSlotName, StorageSlotSchema); 3] { - [ - ( - ACTIVE_FEE_POLICY_PROC_ROOT_SLOT_NAME.clone(), - StorageSlotSchema::value( - "Active fee policy procedure root", - SchemaType::native_word(), - ), - ), - ( - ALLOWED_FEE_POLICY_PROC_ROOTS_SLOT_NAME.clone(), - StorageSlotSchema::map( - "Allowed fee policy procedure roots", - SchemaType::native_word(), - SchemaType::native_word(), - ), - ), - ( - FEE_ASSET_ID_SLOT_NAME.clone(), - StorageSlotSchema::value( - "ID of the asset fees are charged in", - SchemaType::native_word(), - ), - ), - ] - } - /// Builds the three fee-policy storage slots from this manager's configuration: /// - the active-policy value. /// - the allowed-policies map. diff --git a/crates/miden-standards/src/account/fees/policies/basic_constant_fee.rs b/crates/miden-standards/src/account/fees/policies/basic_constant_fee.rs index f82ddad6fe..1d4c0c4941 100644 --- a/crates/miden-standards/src/account/fees/policies/basic_constant_fee.rs +++ b/crates/miden-standards/src/account/fees/policies/basic_constant_fee.rs @@ -1,12 +1,6 @@ use alloc::collections::BTreeMap; -use miden_protocol::account::component::{ - AccountComponentCode, - AccountComponentMetadata, - SchemaType, - StorageSchema, - StorageSlotSchema, -}; +use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{ AccountComponent, AccountComponentName, @@ -21,7 +15,7 @@ use miden_protocol::note::NoteScriptRoot; use miden_protocol::utils::sync::LazyLock; use miden_protocol::{Felt, Word}; -use crate::account::account_component_code; +use crate::account::{account_component_code, package_metadata}; use crate::procedure_root; // BASIC CONSTANT FEE POLICY @@ -172,21 +166,7 @@ impl BasicConstantFeePolicy { /// Returns the [`AccountComponentMetadata`] for this component. pub fn component_metadata() -> AccountComponentMetadata { - let storage_schema = StorageSchema::new([( - Self::fee_schedule_slot_name().clone(), - StorageSlotSchema::map( - "Fee charged per note script root", - SchemaType::native_word(), - SchemaType::native_word(), - ), - )]) - .expect("storage schema should be valid"); - - AccountComponentMetadata::new(Self::NAME) - .with_description( - "`basic_constant_fee` fee policy charging a constant per-note-script fee", - ) - .with_storage_schema(storage_schema) + package_metadata(Self::code()) } } diff --git a/crates/miden-standards/src/account/fees/policies/constant_fee_manager.rs b/crates/miden-standards/src/account/fees/policies/constant_fee_manager.rs index 15c8c2b6e2..3ce295777e 100644 --- a/crates/miden-standards/src/account/fees/policies/constant_fee_manager.rs +++ b/crates/miden-standards/src/account/fees/policies/constant_fee_manager.rs @@ -1,10 +1,4 @@ -use miden_protocol::account::component::{ - AccountComponentCode, - AccountComponentMetadata, - SchemaType, - StorageSchema, - StorageSlotSchema, -}; +use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{ AccountComponent, AccountProcedureRoot, @@ -15,7 +9,7 @@ use miden_protocol::utils::sync::LazyLock; use miden_protocol::{Felt, Word}; use super::BasicConstantFeePolicy; -use crate::account::account_component_code; +use crate::account::{account_component_code, package_metadata}; use crate::procedure_root; // CONSTANT FEE MANAGER @@ -140,22 +134,7 @@ impl ConstantFeeManager { /// Returns the [`AccountComponentMetadata`] for this component. pub fn component_metadata() -> AccountComponentMetadata { - let storage_schema = StorageSchema::new([( - FEE_SCHEDULE_SLOT_ID_SLOT_NAME.clone(), - StorageSlotSchema::value( - "ID of the fee schedule slot this manager updates", - SchemaType::native_word(), - ), - )]) - .expect("storage schema should be valid"); - - AccountComponentMetadata::new(Self::NAME) - .with_description( - "Authority-gated constant-fee schedule admin: exposes `set_note_fee` to update the \ - fee schedule slot recorded in its storage, gated by the account-wide Authority \ - component.", - ) - .with_storage_schema(storage_schema) + package_metadata(Self::code()) } } diff --git a/crates/miden-standards/src/account/inspection/code_inspection.rs b/crates/miden-standards/src/account/inspection/code_inspection.rs index d8a54a1d88..937ab9155a 100644 --- a/crates/miden-standards/src/account/inspection/code_inspection.rs +++ b/crates/miden-standards/src/account/inspection/code_inspection.rs @@ -1,7 +1,7 @@ use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{AccountComponent, AccountComponentName, AccountProcedureRoot}; -use crate::account::account_component_code; +use crate::account::{account_component_code, package_metadata}; use crate::procedure_root; // CODE INSPECTION @@ -115,8 +115,7 @@ impl CodeInspection { /// Returns the [`AccountComponentMetadata`] for this component. pub fn component_metadata() -> AccountComponentMetadata { - AccountComponentMetadata::new(Self::NAME) - .with_description("Read-only introspection over the account's own code") + package_metadata(Self::code()) } } diff --git a/crates/miden-standards/src/account/inspection/schema_commitment.rs b/crates/miden-standards/src/account/inspection/schema_commitment.rs index 57d8f2c32f..f2b436eb19 100644 --- a/crates/miden-standards/src/account/inspection/schema_commitment.rs +++ b/crates/miden-standards/src/account/inspection/schema_commitment.rs @@ -12,10 +12,7 @@ use miden_protocol::Word; use miden_protocol::account::component::{ AccountComponentCode, AccountComponentMetadata, - SchemaType, StorageSchema, - StorageSlotSchema, - WordSchema, }; use miden_protocol::account::{ Account, @@ -27,7 +24,7 @@ use miden_protocol::account::{ use miden_protocol::errors::{AccountError, ComponentMetadataError}; use miden_protocol::utils::sync::LazyLock; -use crate::account::account_component_code; +use crate::account::{account_component_code, package_metadata}; // CONSTANTS // ================================================================================================ @@ -65,7 +62,8 @@ pub struct AccountSchemaCommitment { impl AccountSchemaCommitment { /// Name of the component is set to match the path of the corresponding module in the standards /// library. - const NAME: &str = "miden::standards::inspection::storage_schema"; + pub const NAME: &str = "miden::standards::inspection::storage_schema"; + /// Creates a new [`AccountSchemaCommitment`] component from storage schemas. /// /// The input schemas are merged into a single schema before the final commitment is computed. @@ -98,18 +96,7 @@ impl AccountSchemaCommitment { /// Returns the [`AccountComponentMetadata`] for this component. pub fn component_metadata() -> AccountComponentMetadata { - let storage_schema = StorageSchema::new([( - Self::schema_commitment_slot().clone(), - StorageSlotSchema::value( - "Commitment to the storage schema of an account", - WordSchema::new_simple(SchemaType::native_word()), - ), - )]) - .expect("storage schema should be valid"); - - AccountComponentMetadata::new(Self::NAME) - .with_description("Component exposing the account storage schema commitment") - .with_storage_schema(storage_schema) + package_metadata(Self::code()) } } diff --git a/crates/miden-standards/src/account/mod.rs b/crates/miden-standards/src/account/mod.rs index eaa78080f1..86a902e76e 100644 --- a/crates/miden-standards/src/account/mod.rs +++ b/crates/miden-standards/src/account/mod.rs @@ -1,3 +1,10 @@ +use miden_protocol::account::StorageSlotName; +use miden_protocol::account::component::{ + AccountComponentCode, + AccountComponentMetadata, + StorageSchema, +}; + pub mod access; pub mod auth; pub mod components; @@ -91,3 +98,30 @@ macro_rules! account_component_code { } pub(crate) use account_component_code; + +/// Returns the [`AccountComponentMetadata`] embedded in a component package shipped by this crate. +/// +/// The metadata is declared in the component's `miden-project.toml` manifest and embedded into +/// the package by the build script. +pub(crate) fn package_metadata(code: &AccountComponentCode) -> AccountComponentMetadata { + AccountComponentMetadata::try_from(code.as_package()) + .expect("shipped component package should declare account component metadata") +} + +/// Returns `metadata` with the given slots removed from its storage schema. +/// +/// Used by components whose manifest declares the superset of all possible slots while a +/// particular configuration installs only a subset. +pub(crate) fn metadata_without_slots( + metadata: AccountComponentMetadata, + excluded: &[&StorageSlotName], +) -> AccountComponentMetadata { + let slots = metadata + .storage_schema() + .iter() + .filter(|(slot_name, _)| !excluded.contains(slot_name)) + .map(|(slot_name, schema)| (slot_name.clone(), schema.clone())); + let storage_schema = StorageSchema::new(slots).expect("a subset of a valid schema is valid"); + + metadata.with_storage_schema(storage_schema) +} diff --git a/crates/miden-standards/src/account/note_creator.rs b/crates/miden-standards/src/account/note_creator.rs index 8a70ca6998..08b832da61 100644 --- a/crates/miden-standards/src/account/note_creator.rs +++ b/crates/miden-standards/src/account/note_creator.rs @@ -1,7 +1,7 @@ use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{AccountComponent, AccountComponentName, AccountProcedureRoot}; -use crate::account::account_component_code; +use crate::account::{account_component_code, package_metadata}; use crate::procedure_root; // NOTE CREATOR @@ -65,8 +65,7 @@ impl NoteCreator { /// Returns the [`AccountComponentMetadata`] for this component. pub fn component_metadata() -> AccountComponentMetadata { - AccountComponentMetadata::new(Self::NAME) - .with_description("Note creator component exposing only the create_note procedure") + package_metadata(Self::code()) } } diff --git a/crates/miden-standards/src/account/policies/burn/allow_all.rs b/crates/miden-standards/src/account/policies/burn/allow_all.rs index 0d6717e91d..e25e323b83 100644 --- a/crates/miden-standards/src/account/policies/burn/allow_all.rs +++ b/crates/miden-standards/src/account/policies/burn/allow_all.rs @@ -1,7 +1,7 @@ use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{AccountComponent, AccountComponentName, AccountProcedureRoot}; -use crate::account::account_component_code; +use crate::account::{account_component_code, package_metadata}; use crate::procedure_root; // ALLOW-ALL BURN POLICY @@ -55,12 +55,16 @@ impl BurnAllowAll { pub fn root() -> AccountProcedureRoot { *ALLOW_ALL_POLICY_ROOT } + + /// Returns the [`AccountComponentMetadata`] for this component. + pub fn component_metadata() -> AccountComponentMetadata { + package_metadata(Self::code()) + } } impl From for AccountComponent { fn from(_: BurnAllowAll) -> Self { - let metadata = AccountComponentMetadata::new(BurnAllowAll::NAME) - .with_description("`allow_all` burn policy for fungible faucets"); + let metadata = BurnAllowAll::component_metadata(); AccountComponent::new(BurnAllowAll::code().clone(), 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/min_burn_amount.rs b/crates/miden-standards/src/account/policies/burn/min_burn_amount.rs index 9f9eccf79b..95759d1e03 100644 --- a/crates/miden-standards/src/account/policies/burn/min_burn_amount.rs +++ b/crates/miden-standards/src/account/policies/burn/min_burn_amount.rs @@ -1,10 +1,4 @@ -use miden_protocol::account::component::{ - AccountComponentCode, - AccountComponentMetadata, - SchemaType, - StorageSchema, - StorageSlotSchema, -}; +use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{ AccountComponent, AccountComponentName, @@ -16,7 +10,7 @@ use miden_protocol::asset::AssetAmount; use miden_protocol::utils::sync::LazyLock; use miden_protocol::{Felt, Word}; -use crate::account::account_component_code; +use crate::account::{account_component_code, package_metadata}; use crate::procedure_root; // MIN-BURN-AMOUNT BURN POLICY @@ -124,14 +118,6 @@ impl MinBurnAmount { self.min_burn_amount } - /// Returns the storage slot schema for the minimum burn amount slot. - pub fn slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - Self::slot_name().clone(), - StorageSlotSchema::value("Minimum burn amount", SchemaType::native_word()), - ) - } - /// Converts the configured minimum burn amount into its storage value word /// `[min_burn_amount, 0, 0, 0]`. fn to_word(self) -> Word { @@ -145,12 +131,7 @@ impl MinBurnAmount { /// Returns the [`AccountComponentMetadata`] for this component. pub fn component_metadata() -> AccountComponentMetadata { - let storage_schema = - StorageSchema::new([Self::slot_schema()]).expect("storage schema should be valid"); - - AccountComponentMetadata::new(Self::NAME) - .with_description("`min_burn_amount` burn policy for fungible faucets") - .with_storage_schema(storage_schema) + package_metadata(Self::code()) } } diff --git a/crates/miden-standards/src/account/policies/burn/owner_only.rs b/crates/miden-standards/src/account/policies/burn/owner_only.rs index 808eecb3ed..ee93e2e8bd 100644 --- a/crates/miden-standards/src/account/policies/burn/owner_only.rs +++ b/crates/miden-standards/src/account/policies/burn/owner_only.rs @@ -1,7 +1,7 @@ use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{AccountComponent, AccountComponentName, AccountProcedureRoot}; -use crate::account::account_component_code; +use crate::account::{account_component_code, package_metadata}; use crate::procedure_root; // OWNER-ONLY BURN POLICY @@ -60,13 +60,16 @@ impl BurnOwnerOnly { pub fn root() -> AccountProcedureRoot { *OWNER_ONLY_POLICY_ROOT } + + /// Returns the [`AccountComponentMetadata`] for this component. + pub fn component_metadata() -> AccountComponentMetadata { + package_metadata(Self::code()) + } } impl From for AccountComponent { fn from(_: BurnOwnerOnly) -> Self { - let metadata = AccountComponentMetadata::new(BurnOwnerOnly::NAME).with_description( - "`owner_only` burn policy (owner-controlled family) for fungible faucets", - ); + let metadata = BurnOwnerOnly::component_metadata(); AccountComponent::new(BurnOwnerOnly::code().clone(), 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/manager.rs b/crates/miden-standards/src/account/policies/manager.rs index d61440a06d..f0d0ed640f 100644 --- a/crates/miden-standards/src/account/policies/manager.rs +++ b/crates/miden-standards/src/account/policies/manager.rs @@ -20,6 +20,7 @@ use miden_protocol::account::component::{ SchemaType, StorageSchema, StorageSlotSchema, + ValueSlotSchema, WordSchema, }; use miden_protocol::account::{ @@ -37,7 +38,7 @@ use miden_protocol::utils::sync::LazyLock; use super::burn::BurnPolicy; use super::mint::MintPolicy; use super::transfer::TransferPolicy; -use crate::account::account_component_code; +use crate::account::{account_component_code, metadata_without_slots, package_metadata}; use crate::procedure_root; account_component_code!( @@ -527,95 +528,58 @@ impl TokenPolicyManager { &POLICY_MANAGER_CODE } - /// Returns the [`AccountComponentMetadata`] for this component. - pub fn component_metadata() -> AccountComponentMetadata { - let storage_schema = StorageSchema::new(vec![ - ( - ACTIVE_MINT_POLICY_PROC_ROOT_SLOT_NAME.clone(), - StorageSlotSchema::value( - "Active mint policy procedure root", - SchemaType::native_word(), - ), - ), - ( - ACTIVE_BURN_POLICY_PROC_ROOT_SLOT_NAME.clone(), - StorageSlotSchema::value( - "Active burn policy procedure root", - SchemaType::native_word(), - ), - ), - ( - ACTIVE_SEND_POLICY_PROC_ROOT_SLOT_NAME.clone(), - StorageSlotSchema::value( - "Active send policy procedure root", - SchemaType::native_word(), - ), - ), - ( - ACTIVE_RECEIVE_POLICY_PROC_ROOT_SLOT_NAME.clone(), - StorageSlotSchema::value( - "Active receive policy procedure root", - SchemaType::native_word(), - ), - ), - ( - ALLOWED_MINT_POLICY_PROC_ROOTS_SLOT_NAME.clone(), - StorageSlotSchema::map( - "Allowed mint policy procedure roots", - SchemaType::native_word(), - SchemaType::native_word(), - ), - ), - ( - ALLOWED_BURN_POLICY_PROC_ROOTS_SLOT_NAME.clone(), - StorageSlotSchema::map( - "Allowed burn policy procedure roots", - SchemaType::native_word(), - SchemaType::native_word(), - ), - ), - ( - ALLOWED_SEND_POLICY_PROC_ROOTS_SLOT_NAME.clone(), - StorageSlotSchema::map( - "Allowed send policy procedure roots", - SchemaType::native_word(), - SchemaType::native_word(), - ), - ), - ( - ALLOWED_RECEIVE_POLICY_PROC_ROOTS_SLOT_NAME.clone(), - StorageSlotSchema::map( - "Allowed receive policy procedure roots", - SchemaType::native_word(), - SchemaType::native_word(), - ), - ), + /// Returns the [`AccountComponentMetadata`] for this configuration. + /// + /// The returned schema might not be the exact schema defined in the component manifest: the + /// asset-callback slots are only installed when at least one send or receive policy is + /// configured, and when installed they default to the `invoke_*_policy` wrapper roots, which + /// are only known once the component code is compiled and so cannot be declared in the + /// manifest. + pub fn component_metadata(&self) -> AccountComponentMetadata { + let metadata = package_metadata(Self::code()); + if !self.has_transfer_policy() { + return metadata_without_slots( + metadata, + &[ + AssetCallbacks::on_before_asset_added_to_account_slot(), + AssetCallbacks::on_before_asset_added_to_note_slot(), + ], + ); + } + + let callback_defaults = [ ( - AssetCallbacks::on_before_asset_added_to_account_slot().clone(), - StorageSlotSchema::value( - "on_before_asset_added_to_account callback procedure root", - WordSchema::new_simple_with_default( - SchemaType::native_word(), - Self::invoke_receive_policy_root().as_word(), - ), - ), + AssetCallbacks::on_before_asset_added_to_account_slot(), + Self::invoke_receive_policy_root(), ), ( - AssetCallbacks::on_before_asset_added_to_note_slot().clone(), - StorageSlotSchema::value( - "on_before_asset_added_to_note callback procedure root", - WordSchema::new_simple_with_default( - SchemaType::native_word(), - Self::invoke_send_policy_root().as_word(), - ), - ), + AssetCallbacks::on_before_asset_added_to_note_slot(), + Self::invoke_send_policy_root(), ), - ]) - .expect("storage schema should be valid"); + ]; + let slots = metadata.storage_schema().iter().map(|(slot_name, schema)| { + let schema = match callback_defaults.iter().find(|(name, _)| *name == slot_name) { + Some((_, root)) => { + let description = match schema { + StorageSlotSchema::Value(value) => value.description().cloned(), + StorageSlotSchema::Map(_) => None, + }; + StorageSlotSchema::Value(ValueSlotSchema::new( + description, + WordSchema::new_simple_with_default( + SchemaType::native_word(), + root.as_word(), + ), + )) + }, + None => schema.clone(), + }; + (slot_name.clone(), schema) + }); + let storage_schema = + StorageSchema::new(slots).expect("adding defaults keeps a valid schema valid"); - AccountComponentMetadata::new(Self::NAME) - .with_description(Self::DESCRIPTION) - .with_storage_schema(storage_schema) + metadata.with_storage_schema(storage_schema) } /// Returns `true` if at least one send or receive policy is configured, in which case the @@ -708,7 +672,7 @@ impl TokenPolicyManager { AccountComponent::new( Self::code().clone(), storage_slots, - Self::component_metadata(), + self.component_metadata(), ) .expect( "token policy manager component should satisfy the requirements of a valid account component", @@ -776,6 +740,19 @@ mod tests { component.storage_slots().iter().find(|slot| slot.name() == slot_name) } + /// Asserts the component's metadata schema declares exactly the slots the component installs. + fn assert_schema_matches_storage(component: &AccountComponent) { + let schema: BTreeSet<_> = component + .metadata() + .storage_schema() + .iter() + .map(|(name, _)| name.clone()) + .collect(); + let storage: BTreeSet<_> = + component.storage_slots().iter().map(|slot| slot.name().clone()).collect(); + assert_eq!(schema, storage); + } + /// Checks that a manager configured with a transfer policy for both kinds registers the /// protocol-reserved asset-callback slots populated with the fixed `invoke_*_policy` wrapper /// roots (the active `TransferAllowAll` root lives in the `active_*_policy` slots instead). @@ -821,6 +798,8 @@ mod tests { .expect("active receive policy slot must be registered"); assert_eq!(active_send_slot.value(), allow_all_root); assert_eq!(active_receive_slot.value(), allow_all_root); + + assert_schema_matches_storage(&manager_component); } /// Checks that a manager whose send / receive policies are registered only as reserved @@ -872,6 +851,8 @@ mod tests { // The reserved roots are recorded in the allowed-roots maps so they can be promoted later. assert!(manager.allowed_send_policies().contains(&TransferPolicy::allow_all().root())); assert!(manager.allowed_receive_policies().contains(&TransferPolicy::allow_all().root())); + + assert_schema_matches_storage(&manager_component); } /// A manager configured without send / receive policies must NOT register the protocol @@ -897,6 +878,8 @@ mod tests { "without a send policy, the manager must leave the on_before_asset_added_to_note slot \ to a separate component", ); + + assert_schema_matches_storage(&manager_component); } /// The schema-driven construction path must produce the same storage layout as a manager @@ -933,7 +916,8 @@ mod tests { .expect("active policy root should be a valid init value"); } - let schema_slots = TokenPolicyManager::component_metadata() + let schema_slots = manager + .component_metadata() .storage_schema() .build_storage_slots(&init_storage_data) .expect("schema should build the manager's storage slots"); diff --git a/crates/miden-standards/src/account/policies/mint/allow_all.rs b/crates/miden-standards/src/account/policies/mint/allow_all.rs index d9d6ce722b..19496e8034 100644 --- a/crates/miden-standards/src/account/policies/mint/allow_all.rs +++ b/crates/miden-standards/src/account/policies/mint/allow_all.rs @@ -1,7 +1,7 @@ use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{AccountComponent, AccountComponentName, AccountProcedureRoot}; -use crate::account::account_component_code; +use crate::account::{account_component_code, package_metadata}; use crate::procedure_root; // ALLOW-ALL MINT POLICY @@ -55,12 +55,16 @@ impl MintAllowAll { pub fn root() -> AccountProcedureRoot { *ALLOW_ALL_POLICY_ROOT } + + /// Returns the [`AccountComponentMetadata`] for this component. + pub fn component_metadata() -> AccountComponentMetadata { + package_metadata(Self::code()) + } } impl From for AccountComponent { fn from(_: MintAllowAll) -> Self { - let metadata = AccountComponentMetadata::new(MintAllowAll::NAME) - .with_description("`allow_all` mint policy for fungible faucets"); + let metadata = MintAllowAll::component_metadata(); AccountComponent::new(MintAllowAll::code().clone(), 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/owner_only.rs b/crates/miden-standards/src/account/policies/mint/owner_only.rs index ee3c242495..87274ae8fc 100644 --- a/crates/miden-standards/src/account/policies/mint/owner_only.rs +++ b/crates/miden-standards/src/account/policies/mint/owner_only.rs @@ -1,7 +1,7 @@ use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{AccountComponent, AccountComponentName, AccountProcedureRoot}; -use crate::account::account_component_code; +use crate::account::{account_component_code, package_metadata}; use crate::procedure_root; // OWNER-ONLY MINT POLICY @@ -60,13 +60,16 @@ impl MintOwnerOnly { pub fn root() -> AccountProcedureRoot { *OWNER_ONLY_POLICY_ROOT } + + /// Returns the [`AccountComponentMetadata`] for this component. + pub fn component_metadata() -> AccountComponentMetadata { + package_metadata(Self::code()) + } } impl From for AccountComponent { fn from(_: MintOwnerOnly) -> Self { - let metadata = AccountComponentMetadata::new(MintOwnerOnly::NAME).with_description( - "`owner_only` mint policy (owner-controlled family) for fungible faucets", - ); + let metadata = MintOwnerOnly::component_metadata(); AccountComponent::new(MintOwnerOnly::code().clone(), 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/transfer/allow_all.rs b/crates/miden-standards/src/account/policies/transfer/allow_all.rs index 2e91721929..f615d6cdd7 100644 --- a/crates/miden-standards/src/account/policies/transfer/allow_all.rs +++ b/crates/miden-standards/src/account/policies/transfer/allow_all.rs @@ -1,7 +1,7 @@ use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{AccountComponent, AccountProcedureRoot}; -use crate::account::account_component_code; +use crate::account::{account_component_code, package_metadata}; use crate::procedure_root; // ALLOW-ALL TRANSFER POLICY @@ -49,12 +49,16 @@ impl TransferAllowAll { pub fn root() -> AccountProcedureRoot { *ALLOW_ALL_TRANSFER_POLICY_ROOT } + + /// Returns the [`AccountComponentMetadata`] for this component. + pub fn component_metadata() -> AccountComponentMetadata { + package_metadata(Self::code()) + } } impl From for AccountComponent { fn from(_: TransferAllowAll) -> Self { - let metadata = AccountComponentMetadata::new(TransferAllowAll::NAME) - .with_description("`allow_all` transfer policy for callback-enabled faucets"); + let metadata = TransferAllowAll::component_metadata(); AccountComponent::new(TransferAllowAll::code().clone(), vec![], metadata).expect( "`allow_all` transfer policy component should satisfy the requirements of a valid account component", diff --git a/crates/miden-standards/src/account/policies/transfer/allowlist/manager.rs b/crates/miden-standards/src/account/policies/transfer/allowlist/manager.rs index 7efa04700b..c025a3b025 100644 --- a/crates/miden-standards/src/account/policies/transfer/allowlist/manager.rs +++ b/crates/miden-standards/src/account/policies/transfer/allowlist/manager.rs @@ -1,7 +1,7 @@ use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{AccountComponent, AccountProcedureRoot}; -use crate::account::account_component_code; +use crate::account::{account_component_code, package_metadata}; use crate::procedure_root; account_component_code!( @@ -81,10 +81,7 @@ impl AllowlistManager { /// Returns the [`AccountComponentMetadata`] for this component. pub fn component_metadata() -> AccountComponentMetadata { - AccountComponentMetadata::new(Self::NAME).with_description( - "Authority-gated allowlist admin: wraps `allowlist::allow_account` / \ - `disallow_account` with the account-wide Authority component.", - ) + package_metadata(Self::code()) } } diff --git a/crates/miden-standards/src/account/policies/transfer/allowlist/mod.rs b/crates/miden-standards/src/account/policies/transfer/allowlist/mod.rs index 421d6943e5..8c260e372b 100644 --- a/crates/miden-standards/src/account/policies/transfer/allowlist/mod.rs +++ b/crates/miden-standards/src/account/policies/transfer/allowlist/mod.rs @@ -1,7 +1,6 @@ use alloc::collections::BTreeSet; use miden_protocol::Word; -use miden_protocol::account::component::{SchemaType, StorageSlotSchema}; use miden_protocol::account::{AccountId, StorageMap, StorageMapKey, StorageSlot, StorageSlotName}; use miden_protocol::block::account_tree::AccountIdKey; use miden_protocol::utils::sync::LazyLock; @@ -64,18 +63,6 @@ impl AllowlistStorage { &ALLOWED_ACCOUNTS_SLOT_NAME } - /// Schema entry for the allowed-accounts map slot (documentation / tooling). - pub fn allowed_accounts_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - Self::allowed_accounts_slot().clone(), - StorageSlotSchema::map( - "Per-account allowed flag; zero word is not allowed, [1,0,0,0] is allowed", - SchemaType::native_word(), - SchemaType::bool(), - ), - ) - } - /// Builds the initial `allowed_accounts` [`StorageMap`] from the captured set, marking each /// account ID's map entry with the `[1, 0, 0, 0]` allowed-flag word. pub fn build_storage_map(&self) -> StorageMap { diff --git a/crates/miden-standards/src/account/policies/transfer/basic_allowlist.rs b/crates/miden-standards/src/account/policies/transfer/basic_allowlist.rs index 1a595823b3..0bbbece383 100644 --- a/crates/miden-standards/src/account/policies/transfer/basic_allowlist.rs +++ b/crates/miden-standards/src/account/policies/transfer/basic_allowlist.rs @@ -1,14 +1,10 @@ use alloc::collections::BTreeSet; -use miden_protocol::account::component::{ - AccountComponentCode, - AccountComponentMetadata, - StorageSchema, -}; +use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{AccountComponent, AccountId, AccountProcedureRoot}; -use crate::account::account_component_code; use crate::account::policies::transfer::allowlist::AllowlistStorage; +use crate::account::{account_component_code, package_metadata}; use crate::procedure_root; // BASIC ALLOWLIST TRANSFER POLICY @@ -78,6 +74,11 @@ impl BasicAllowlist { pub fn root() -> AccountProcedureRoot { *BASIC_ALLOWLIST_TRANSFER_POLICY_ROOT } + + /// Returns the [`AccountComponentMetadata`] for this component. + pub fn component_metadata() -> AccountComponentMetadata { + package_metadata(Self::code()) + } } impl From for BasicAllowlist { @@ -88,15 +89,7 @@ impl From for BasicAllowlist { impl From for AccountComponent { fn from(allowlist: BasicAllowlist) -> Self { - let storage_schema = StorageSchema::new([AllowlistStorage::allowed_accounts_slot_schema()]) - .expect("storage schema should be valid"); - - let metadata = AccountComponentMetadata::new(BasicAllowlist::NAME) - .with_description( - "Basic allowlist transfer policy: predicate procedure plus the `allowed_accounts` \ - storage map it reads", - ) - .with_storage_schema(storage_schema); + let metadata = BasicAllowlist::component_metadata(); AccountComponent::new(BasicAllowlist::code().clone(), vec![allowlist.0.into_slot()], metadata) .expect( diff --git a/crates/miden-standards/src/account/policies/transfer/basic_blocklist.rs b/crates/miden-standards/src/account/policies/transfer/basic_blocklist.rs index 56322c2250..741e69be0a 100644 --- a/crates/miden-standards/src/account/policies/transfer/basic_blocklist.rs +++ b/crates/miden-standards/src/account/policies/transfer/basic_blocklist.rs @@ -1,14 +1,10 @@ use alloc::collections::BTreeSet; -use miden_protocol::account::component::{ - AccountComponentCode, - AccountComponentMetadata, - StorageSchema, -}; +use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{AccountComponent, AccountId, AccountProcedureRoot}; -use crate::account::account_component_code; use crate::account::policies::transfer::blocklist::BlocklistStorage; +use crate::account::{account_component_code, package_metadata}; use crate::procedure_root; // BASIC BLOCKLIST TRANSFER POLICY @@ -83,6 +79,11 @@ impl BasicBlocklist { pub fn root() -> AccountProcedureRoot { *BASIC_BLOCKLIST_TRANSFER_POLICY_ROOT } + + /// Returns the [`AccountComponentMetadata`] for this component. + pub fn component_metadata() -> AccountComponentMetadata { + package_metadata(Self::code()) + } } impl From for BasicBlocklist { @@ -93,15 +94,7 @@ impl From for BasicBlocklist { impl From for AccountComponent { fn from(blocklist: BasicBlocklist) -> Self { - let storage_schema = StorageSchema::new([BlocklistStorage::blocked_accounts_slot_schema()]) - .expect("storage schema should be valid"); - - let metadata = AccountComponentMetadata::new(BasicBlocklist::NAME) - .with_description( - "Basic blocklist transfer policy: predicate procedure plus the `blocked_accounts` \ - storage map it reads", - ) - .with_storage_schema(storage_schema); + let metadata = BasicBlocklist::component_metadata(); AccountComponent::new(BasicBlocklist::code().clone(), vec![blocklist.0.into_slot()], metadata) .expect( diff --git a/crates/miden-standards/src/account/policies/transfer/blocklist/manager.rs b/crates/miden-standards/src/account/policies/transfer/blocklist/manager.rs index 4df8c051bc..6cba6f3ee5 100644 --- a/crates/miden-standards/src/account/policies/transfer/blocklist/manager.rs +++ b/crates/miden-standards/src/account/policies/transfer/blocklist/manager.rs @@ -1,7 +1,7 @@ use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{AccountComponent, AccountProcedureRoot}; -use crate::account::account_component_code; +use crate::account::{account_component_code, package_metadata}; use crate::procedure_root; account_component_code!( @@ -81,10 +81,7 @@ impl BlocklistManager { /// Returns the [`AccountComponentMetadata`] for this component. pub fn component_metadata() -> AccountComponentMetadata { - AccountComponentMetadata::new(Self::NAME).with_description( - "Authority-gated blocklist admin: wraps `blocklist::block_account` / \ - `unblock_account` with the account-wide Authority component.", - ) + package_metadata(Self::code()) } } diff --git a/crates/miden-standards/src/account/policies/transfer/blocklist/mod.rs b/crates/miden-standards/src/account/policies/transfer/blocklist/mod.rs index 85df71c1bb..432904950b 100644 --- a/crates/miden-standards/src/account/policies/transfer/blocklist/mod.rs +++ b/crates/miden-standards/src/account/policies/transfer/blocklist/mod.rs @@ -1,7 +1,6 @@ use alloc::collections::BTreeSet; use miden_protocol::Word; -use miden_protocol::account::component::{SchemaType, StorageSlotSchema}; use miden_protocol::account::{AccountId, StorageMap, StorageMapKey, StorageSlot, StorageSlotName}; use miden_protocol::block::account_tree::AccountIdKey; use miden_protocol::utils::sync::LazyLock; @@ -69,18 +68,6 @@ impl BlocklistStorage { &BLOCKED_ACCOUNTS_SLOT_NAME } - /// Schema entry for the blocked-accounts map slot (documentation / tooling). - pub fn blocked_accounts_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - ( - Self::blocked_accounts_slot().clone(), - StorageSlotSchema::map( - "Per-account blocked flag; zero word is not blocked, [1,0,0,0] is blocked", - SchemaType::native_word(), - SchemaType::bool(), - ), - ) - } - /// Builds the initial `blocked_accounts` [`StorageMap`] from the captured set, marking each /// account ID's map entry with the `[1, 0, 0, 0]` blocked-flag word. pub fn build_storage_map(&self) -> StorageMap { diff --git a/crates/miden-standards/src/account/upgrade.rs b/crates/miden-standards/src/account/upgrade.rs index c06e7a0147..c2c78f5cba 100644 --- a/crates/miden-standards/src/account/upgrade.rs +++ b/crates/miden-standards/src/account/upgrade.rs @@ -1,7 +1,7 @@ use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata}; use miden_protocol::account::{AccountComponent, AccountComponentName, AccountProcedureRoot}; -use crate::account::account_component_code; +use crate::account::{account_component_code, package_metadata}; use crate::procedure_root; // UPGRADE MANAGER COMPONENT @@ -44,7 +44,7 @@ pub struct UpgradeManager; impl UpgradeManager { /// The name of the component. - const NAME: &'static str = "miden::standards::upgrade::manager"; + pub const NAME: &'static str = "miden::standards::upgrade::manager"; const UPGRADE_PROC_NAME: &'static str = "upgrade"; @@ -62,12 +62,16 @@ impl UpgradeManager { pub fn upgrade_root() -> AccountProcedureRoot { *UPGRADE_MANAGER_UPGRADE } + + /// Returns the [`AccountComponentMetadata`] for this component. + pub fn component_metadata() -> AccountComponentMetadata { + package_metadata(Self::code()) + } } impl From for AccountComponent { fn from(_: UpgradeManager) -> Self { - let metadata = AccountComponentMetadata::new(UpgradeManager::NAME) - .with_description("Code and storage upgrades for accounts."); + let metadata = UpgradeManager::component_metadata(); AccountComponent::new(UpgradeManager::code().clone(), vec![], metadata).expect( "upgrade manager component should satisfy the requirements of a valid account component", diff --git a/crates/miden-standards/src/account/wallets/mod.rs b/crates/miden-standards/src/account/wallets/mod.rs index 8244db5ccc..1a51772d3f 100644 --- a/crates/miden-standards/src/account/wallets/mod.rs +++ b/crates/miden-standards/src/account/wallets/mod.rs @@ -11,7 +11,6 @@ use miden_protocol::account::{ }; use miden_protocol::errors::AccountError; -use crate::account::account_component_code; use crate::account::auth::{ Approver, ApproverSet, @@ -22,6 +21,7 @@ use crate::account::auth::{ AuthSingleSig, GuardianConfig, }; +use crate::account::{account_component_code, package_metadata}; use crate::procedure_root; // BASIC WALLET @@ -119,8 +119,7 @@ impl BasicWallet { /// Returns the [`AccountComponentMetadata`] for this component. pub fn component_metadata() -> AccountComponentMetadata { - AccountComponentMetadata::new(Self::NAME) - .with_description("Basic wallet component for receiving and sending assets") + package_metadata(Self::code()) } } diff --git a/crates/miden-standards/tests/component_metadata.rs b/crates/miden-standards/tests/component_metadata.rs new file mode 100644 index 0000000000..cd68276375 --- /dev/null +++ b/crates/miden-standards/tests/component_metadata.rs @@ -0,0 +1,99 @@ +//! Tests for the account component metadata embedded in the standard component packages. + +use miden_protocol::account::component::AccountComponentMetadata; +use miden_standards::account::access::{ + Authority, + Ownable2Step, + Pausable, + PausableManager, + RoleBasedAccessControl, +}; +use miden_standards::account::auth::{ + AuthGuardedMultisig, + AuthMultisig, + AuthMultisigSmart, + AuthNetworkAccount, + AuthSingleSig, + NoAuth, +}; +use miden_standards::account::faucets::{FungibleFaucet, NonFungibleFaucet}; +use miden_standards::account::fees::{BasicConstantFeePolicy, ConstantFeeManager}; +use miden_standards::account::inspection::{AccountSchemaCommitment, CodeInspection}; +use miden_standards::account::note_creator::NoteCreator; +use miden_standards::account::policies::{ + AllowlistManager, + BasicAllowlist, + BasicBlocklist, + BlocklistManager, + BurnAllowAll, + BurnOwnerOnly, + BurnPolicy, + MinBurnAmount, + MintAllowAll, + MintOwnerOnly, + MintPolicy, + TokenPolicyManager, + TransferAllowAll, +}; +use miden_standards::account::upgrade::UpgradeManager; +use miden_standards::account::wallets::BasicWallet; + +/// Returns each standard component's `NAME` paired with the metadata read from its package. +fn components() -> Vec<(&'static str, AccountComponentMetadata)> { + vec![ + (Authority::NAME, Authority::AuthControlled.component_metadata()), + (Ownable2Step::NAME, Ownable2Step::component_metadata()), + (Pausable::NAME, Pausable::component_metadata()), + (PausableManager::NAME, PausableManager::component_metadata()), + (RoleBasedAccessControl::NAME, RoleBasedAccessControl::component_metadata()), + (AuthGuardedMultisig::NAME, AuthGuardedMultisig::component_metadata()), + (AuthMultisig::NAME, AuthMultisig::component_metadata()), + (AuthMultisigSmart::NAME, AuthMultisigSmart::component_metadata()), + (AuthNetworkAccount::NAME, AuthNetworkAccount::component_metadata()), + (NoAuth::NAME, NoAuth::component_metadata()), + (AuthSingleSig::NAME, AuthSingleSig::component_metadata()), + (FungibleFaucet::NAME, FungibleFaucet::component_metadata()), + (NonFungibleFaucet::NAME, NonFungibleFaucet::component_metadata()), + (BurnAllowAll::NAME, BurnAllowAll::component_metadata()), + (MinBurnAmount::NAME, MinBurnAmount::component_metadata()), + (BurnOwnerOnly::NAME, BurnOwnerOnly::component_metadata()), + (MintAllowAll::NAME, MintAllowAll::component_metadata()), + (MintOwnerOnly::NAME, MintOwnerOnly::component_metadata()), + ( + TokenPolicyManager::NAME, + TokenPolicyManager::builder() + .active_mint_policy(MintPolicy::allow_all()) + .active_burn_policy(BurnPolicy::allow_all()) + .build() + .component_metadata(), + ), + (TransferAllowAll::NAME, TransferAllowAll::component_metadata()), + (AllowlistManager::NAME, AllowlistManager::component_metadata()), + (BasicAllowlist::NAME, BasicAllowlist::component_metadata()), + (BasicBlocklist::NAME, BasicBlocklist::component_metadata()), + (BlocklistManager::NAME, BlocklistManager::component_metadata()), + (BasicConstantFeePolicy::NAME, BasicConstantFeePolicy::component_metadata()), + (ConstantFeeManager::NAME, ConstantFeeManager::component_metadata()), + (CodeInspection::NAME, CodeInspection::component_metadata()), + (AccountSchemaCommitment::NAME, AccountSchemaCommitment::component_metadata()), + (NoteCreator::NAME, NoteCreator::component_metadata()), + (UpgradeManager::NAME, UpgradeManager::component_metadata()), + (BasicWallet::NAME, BasicWallet::component_metadata()), + ] +} + +/// The name declared in a component's manifest must match its `NAME` constant. +#[test] +fn manifest_name_matches_component_name() { + for (name, metadata) in components() { + assert_eq!(metadata.name(), name); + } +} + +/// Every component must declare a non-empty description. +#[test] +fn every_component_is_described() { + for (name, metadata) in components() { + assert!(!metadata.description().is_empty(), "{name} declares no description"); + } +}