miden-agglayer 0.16.0

Agglayer components for the Miden protocol
Documentation
//! DEREGISTER_AGG_FAUCET note creation utilities.
//!
//! This module provides helpers for creating DEREGISTER_AGG_FAUCET notes,
//! which are used to deregister faucets from the bridge's faucet registry.

extern crate alloc;

use alloc::string::ToString;
use alloc::vec;
use alloc::vec::Vec;

use miden_core::Felt;
use miden_protocol::account::AccountId;
use miden_protocol::crypto::rand::FeltRng;
use miden_protocol::errors::NoteError;
use miden_protocol::note::{
    Note,
    NoteAssets,
    NoteAttachment,
    NoteAttachments,
    NoteRecipient,
    NoteScript,
    NoteScriptRoot,
    NoteStorage,
    NoteType,
    PartialNoteMetadata,
};
use miden_standards::note::costs::NoteConsumptionCost;
use miden_standards::note::{NetworkAccountTarget, NoteExecutionHint};
use miden_utils_sync::LazyLock;

use crate::costs::DEREGISTER_AGG_FAUCET_CONSUMPTION_CYCLES;
use crate::note_script;

// NOTE SCRIPT
// ================================================================================================

/// Path to the DEREGISTER_AGG_FAUCET note script procedure in the agglayer package.
const DEREGISTER_AGG_FAUCET_SCRIPT_PATH: &str = "::agglayer::notes::deregister_agg_faucet::main";

// Initialize the DEREGISTER_AGG_FAUCET note script only once
static DEREGISTER_AGG_FAUCET_SCRIPT: LazyLock<NoteScript> =
    LazyLock::new(|| note_script(DEREGISTER_AGG_FAUCET_SCRIPT_PATH));

// DEREGISTER_AGG_FAUCET NOTE
// ================================================================================================

/// DEREGISTER_AGG_FAUCET note.
///
/// Deregisters a faucet from the bridge's faucet registry, token registry, and faucet metadata.
/// Carries only the faucet account ID; the bridge recomputes the token-registry key from its own
/// stored metadata rather than trusting note-supplied values. The note is always public.
///
/// Any in-flight B2AGG / CLAIM notes targeting the faucet fail once this note is consumed, since
/// `assert_faucet_registered` / `lookup_faucet_by_token_address` no longer find it.
pub struct DeregisterAggFaucetNote;

impl DeregisterAggFaucetNote {
    // CONSTANTS
    // --------------------------------------------------------------------------------------------

    /// Expected number of storage items for a DEREGISTER_AGG_FAUCET note.
    /// Layout: [faucet_id_suffix, faucet_id_prefix]
    pub const NUM_STORAGE_ITEMS: usize = 2;

    // PUBLIC ACCESSORS
    // --------------------------------------------------------------------------------------------

    /// Returns the DEREGISTER_AGG_FAUCET note script.
    pub fn script() -> NoteScript {
        DEREGISTER_AGG_FAUCET_SCRIPT.clone()
    }

    /// Returns the DEREGISTER_AGG_FAUCET note script root.
    pub fn script_root() -> NoteScriptRoot {
        DEREGISTER_AGG_FAUCET_SCRIPT.root()
    }

    // BUILDERS
    // --------------------------------------------------------------------------------------------

    /// Creates a DEREGISTER_AGG_FAUCET note to deregister a faucet from the bridge's registry.
    ///
    /// The note storage contains 2 felts:
    /// - `faucet_id_suffix`: The suffix of the faucet account ID
    /// - `faucet_id_prefix`: The prefix of the faucet account ID
    ///
    /// # Parameters
    /// - `faucet_account_id`: The account ID of the faucet to deregister
    /// - `sender_account_id`: The account ID of the note creator (must hold the `FAUCET_MNGR` role)
    /// - `target_account_id`: The bridge account ID that will consume this note
    /// - `rng`: Random number generator for creating the note serial number
    ///
    /// # Errors
    /// Returns an error if note creation fails.
    pub fn create<R: FeltRng>(
        faucet_account_id: AccountId,
        sender_account_id: AccountId,
        target_account_id: AccountId,
        rng: &mut R,
    ) -> Result<Note, NoteError> {
        // Create note storage with 2 felts: [faucet_id_suffix, faucet_id_prefix]
        let storage_values: Vec<Felt> =
            vec![faucet_account_id.suffix(), faucet_account_id.prefix().as_felt()];

        let note_storage = NoteStorage::new(storage_values)?;

        // Generate a serial number for the note
        let serial_num = rng.draw_word();

        let recipient = NoteRecipient::new(serial_num, Self::script(), note_storage);

        let attachment = NetworkAccountTarget::new(target_account_id, NoteExecutionHint::Always)
            .map_err(|e| NoteError::other(e.to_string()))?;
        let attachments = NoteAttachments::from(NoteAttachment::from(attachment));
        let metadata = PartialNoteMetadata::new(sender_account_id, NoteType::Public);

        // DEREGISTER_AGG_FAUCET notes don't carry assets
        let assets = NoteAssets::new(vec![])?;

        Ok(Note::with_attachments(assets, metadata, recipient, attachments))
    }
}

// NOTE CONSUMPTION COST
// ================================================================================================

impl NoteConsumptionCost for DeregisterAggFaucetNote {
    fn consumption_cycles() -> u32 {
        DEREGISTER_AGG_FAUCET_CONSUMPTION_CYCLES
    }
}