use miden_protocol::account::component::{
AccountComponentCode,
AccountComponentMetadata,
StorageSchema,
StorageSlotSchema,
};
use miden_protocol::account::{
AccountComponent,
AccountProcedureRoot,
StorageSlot,
StorageSlotName,
};
use miden_protocol::utils::sync::LazyLock;
use miden_protocol::{Felt, Word};
use crate::account::account_component_code;
use crate::procedure_root;
mod manager;
pub use manager::PausableManager;
account_component_code!(PAUSABLE_CODE, "access/pausable/mod.masl");
static IS_PAUSED_SLOT_NAME: LazyLock<StorageSlotName> = LazyLock::new(|| {
StorageSlotName::new("miden::standards::access::pausable::is_paused")
.expect("storage slot name should be valid")
});
procedure_root!(
PAUSABLE_IS_PAUSED_ROOT,
Pausable::NAME,
Pausable::IS_PAUSED_PROC_NAME,
Pausable::code()
);
#[derive(Debug, Clone, Copy, Default)]
pub struct PausableStorage {
state: bool,
}
impl PausableStorage {
pub const fn new(state: bool) -> Self {
Self { state }
}
pub const fn paused() -> Self {
Self::new(true)
}
pub const fn unpaused() -> Self {
Self::new(false)
}
pub fn state(&self) -> bool {
self.state
}
pub fn is_paused_slot() -> &'static StorageSlotName {
&IS_PAUSED_SLOT_NAME
}
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],
),
)
}
pub fn to_word(&self) -> Word {
if self.state {
Word::from([1u32, 0, 0, 0])
} else {
Word::default()
}
}
pub fn into_slot(self) -> StorageSlot {
StorageSlot::with_value(Self::is_paused_slot().clone(), self.to_word())
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct Pausable(PausableStorage);
impl Pausable {
pub const NAME: &'static str = "miden::standards::components::access::pausable";
pub const IS_PAUSED_PROC_NAME: &'static str = "is_paused";
pub const fn new(state: bool) -> Self {
Self(PausableStorage::new(state))
}
pub const fn paused() -> Self {
Self::new(true)
}
pub const fn unpaused() -> Self {
Self::new(false)
}
pub fn state(&self) -> bool {
self.0.state()
}
pub fn storage(&self) -> &PausableStorage {
&self.0
}
pub fn code() -> &'static AccountComponentCode {
&PAUSABLE_CODE
}
pub fn is_paused_root() -> AccountProcedureRoot {
*PAUSABLE_IS_PAUSED_ROOT
}
}
impl From<Pausable> 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);
AccountComponent::new(Pausable::code().clone(), vec![pausable.0.into_slot()], metadata)
.expect(
"pausable component should satisfy the requirements of a valid account component",
)
}
}