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;
mod owner_controlled;
pub use owner_controlled::AllowlistOwnerControlled;
static ALLOWED_ACCOUNTS_SLOT_NAME: LazyLock<StorageSlotName> = LazyLock::new(|| {
StorageSlotName::new(
"miden::standards::faucets::policies::transfer::allowlist::allowed_accounts",
)
.expect("storage slot name should be valid")
});
#[derive(Debug, Clone, Default)]
pub struct AllowlistStorage {
allowed_accounts: BTreeSet<AccountId>,
}
impl AllowlistStorage {
pub fn new() -> Self {
Self::default()
}
pub fn with_allowed_accounts(allowed_accounts: impl IntoIterator<Item = AccountId>) -> Self {
Self {
allowed_accounts: allowed_accounts.into_iter().collect(),
}
}
pub fn allowed_accounts(&self) -> &BTreeSet<AccountId> {
&self.allowed_accounts
}
pub fn allowed_accounts_slot() -> &'static StorageSlotName {
&ALLOWED_ACCOUNTS_SLOT_NAME
}
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(),
),
)
}
pub fn build_storage_map(&self) -> StorageMap {
let allowed_word = Word::from([1u32, 0, 0, 0]);
StorageMap::with_entries(
self.allowed_accounts
.iter()
.map(|id| (StorageMapKey::new(AccountIdKey::from(*id).as_word()), allowed_word)),
)
.expect("initial allowed accounts should have unique IDs")
}
pub fn into_slot(self) -> StorageSlot {
StorageSlot::with_map(ALLOWED_ACCOUNTS_SLOT_NAME.clone(), self.build_storage_map())
}
}