miden_standards/account/access/pausable/
mod.rs1use miden_protocol::account::component::{
2 AccountComponentCode,
3 AccountComponentMetadata,
4 StorageSchema,
5 StorageSlotSchema,
6};
7use miden_protocol::account::{
8 AccountComponent,
9 AccountProcedureRoot,
10 StorageSlot,
11 StorageSlotName,
12};
13use miden_protocol::utils::sync::LazyLock;
14use miden_protocol::{Felt, Word};
15
16use crate::account::account_component_code;
17use crate::procedure_root;
18
19mod manager;
20pub use manager::PausableManager;
21
22account_component_code!(PAUSABLE_CODE, "miden-standards-access-pausable.masp");
26
27static IS_PAUSED_SLOT_NAME: LazyLock<StorageSlotName> = LazyLock::new(|| {
28 StorageSlotName::new("miden::standards::access::pausable::is_paused")
29 .expect("storage slot name should be valid")
30});
31
32const PAUSABLE_LIBRARY_PATH: &str = "miden::standards::components::access::pausable";
38
39procedure_root!(
40 PAUSABLE_IS_PAUSED_ROOT,
41 PAUSABLE_LIBRARY_PATH,
42 Pausable::IS_PAUSED_PROC_NAME,
43 Pausable::code()
44);
45
46#[derive(Debug, Clone, Copy, Default)]
60pub struct PausableStorage {
61 state: bool,
62}
63
64impl PausableStorage {
65 pub const fn new(state: bool) -> Self {
67 Self { state }
68 }
69
70 pub const fn paused() -> Self {
72 Self::new(true)
73 }
74
75 pub const fn unpaused() -> Self {
77 Self::new(false)
78 }
79
80 pub fn state(&self) -> bool {
82 self.state
83 }
84
85 pub fn is_paused_slot() -> &'static StorageSlotName {
87 &IS_PAUSED_SLOT_NAME
88 }
89
90 pub fn is_paused_slot_schema() -> (StorageSlotName, StorageSlotSchema) {
92 (
93 Self::is_paused_slot().clone(),
94 StorageSlotSchema::value(
95 "Pause flag word; zero is unpaused, canonical paused encoding is [1,0,0,0]",
96 [Felt::ZERO; 4],
97 ),
98 )
99 }
100
101 pub fn to_word(&self) -> Word {
103 if self.state {
104 Word::from([1u32, 0, 0, 0])
105 } else {
106 Word::default()
107 }
108 }
109
110 pub fn into_slot(self) -> StorageSlot {
113 StorageSlot::with_value(Self::is_paused_slot().clone(), self.to_word())
114 }
115}
116
117#[derive(Debug, Clone, Copy, Default)]
126pub struct Pausable(PausableStorage);
127
128impl Pausable {
129 pub const NAME: &'static str = "miden::standards::access::pausable";
131
132 const IS_PAUSED_PROC_NAME: &'static str = "is_paused";
133
134 pub const fn new(state: bool) -> Self {
136 Self(PausableStorage::new(state))
137 }
138
139 pub const fn paused() -> Self {
141 Self::new(true)
142 }
143
144 pub const fn unpaused() -> Self {
146 Self::new(false)
147 }
148
149 pub fn state(&self) -> bool {
151 self.0.state()
152 }
153
154 pub fn storage(&self) -> &PausableStorage {
156 &self.0
157 }
158
159 pub fn code() -> &'static AccountComponentCode {
161 &PAUSABLE_CODE
162 }
163
164 pub fn is_paused_root() -> AccountProcedureRoot {
166 *PAUSABLE_IS_PAUSED_ROOT
167 }
168}
169
170impl From<Pausable> for AccountComponent {
171 fn from(pausable: Pausable) -> Self {
172 let storage_schema = StorageSchema::new([PausableStorage::is_paused_slot_schema()])
173 .expect("storage schema should be valid");
174
175 let metadata = AccountComponentMetadata::new(Pausable::NAME)
176 .with_description(
177 "Pausable: installs the `is_paused` storage slot and exposes \
178 `is_paused` view.",
179 )
180 .with_storage_schema(storage_schema);
181
182 AccountComponent::new(Pausable::code().clone(), vec![pausable.0.into_slot()], metadata)
183 .expect(
184 "pausable component should satisfy the requirements of a valid account component",
185 )
186 }
187}