Skip to main content

miden_standards/account/policies/transfer/
basic_blocklist.rs

1use alloc::collections::BTreeSet;
2
3use miden_protocol::account::component::{
4    AccountComponentCode,
5    AccountComponentMetadata,
6    StorageSchema,
7};
8use miden_protocol::account::{AccountComponent, AccountId, AccountProcedureRoot};
9
10use crate::account::account_component_code;
11use crate::account::policies::transfer::blocklist::BlocklistStorage;
12use crate::procedure_root;
13
14// BASIC BLOCKLIST TRANSFER POLICY
15// ================================================================================================
16
17account_component_code!(
18    BASIC_BLOCKLIST_TRANSFER_POLICY_CODE,
19    "miden-standards-faucets-policies-transfer-basic-blocklist.masp"
20);
21
22// PROCEDURE ROOTS
23// ================================================================================================
24
25/// MASL library namespace used for procedure-root lookups. Distinct from [`BasicBlocklist::NAME`],
26/// which mirrors the standards-side MASM module path.
27const BASIC_BLOCKLIST_LIBRARY_PATH: &str =
28    "miden::standards::components::faucets::policies::transfer::basic_blocklist";
29
30procedure_root!(
31    BASIC_BLOCKLIST_TRANSFER_POLICY_ROOT,
32    BASIC_BLOCKLIST_LIBRARY_PATH,
33    BasicBlocklist::PROC_NAME,
34    BasicBlocklist::code()
35);
36
37/// The basic blocklist transfer policy account component.
38///
39/// Installs the per-faucet `blocked_accounts` storage map (defined by [`BlocklistStorage`])
40/// plus the `check_policy` predicate procedure. Pair with a
41/// [`crate::account::policies::TokenPolicyManager`] whose send / receive policy maps include
42/// [`BasicBlocklist::root`]. When active, transfers fail if the native account (asset
43/// recipient or note creator) is currently blocked on the issuing faucet.
44///
45/// The issuing faucet is exempt from its own blocklist.
46///
47/// The wrapped [`BlocklistStorage`] captures the initial blocklist contents (it can be empty
48/// for a faucet that starts unblocked). Use [`Default`] for an empty blocklist or
49/// [`Self::with_blocked_accounts`] to seed the storage map at component construction time.
50///
51/// Block / unblock administration is intentionally not part of this component. The
52/// `block_account` / `unblock_account` procedures live in the standards library and require an
53/// auth-wrapped admin component (see [`super::BlocklistManager`]) to be safely exposed
54/// on a production faucet.
55#[derive(Debug, Clone, Default)]
56pub struct BasicBlocklist(BlocklistStorage);
57
58impl BasicBlocklist {
59    /// The name of the component.
60    pub const NAME: &'static str = "miden::standards::faucets::policies::transfer::basic_blocklist";
61
62    pub(crate) const PROC_NAME: &str = "check_policy";
63
64    /// Creates a basic blocklist with the given initial blocked accounts.
65    pub fn with_blocked_accounts<I>(blocked_accounts: I) -> Self
66    where
67        I: IntoIterator<Item = AccountId>,
68    {
69        Self(BlocklistStorage::with_blocked_accounts(blocked_accounts))
70    }
71
72    /// Returns the initial blocked accounts captured in this component.
73    pub fn blocked_accounts(&self) -> &BTreeSet<AccountId> {
74        self.0.blocked_accounts()
75    }
76
77    /// Returns the [`AccountComponentCode`] of this component.
78    pub fn code() -> &'static AccountComponentCode {
79        &BASIC_BLOCKLIST_TRANSFER_POLICY_CODE
80    }
81
82    /// Returns the MAST root of the basic blocklist transfer policy procedure.
83    pub fn root() -> AccountProcedureRoot {
84        *BASIC_BLOCKLIST_TRANSFER_POLICY_ROOT
85    }
86}
87
88impl From<BlocklistStorage> for BasicBlocklist {
89    fn from(storage: BlocklistStorage) -> Self {
90        Self(storage)
91    }
92}
93
94impl From<BasicBlocklist> for AccountComponent {
95    fn from(blocklist: BasicBlocklist) -> Self {
96        let storage_schema = StorageSchema::new([BlocklistStorage::blocked_accounts_slot_schema()])
97            .expect("storage schema should be valid");
98
99        let metadata = AccountComponentMetadata::new(BasicBlocklist::NAME)
100            .with_description(
101                "Basic blocklist transfer policy: predicate procedure plus the `blocked_accounts` \
102                 storage map it reads",
103            )
104            .with_storage_schema(storage_schema);
105
106        AccountComponent::new(BasicBlocklist::code().clone(), vec![blocklist.0.into_slot()], metadata)
107            .expect(
108                "basic blocklist transfer policy component should satisfy the requirements of a valid account component",
109            )
110    }
111}