miden-client-web 0.15.5

Web Client library that facilitates interaction with the Miden network
use js_export_macro::js_export;
use miden_client::crypto::RandomCoin;
use miden_client::note::{
    NoteRecipient as NativeNoteRecipient,
    NoteScript as NativeNoteScript,
    NoteStorage as NativeNoteStorage,
};
use miden_client::{Felt as NativeFelt, Word as NativeWord};
use rand::rngs::StdRng;
use rand::{Rng, SeedableRng};

use super::note_script::NoteScript;
use super::note_storage::NoteStorage;
use super::word::Word;
use crate::models::miden_arrays::NoteRecipientArray as RecipientArray;

/// Value that describes under which condition a note can be consumed.
///
/// The recipient is not an account address, instead it is a value that describes when a note can be
/// consumed. Because not all notes have predetermined consumer addresses, e.g. swap notes can be
/// consumed by anyone, the recipient is defined as the code and its storage, that when successfully
/// executed results in the note's consumption.
///
/// Recipient is computed as a nested hash of the serial number, the script root, and the storage
/// commitment, ensuring the recipient digest binds all three pieces of data together.
#[derive(Clone)]
#[js_export]
pub struct NoteRecipient(NativeNoteRecipient);

#[js_export]
impl NoteRecipient {
    /// Creates a note recipient from its serial number, script, and storage.
    #[js_export(constructor)]
    pub fn new(
        serial_num: &Word,
        note_script: &NoteScript,
        storage: &NoteStorage,
    ) -> NoteRecipient {
        let native_serial_num: NativeWord = serial_num.into();
        let native_note_script: NativeNoteScript = note_script.into();
        let native_note_storage: NativeNoteStorage = storage.into();
        let native_note_recipient =
            NativeNoteRecipient::new(native_serial_num, native_note_script, native_note_storage);

        NoteRecipient(native_note_recipient)
    }

    /// Creates a recipient from a script and storage, generating a fresh random
    /// serial number (the secret that prevents double-spends).
    #[js_export(js_name = "fromScript")]
    pub fn from_script(note_script: &NoteScript, storage: &NoteStorage) -> NoteRecipient {
        let mut rng = StdRng::from_os_rng();
        let coin_seed: [u64; 4] = rng.random();
        // See `Note::create_p2id_note` for why `new_unchecked` is fine here.
        let mut rng = RandomCoin::new(coin_seed.map(NativeFelt::new_unchecked).into());
        let serial_num: NativeWord = [rng.draw(), rng.draw(), rng.draw(), rng.draw()].into();

        let native = NativeNoteRecipient::new(serial_num, note_script.into(), storage.into());
        NoteRecipient(native)
    }

    /// Returns the digest of the recipient data (used in the note commitment).
    pub fn digest(&self) -> Word {
        self.0.digest().into()
    }

    /// Returns the serial number that prevents double spends.
    #[js_export(js_name = "serialNum")]
    pub fn serial_num(&self) -> Word {
        self.0.serial_num().into()
    }

    /// Returns the script that controls consumption.
    pub fn script(&self) -> NoteScript {
        self.0.script().into()
    }

    /// Returns the storage provided to the script.
    pub fn storage(&self) -> NoteStorage {
        self.0.storage().into()
    }
}

// CONVERSIONS
// ================================================================================================

impl From<NativeNoteRecipient> for NoteRecipient {
    fn from(native_note_recipient: NativeNoteRecipient) -> Self {
        NoteRecipient(native_note_recipient)
    }
}

impl From<&NativeNoteRecipient> for NoteRecipient {
    fn from(native_note_recipient: &NativeNoteRecipient) -> Self {
        NoteRecipient(native_note_recipient.clone())
    }
}

impl From<NoteRecipient> for NativeNoteRecipient {
    fn from(note_recipient: NoteRecipient) -> Self {
        note_recipient.0
    }
}

impl From<&NoteRecipient> for NativeNoteRecipient {
    fn from(note_recipient: &NoteRecipient) -> Self {
        note_recipient.0.clone()
    }
}

impl From<&RecipientArray> for Vec<NativeNoteRecipient> {
    fn from(recipient_array: &RecipientArray) -> Self {
        recipient_array.iter().map(NativeNoteRecipient::from).collect()
    }
}

impl_napi_from_value!(NoteRecipient);