From 68188937ff14520c8d7024befe2e0114eb6129c2 Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Wed, 7 Jan 2026 12:15:44 -0300 Subject: [PATCH 1/2] feat(WebClient): RPC methods and JS bindings for native types --- CHANGELOG.md | 1 + Cargo.lock | 1 + crates/web-client/Cargo.toml | 5 +- crates/web-client/src/models/account_file.rs | 19 +++ crates/web-client/src/models/code_builder.rs | 5 +- .../web-client/src/models/committed_note.rs | 52 ++++++ .../web-client/src/models/fetched_account.rs | 85 +++++++++ crates/web-client/src/models/mod.rs | 6 + crates/web-client/src/models/note.rs | 11 +- crates/web-client/src/models/note_details.rs | 11 ++ crates/web-client/src/models/note_file.rs | 66 +++++++ .../web-client/src/models/note_sync_info.rs | 45 +++++ crates/web-client/src/models/note_tag.rs | 15 ++ .../src/models/output_note_record.rs | 93 ++++++++++ .../src/models/output_note_state.rs | 39 +++++ .../src/models/sparse_merkle_path.rs | 45 +++++ .../src/models/transaction_record.rs | 12 ++ crates/web-client/src/notes.rs | 20 +-- crates/web-client/src/rpc_client/mod.rs | 85 ++++++++- .../web-client/test/new_transactions.test.ts | 1 - crates/web-client/test/notes.test.ts | 50 ++++++ crates/web-client/yarn.lock | 77 ++++++--- docs/typedoc/web-client/README.md | 6 + .../typedoc/web-client/classes/AccountFile.md | 36 ++++ .../web-client/classes/CommittedNote.md | 77 +++++++++ .../web-client/classes/FetchedAccount.md | 113 ++++++++++++ docs/typedoc/web-client/classes/Note.md | 12 ++ .../typedoc/web-client/classes/NoteDetails.md | 12 ++ docs/typedoc/web-client/classes/NoteFile.md | 84 +++++++++ .../web-client/classes/NoteSyncInfo.md | 77 +++++++++ docs/typedoc/web-client/classes/NoteTag.md | 36 ++++ .../web-client/classes/OutputNoteRecord.md | 161 ++++++++++++++++++ docs/typedoc/web-client/classes/RpcClient.md | 84 +++++++++ .../web-client/classes/SparseMerklePath.md | 79 +++++++++ .../web-client/classes/TransactionRecord.md | 24 +++ docs/typedoc/web-client/classes/WebClient.md | 8 +- .../enumerations/OutputNoteState.md | 37 ++++ 37 files changed, 1540 insertions(+), 50 deletions(-) create mode 100644 crates/web-client/src/models/committed_note.rs create mode 100644 crates/web-client/src/models/fetched_account.rs create mode 100644 crates/web-client/src/models/note_sync_info.rs create mode 100644 crates/web-client/src/models/output_note_record.rs create mode 100644 crates/web-client/src/models/output_note_state.rs create mode 100644 crates/web-client/src/models/sparse_merkle_path.rs create mode 100644 docs/typedoc/web-client/classes/CommittedNote.md create mode 100644 docs/typedoc/web-client/classes/FetchedAccount.md create mode 100644 docs/typedoc/web-client/classes/NoteSyncInfo.md create mode 100644 docs/typedoc/web-client/classes/OutputNoteRecord.md create mode 100644 docs/typedoc/web-client/classes/SparseMerklePath.md create mode 100644 docs/typedoc/web-client/enumerations/OutputNoteState.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a35c0930..135f24209 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ * Incremented the limits for various RPC calls to accommodate larger data sets ([#1621](https://github.com/0xMiden/miden-client/pull/1621)). * [BREAKING] Introduced named storage slots, changed `FilesystemKeystore` to not be generic over RNG ([#1626](https://github.com/0xMiden/miden-client/pull/1626)). * Added `submit_new_transaction_with_prover` to the Rust client and `submitNewTransactionWithProver` to the WebClient([#1622](https://github.com/0xMiden/miden-client/pull/1622)). +* Added WebClient bindings and RPC helpers for additional account, note, and validation workflows ([#1638](https://github.com/0xMiden/miden-client/pull/1638)). * [BREAKING] Modified JS binding for `AccountComponent::compile` which now takes an `AccountComponentCode` built with the newly added binding `CodeBuilder::compile_account_component_code` ([#1627](https://github.com/0xMiden/miden-client/pull/1627)). ## 0.12.5 (2025-12-01) diff --git a/Cargo.lock b/Cargo.lock index 2b05ef853..f53240e53 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2601,6 +2601,7 @@ dependencies = [ "js-sys", "miden-client", "miden-idxdb-store", + "miden-protocol", "rand 0.9.2", "serde-wasm-bindgen", "thiserror 2.0.17", diff --git a/crates/web-client/Cargo.toml b/crates/web-client/Cargo.toml index 960b42d88..bd0ac6482 100644 --- a/crates/web-client/Cargo.toml +++ b/crates/web-client/Cargo.toml @@ -23,8 +23,9 @@ testing = ["miden-client/testing"] [dependencies] # Workspace dependencies -idxdb-store = { package = "miden-idxdb-store", path = "../idxdb-store" } -miden-client = { default-features = false, features = ["testing", "tonic"], path = "../rust-client" } +idxdb-store = { package = "miden-idxdb-store", path = "../idxdb-store" } +miden-client = { default-features = false, features = ["testing", "tonic"], path = "../rust-client" } +miden-protocol = { workspace = true } # External dependencies console_error_panic_hook = { version = "0.1.7" } diff --git a/crates/web-client/src/models/account_file.rs b/crates/web-client/src/models/account_file.rs index 64ce30123..9154eedfe 100644 --- a/crates/web-client/src/models/account_file.rs +++ b/crates/web-client/src/models/account_file.rs @@ -2,6 +2,8 @@ use miden_client::account::AccountFile as NativeAccountFile; use wasm_bindgen::prelude::*; use wasm_bindgen_futures::js_sys::Uint8Array; +use crate::models::account::Account; +use crate::models::account_id::AccountId; use crate::utils::{deserialize_from_uint8array, serialize_to_uint8array}; #[derive(Debug, Clone)] @@ -10,6 +12,23 @@ pub struct AccountFile(NativeAccountFile); #[wasm_bindgen] impl AccountFile { + /// Returns the account ID. + #[wasm_bindgen(js_name = "accountId")] + pub fn account_id(&self) -> AccountId { + self.0.account.id().into() + } + + /// Returns the account data. + pub fn account(&self) -> Account { + self.0.account.clone().into() + } + + /// Returns the number of auth secret keys included. + #[wasm_bindgen(js_name = "authSecretKeyCount")] + pub fn auth_secret_key_count(&self) -> usize { + self.0.auth_secret_keys.len() + } + /// Serializes the `AccountFile` into a byte array pub fn serialize(&self) -> Uint8Array { serialize_to_uint8array(&self.0) diff --git a/crates/web-client/src/models/code_builder.rs b/crates/web-client/src/models/code_builder.rs index e3d3a8710..c1530dd2e 100644 --- a/crates/web-client/src/models/code_builder.rs +++ b/crates/web-client/src/models/code_builder.rs @@ -24,10 +24,7 @@ use crate::models::transaction_script::TransactionScript; #[derive(Clone)] #[wasm_bindgen(inspectable)] pub struct CodeBuilder { - // We need both a builder and an assembler since we want the capability of linking libraries, - // and compiling scripts. This can be done by the NativeCodeBuilder alone, but we still - // need an assembler to compile an AccountComponent. After miden-base issue #1756 is complete - // we will be able to remove the Assembler and only use the NativeCodeBuilder. + // Keep the builder and derive an assembler when compiling account component code. builder: NativeCodeBuilder, } diff --git a/crates/web-client/src/models/committed_note.rs b/crates/web-client/src/models/committed_note.rs new file mode 100644 index 000000000..054b506ee --- /dev/null +++ b/crates/web-client/src/models/committed_note.rs @@ -0,0 +1,52 @@ +use miden_client::rpc::domain::note::CommittedNote as NativeCommittedNote; +use wasm_bindgen::prelude::*; + +use super::note_id::NoteId; +use super::note_metadata::NoteMetadata; +use super::sparse_merkle_path::SparseMerklePath; + +/// Represents a note committed on chain, as returned by `syncNotes`. +#[derive(Clone)] +#[wasm_bindgen] +pub struct CommittedNote(NativeCommittedNote); + +#[wasm_bindgen] +impl CommittedNote { + /// Returns the note ID. + #[wasm_bindgen(js_name = "noteId")] + pub fn note_id(&self) -> NoteId { + (*self.0.note_id()).into() + } + + /// Returns the note index in the block's note tree. + #[wasm_bindgen(js_name = "noteIndex")] + pub fn note_index(&self) -> u16 { + self.0.note_index() + } + + /// Returns the inclusion path for the note. + #[wasm_bindgen(js_name = "inclusionPath")] + pub fn inclusion_path(&self) -> SparseMerklePath { + self.0.inclusion_path().into() + } + + /// Returns the note metadata. + pub fn metadata(&self) -> NoteMetadata { + self.0.metadata().into() + } +} + +// CONVERSIONS +// ================================================================================================ + +impl From for CommittedNote { + fn from(native_note: NativeCommittedNote) -> Self { + CommittedNote(native_note) + } +} + +impl From<&NativeCommittedNote> for CommittedNote { + fn from(native_note: &NativeCommittedNote) -> Self { + CommittedNote(native_note.clone()) + } +} diff --git a/crates/web-client/src/models/fetched_account.rs b/crates/web-client/src/models/fetched_account.rs new file mode 100644 index 000000000..423beabe0 --- /dev/null +++ b/crates/web-client/src/models/fetched_account.rs @@ -0,0 +1,85 @@ +use miden_client::rpc::domain::account::FetchedAccount as NativeFetchedAccount; +use wasm_bindgen::prelude::*; + +use super::account::Account; +use super::account_id::AccountId; +use super::word::Word; + +/// Account details returned by the node. +#[derive(Clone)] +#[wasm_bindgen] +pub struct FetchedAccount { + account_id: AccountId, + commitment: Word, + last_block_num: u32, + account: Option, +} + +#[wasm_bindgen] +impl FetchedAccount { + /// Returns the account ID. + #[wasm_bindgen(js_name = "accountId")] + pub fn account_id(&self) -> AccountId { + self.account_id + } + + /// Returns the account commitment reported by the node. + pub fn commitment(&self) -> Word { + self.commitment.clone() + } + + /// Returns the last block height where the account was updated. + #[wasm_bindgen(js_name = "lastBlockNum")] + pub fn last_block_num(&self) -> u32 { + self.last_block_num + } + + /// Returns the full account data when the account is public. + pub fn account(&self) -> Option { + self.account.clone() + } + + /// Returns true when the account is public. + #[wasm_bindgen(js_name = "isPublic")] + pub fn is_public(&self) -> bool { + self.account_id.is_public() + } + + /// Returns true when the account is private. + #[wasm_bindgen(js_name = "isPrivate")] + pub fn is_private(&self) -> bool { + self.account_id.is_private() + } + + /// Returns true when the account is a network account. + #[wasm_bindgen(js_name = "isNetwork")] + pub fn is_network(&self) -> bool { + self.account_id.is_network() + } +} + +// CONVERSIONS +// ================================================================================================ + +impl From for FetchedAccount { + fn from(native_account: NativeFetchedAccount) -> Self { + match native_account { + NativeFetchedAccount::Private(account_id, summary) => FetchedAccount { + account_id: account_id.into(), + commitment: summary.commitment.into(), + last_block_num: summary.last_block_num, + account: None, + }, + NativeFetchedAccount::Public(account, summary) => { + let account_id = account.id().into(); + let account = (*account).into(); + FetchedAccount { + account_id, + commitment: summary.commitment.into(), + last_block_num: summary.last_block_num, + account: Some(account), + } + }, + } + } +} diff --git a/crates/web-client/src/models/mod.rs b/crates/web-client/src/models/mod.rs index d9a4eb77f..f12d32c5e 100644 --- a/crates/web-client/src/models/mod.rs +++ b/crates/web-client/src/models/mod.rs @@ -50,10 +50,12 @@ pub mod auth_secret_key; pub mod basic_fungible_faucet_component; pub mod block_header; pub mod code_builder; +pub mod committed_note; pub mod consumable_note_record; pub mod endpoint; pub mod executed_transaction; pub mod felt; +pub mod fetched_account; pub mod foreign_account; pub mod fungible_asset; pub mod input_note; @@ -77,9 +79,12 @@ pub mod note_location; pub mod note_metadata; pub mod note_recipient; pub mod note_script; +pub mod note_sync_info; pub mod note_tag; pub mod note_type; pub mod output_note; +pub mod output_note_record; +pub mod output_note_state; pub mod output_notes; pub mod package; pub mod partial_note; @@ -90,6 +95,7 @@ pub mod public_key; pub mod rpo256; pub mod signature; pub mod signing_inputs; +pub mod sparse_merkle_path; pub mod storage_map; pub mod storage_slot; pub mod sync_summary; diff --git a/crates/web-client/src/models/note.rs b/crates/web-client/src/models/note.rs index 3a2040582..7d18b5fba 100644 --- a/crates/web-client/src/models/note.rs +++ b/crates/web-client/src/models/note.rs @@ -1,4 +1,3 @@ -use miden_client::Felt as NativeFelt; use miden_client::asset::Asset as NativeAsset; use miden_client::block::BlockNumber as NativeBlockNumber; use miden_client::crypto::RpoRandomCoin; @@ -8,6 +7,7 @@ use miden_client::note::{ create_p2id_note, create_p2ide_note, }; +use miden_client::{Felt as NativeFelt, Word as NativeWord}; use rand::rngs::StdRng; use rand::{Rng, SeedableRng}; use wasm_bindgen::prelude::*; @@ -86,6 +86,15 @@ impl Note { self.0.script().clone().into() } + /// Returns the note nullifier as a word. + pub fn nullifier(&self) -> Word { + let nullifier = self.0.nullifier(); + let elements: [miden_client::Felt; 4] = + nullifier.as_elements().try_into().expect("nullifier has 4 elements"); + let native_word: NativeWord = NativeWord::from(&elements); + native_word.into() + } + /// Builds a standard P2ID note that targets the specified account. #[wasm_bindgen(js_name = "createP2IDNote")] pub fn create_p2id_note( diff --git a/crates/web-client/src/models/note_details.rs b/crates/web-client/src/models/note_details.rs index ec1fde38f..5e9cd82da 100644 --- a/crates/web-client/src/models/note_details.rs +++ b/crates/web-client/src/models/note_details.rs @@ -1,9 +1,11 @@ +use miden_client::Word as NativeWord; use miden_client::note::NoteDetails as NativeNoteDetails; use wasm_bindgen::prelude::*; use super::note_assets::NoteAssets; use super::note_id::NoteId; use super::note_recipient::NoteRecipient; +use super::word::Word; /// Details of a note consisting of assets, script, inputs, and a serial number. /// @@ -34,6 +36,15 @@ impl NoteDetails { pub fn recipient(&self) -> NoteRecipient { self.0.recipient().into() } + + /// Returns the note nullifier as a word. + pub fn nullifier(&self) -> Word { + let nullifier = self.0.nullifier(); + let elements: [miden_client::Felt; 4] = + nullifier.as_elements().try_into().expect("nullifier has 4 elements"); + let native_word: NativeWord = NativeWord::from(&elements); + native_word.into() + } } impl From for NativeNoteDetails { diff --git a/crates/web-client/src/models/note_file.rs b/crates/web-client/src/models/note_file.rs index 9b947c26e..cbd303712 100644 --- a/crates/web-client/src/models/note_file.rs +++ b/crates/web-client/src/models/note_file.rs @@ -4,10 +4,13 @@ use miden_client::{Deserializable, Serializable}; use wasm_bindgen::prelude::*; use super::input_note::InputNote; +use super::note::Note; use super::output_note::OutputNote; use crate::js_error_with_context; use crate::models::note_details::NoteDetails; use crate::models::note_id::NoteId; +use crate::models::note_inclusion_proof::NoteInclusionProof; +use crate::models::note_tag::NoteTag; /// A serialized representation of a note. #[wasm_bindgen(inspectable)] @@ -27,6 +30,69 @@ impl NoteFile { } } + /// Returns the note ID for any `NoteFile` variant. + #[wasm_bindgen(js_name = "noteId")] + pub fn note_id(&self) -> NoteId { + match &self.inner { + NativeNoteFile::NoteId(note_id) => (*note_id).into(), + NativeNoteFile::NoteDetails { details, .. } => details.id().into(), + NativeNoteFile::NoteWithProof(note, _) => note.id().into(), + } + } + + /// Returns the note details if present. + #[wasm_bindgen(js_name = "noteDetails")] + pub fn note_details(&self) -> Option { + match &self.inner { + NativeNoteFile::NoteDetails { details, .. } => Some(details.into()), + _ => None, + } + } + + /// Returns the full note when the file includes it. + pub fn note(&self) -> Option { + match &self.inner { + NativeNoteFile::NoteWithProof(note, _) => Some(note.into()), + _ => None, + } + } + + /// Returns the inclusion proof if present. + #[wasm_bindgen(js_name = "inclusionProof")] + pub fn inclusion_proof(&self) -> Option { + match &self.inner { + NativeNoteFile::NoteWithProof(_, proof) => Some(proof.into()), + _ => None, + } + } + + /// Returns the after-block hint when present. + #[wasm_bindgen(js_name = "afterBlockNum")] + pub fn after_block_num(&self) -> Option { + match &self.inner { + NativeNoteFile::NoteDetails { after_block_num, .. } => Some(after_block_num.as_u32()), + _ => None, + } + } + + /// Returns the note tag hint when present. + #[wasm_bindgen(js_name = "noteTag")] + pub fn note_tag(&self) -> Option { + match &self.inner { + NativeNoteFile::NoteDetails { tag, .. } => tag.map(Into::into), + _ => None, + } + } + + /// Returns the note nullifier when present. + pub fn nullifier(&self) -> Option { + match &self.inner { + NativeNoteFile::NoteDetails { details, .. } => Some(details.nullifier().to_hex()), + NativeNoteFile::NoteWithProof(note, _) => Some(note.nullifier().to_hex()), + NativeNoteFile::NoteId(_) => None, + } + } + /// Turn a notefile into its byte representation. #[wasm_bindgen(js_name = serialize)] pub fn serialize(&self) -> Vec { diff --git a/crates/web-client/src/models/note_sync_info.rs b/crates/web-client/src/models/note_sync_info.rs new file mode 100644 index 000000000..328f206a8 --- /dev/null +++ b/crates/web-client/src/models/note_sync_info.rs @@ -0,0 +1,45 @@ +use miden_client::rpc::domain::note::NoteSyncInfo as NativeNoteSyncInfo; +use wasm_bindgen::prelude::*; + +use super::block_header::BlockHeader; +use super::committed_note::CommittedNote; +use super::merkle_path::MerklePath; + +/// Represents the response data from `syncNotes`. +#[wasm_bindgen] +pub struct NoteSyncInfo(NativeNoteSyncInfo); + +#[wasm_bindgen] +impl NoteSyncInfo { + /// Returns the latest block number in the chain. + #[wasm_bindgen(js_name = "chainTip")] + pub fn chain_tip(&self) -> u32 { + self.0.chain_tip.as_u32() + } + + /// Returns the block header associated with the matching notes. + #[wasm_bindgen(js_name = "blockHeader")] + pub fn block_header(&self) -> BlockHeader { + self.0.block_header.clone().into() + } + + /// Returns the MMR path for the block header. + #[wasm_bindgen(js_name = "mmrPath")] + pub fn mmr_path(&self) -> MerklePath { + self.0.mmr_path.clone().into() + } + + /// Returns the committed notes returned by the node. + pub fn notes(&self) -> Vec { + self.0.notes.iter().map(Into::into).collect() + } +} + +// CONVERSIONS +// ================================================================================================ + +impl From for NoteSyncInfo { + fn from(native_info: NativeNoteSyncInfo) -> Self { + NoteSyncInfo(native_info) + } +} diff --git a/crates/web-client/src/models/note_tag.rs b/crates/web-client/src/models/note_tag.rs index 2c5d0058f..48c152cf1 100644 --- a/crates/web-client/src/models/note_tag.rs +++ b/crates/web-client/src/models/note_tag.rs @@ -43,6 +43,21 @@ impl NoteTag { NoteTag(native_note_tag) } + /// Builds a note tag from its raw u32 representation. + #[wasm_bindgen(js_name = "fromU32")] + pub fn from_u32(raw: u32) -> NoteTag { + NoteTag(NativeNoteTag::from(raw)) + } + + /// Builds a note tag from a hex-encoded string (with or without 0x prefix). + #[wasm_bindgen(js_name = "fromHex")] + pub fn from_hex(hex: &str) -> Result { + let trimmed = hex.strip_prefix("0x").unwrap_or(hex); + let raw = u32::from_str_radix(trimmed, 16) + .map_err(|err| JsValue::from_str(&format!("invalid note tag hex: {err}")))?; + Ok(NoteTag(NativeNoteTag::from(raw))) + } + /// Returns true if the tag targets a single account. #[wasm_bindgen(js_name = "isSingleTarget")] pub fn is_single_target(&self) -> bool { diff --git a/crates/web-client/src/models/output_note_record.rs b/crates/web-client/src/models/output_note_record.rs new file mode 100644 index 000000000..897ef5758 --- /dev/null +++ b/crates/web-client/src/models/output_note_record.rs @@ -0,0 +1,93 @@ +use miden_client::store::OutputNoteRecord as NativeOutputNoteRecord; +use wasm_bindgen::prelude::*; + +use super::note_assets::NoteAssets; +use super::note_id::NoteId; +use super::note_inclusion_proof::NoteInclusionProof; +use super::note_metadata::NoteMetadata; +use super::note_recipient::NoteRecipient; +use super::output_note_state::OutputNoteState; +use super::word::Word; + +/// Represents an output note tracked by the client store. +#[derive(Clone)] +#[wasm_bindgen] +pub struct OutputNoteRecord(NativeOutputNoteRecord); + +#[wasm_bindgen] +impl OutputNoteRecord { + /// Returns the note ID. + pub fn id(&self) -> NoteId { + self.0.id().into() + } + + /// Returns the current processing state for this note. + pub fn state(&self) -> OutputNoteState { + self.0.state().into() + } + + /// Returns the recipient digest committed for the note. + #[wasm_bindgen(js_name = "recipientDigest")] + pub fn recipient_digest(&self) -> Word { + self.0.recipient_digest().into() + } + + /// Returns the note assets. + pub fn assets(&self) -> NoteAssets { + self.0.assets().into() + } + + /// Returns the note metadata. + pub fn metadata(&self) -> NoteMetadata { + self.0.metadata().into() + } + + /// Returns the inclusion proof when the note is committed. + #[wasm_bindgen(js_name = "inclusionProof")] + pub fn inclusion_proof(&self) -> Option { + self.0.inclusion_proof().map(Into::into) + } + + /// Returns the recipient details if available. + pub fn recipient(&self) -> Option { + self.0.recipient().map(Into::into) + } + + /// Returns the expected block height for the note. + #[wasm_bindgen(js_name = "expectedHeight")] + pub fn expected_height(&self) -> u32 { + self.0.expected_height().as_u32() + } + + /// Returns the nullifier when the recipient is known. + pub fn nullifier(&self) -> Option { + self.0.nullifier().map(|nullifier| nullifier.to_hex()) + } + + /// Returns true if the note has been consumed on chain. + #[wasm_bindgen(js_name = "isConsumed")] + pub fn is_consumed(&self) -> bool { + self.0.is_consumed() + } + + /// Returns true if the note is committed on chain. + #[wasm_bindgen(js_name = "isCommitted")] + pub fn is_committed(&self) -> bool { + self.0.is_committed() + } +} + +// CONVERSIONS +// ================================================================================================ + +impl From for OutputNoteRecord { + fn from(native_note: NativeOutputNoteRecord) -> Self { + OutputNoteRecord(native_note) + } +} + +impl From<&NativeOutputNoteRecord> for OutputNoteRecord { + fn from(native_note: &NativeOutputNoteRecord) -> Self { + OutputNoteRecord(native_note.clone()) + } +} diff --git a/crates/web-client/src/models/output_note_state.rs b/crates/web-client/src/models/output_note_state.rs new file mode 100644 index 000000000..12460128e --- /dev/null +++ b/crates/web-client/src/models/output_note_state.rs @@ -0,0 +1,39 @@ +use miden_client::store::OutputNoteState as NativeOutputNoteState; +use wasm_bindgen::prelude::*; + +#[derive(Clone)] +#[wasm_bindgen] +pub enum OutputNoteState { + ExpectedPartial, + ExpectedFull, + CommittedPartial, + CommittedFull, + Consumed, +} + +// CONVERSIONS +// ================================================================================================ + +impl From for OutputNoteState { + fn from(native_note: NativeOutputNoteState) -> Self { + match native_note { + NativeOutputNoteState::ExpectedPartial => OutputNoteState::ExpectedPartial, + NativeOutputNoteState::ExpectedFull { .. } => OutputNoteState::ExpectedFull, + NativeOutputNoteState::CommittedPartial { .. } => OutputNoteState::CommittedPartial, + NativeOutputNoteState::CommittedFull { .. } => OutputNoteState::CommittedFull, + NativeOutputNoteState::Consumed { .. } => OutputNoteState::Consumed, + } + } +} + +impl From<&NativeOutputNoteState> for OutputNoteState { + fn from(native_note: &NativeOutputNoteState) -> Self { + match native_note { + NativeOutputNoteState::ExpectedPartial => OutputNoteState::ExpectedPartial, + NativeOutputNoteState::ExpectedFull { .. } => OutputNoteState::ExpectedFull, + NativeOutputNoteState::CommittedPartial { .. } => OutputNoteState::CommittedPartial, + NativeOutputNoteState::CommittedFull { .. } => OutputNoteState::CommittedFull, + NativeOutputNoteState::Consumed { .. } => OutputNoteState::Consumed, + } + } +} diff --git a/crates/web-client/src/models/sparse_merkle_path.rs b/crates/web-client/src/models/sparse_merkle_path.rs new file mode 100644 index 000000000..32ea6d36d --- /dev/null +++ b/crates/web-client/src/models/sparse_merkle_path.rs @@ -0,0 +1,45 @@ +use miden_protocol::crypto::merkle::SparseMerklePath as NativeSparseMerklePath; +use wasm_bindgen::prelude::*; + +use super::word::Word; + +/// Represents a sparse Merkle path. +#[derive(Clone)] +#[wasm_bindgen] +pub struct SparseMerklePath(NativeSparseMerklePath); + +#[wasm_bindgen] +impl SparseMerklePath { + /// Returns the empty nodes mask used by this path. + #[wasm_bindgen(js_name = "emptyNodesMask")] + pub fn empty_nodes_mask(&self) -> u64 { + let (mask, _siblings) = self.0.clone().into_parts(); + mask + } + + /// Returns the sibling nodes that make up the path. + pub fn nodes(&self) -> Vec { + let (_mask, siblings) = self.0.clone().into_parts(); + siblings.into_iter().map(Into::into).collect() + } + + /// Verifies the path against a root. + pub fn verify(&self, index: u64, node: &Word, root: &Word) -> bool { + self.0.verify(index, node.clone().into(), &root.clone().into()).is_ok() + } +} + +// CONVERSIONS +// ================================================================================================ + +impl From for SparseMerklePath { + fn from(native_path: NativeSparseMerklePath) -> Self { + SparseMerklePath(native_path) + } +} + +impl From<&NativeSparseMerklePath> for SparseMerklePath { + fn from(native_path: &NativeSparseMerklePath) -> Self { + SparseMerklePath(native_path.clone()) + } +} diff --git a/crates/web-client/src/models/transaction_record.rs b/crates/web-client/src/models/transaction_record.rs index 1ad4dd3c6..8af11a5ad 100644 --- a/crates/web-client/src/models/transaction_record.rs +++ b/crates/web-client/src/models/transaction_record.rs @@ -59,6 +59,18 @@ impl TransactionRecord { self.0.details.block_num.as_u32() } + /// Returns the block height at which the transaction was submitted. + #[wasm_bindgen(js_name = "submissionHeight")] + pub fn submission_height(&self) -> u32 { + self.0.details.submission_height.as_u32() + } + + /// Returns the expiration block height for the transaction. + #[wasm_bindgen(js_name = "expirationBlockNum")] + pub fn expiration_block_num(&self) -> u32 { + self.0.details.expiration_block_num.as_u32() + } + /// Returns the current status of the transaction. #[wasm_bindgen(js_name = "transactionStatus")] pub fn transaction_status(&self) -> TransactionStatus { diff --git a/crates/web-client/src/notes.rs b/crates/web-client/src/notes.rs index 8f629c624..b47392b6b 100644 --- a/crates/web-client/src/notes.rs +++ b/crates/web-client/src/notes.rs @@ -1,12 +1,12 @@ use miden_client::Word; use miden_client::note::NoteId; -use miden_client::store::OutputNoteRecord; use wasm_bindgen::prelude::*; use crate::models::account_id::AccountId; use crate::models::consumable_note_record::ConsumableNoteRecord; use crate::models::input_note_record::InputNoteRecord; use crate::models::note_filter::NoteFilter; +use crate::models::output_note_record::OutputNoteRecord; use crate::{WebClient, js_error_with_context}; #[wasm_bindgen] @@ -49,35 +49,35 @@ impl WebClient { } #[wasm_bindgen(js_name = "getOutputNotes")] - pub async fn get_output_notes(&mut self, filter: NoteFilter) -> Result { + pub async fn get_output_notes( + &mut self, + filter: NoteFilter, + ) -> Result, JsValue> { if let Some(client) = self.get_mut_inner() { - let notes: Vec = client + let notes = client .get_output_notes(filter.into()) .await .map_err(|err| js_error_with_context(err, "failed to get output notes"))?; - let note_ids = notes.iter().map(|note| note.id().to_string()).collect::>(); - - serde_wasm_bindgen::to_value(¬e_ids).map_err(|e| JsValue::from_str(&e.to_string())) + Ok(notes.into_iter().map(Into::into).collect()) } else { Err(JsValue::from_str("Client not initialized")) } } #[wasm_bindgen(js_name = "getOutputNote")] - pub async fn get_output_note(&mut self, note_id: String) -> Result { + pub async fn get_output_note(&mut self, note_id: String) -> Result { if let Some(client) = self.get_mut_inner() { let note_id: NoteId = NoteId::from_raw( Word::try_from(note_id) .map_err(|err| js_error_with_context(err, "failed to parse output note id"))?, ); - let note: OutputNoteRecord = client + let note = client .get_output_note(note_id) .await .map_err(|err| js_error_with_context(err, "failed to get output note"))? .ok_or_else(|| JsValue::from_str("Note not found"))?; - serde_wasm_bindgen::to_value(¬e.id().to_string()) - .map_err(|e| JsValue::from_str(&e.to_string())) + Ok(note.into()) } else { Err(JsValue::from_str("Client not initialized")) } diff --git a/crates/web-client/src/rpc_client/mod.rs b/crates/web-client/src/rpc_client/mod.rs index fdc50f453..381b98d0f 100644 --- a/crates/web-client/src/rpc_client/mod.rs +++ b/crates/web-client/src/rpc_client/mod.rs @@ -2,19 +2,26 @@ //! //! This module provides a WebAssembly-compatible RPC client for interacting with Miden nodes. +use alloc::collections::BTreeSet; use alloc::sync::Arc; use alloc::vec::Vec; -use miden_client::note::NoteId as NativeNoteId; +use miden_client::block::BlockNumber; +use miden_client::note::{NoteId as NativeNoteId, Nullifier}; use miden_client::rpc::domain::note::FetchedNote as NativeFetchedNote; use miden_client::rpc::{GrpcClient, NodeRpcClient}; use note::FetchedNote; use wasm_bindgen::prelude::*; use crate::js_error_with_context; +use crate::models::account_id::AccountId; +use crate::models::block_header::BlockHeader; use crate::models::endpoint::Endpoint; +use crate::models::fetched_account::FetchedAccount; use crate::models::note_id::NoteId; use crate::models::note_script::NoteScript; +use crate::models::note_sync_info::NoteSyncInfo; +use crate::models::note_tag::NoteTag; use crate::models::word::Word; mod note; @@ -92,4 +99,80 @@ impl RpcClient { Ok(note_script.into()) } + + /// Fetches a block header by number. When `block_num` is undefined, returns the latest header. + #[wasm_bindgen(js_name = "getBlockHeaderByNumber")] + pub async fn get_block_header_by_number( + &self, + block_num: Option, + ) -> Result { + let native_block_num = block_num.map(BlockNumber::from); + let (header, _proof) = + self.inner.get_block_header_by_number(native_block_num, false).await.map_err( + |err| js_error_with_context(err, "failed to get block header by number"), + )?; + + Ok(header.into()) + } + + /// Fetches account details for a specific account ID. + #[wasm_bindgen(js_name = "getAccountDetails")] + pub async fn get_account_details( + &self, + account_id: AccountId, + ) -> Result { + let fetched = self + .inner + .get_account_details(account_id.into()) + .await + .map_err(|err| js_error_with_context(err, "failed to get account details"))?; + + Ok(fetched.into()) + } + + /// Fetches notes matching the provided tags from the node. + #[wasm_bindgen(js_name = "syncNotes")] + pub async fn sync_notes( + &self, + block_num: u32, + block_to: Option, + note_tags: Vec, + ) -> Result { + let mut tags = BTreeSet::new(); + for tag in note_tags { + tags.insert(tag.into()); + } + + let block_num = BlockNumber::from(block_num); + let block_to = block_to.map(BlockNumber::from); + + let info = self + .inner + .sync_notes(block_num, block_to, &tags) + .await + .map_err(|err| js_error_with_context(err, "failed to sync notes"))?; + + Ok(info.into()) + } + + /// Fetches the block height at which a nullifier was committed, if any. + #[wasm_bindgen(js_name = "getNullifierCommitHeight")] + pub async fn get_nullifier_commit_height( + &self, + nullifier: Word, + block_num: u32, + ) -> Result, JsValue> { + let native_word: miden_client::Word = nullifier.into(); + // TODO: nullifier JS binding + let nullifier = Nullifier::from_raw(native_word); + let block_num = BlockNumber::from(block_num); + + let height = self + .inner + .get_nullifier_commit_height(&nullifier, block_num) + .await + .map_err(|err| js_error_with_context(err, "failed to get nullifier commit height"))?; + + Ok(height.map(|height| height.as_u32())) + } } diff --git a/crates/web-client/test/new_transactions.test.ts b/crates/web-client/test/new_transactions.test.ts index d11517be3..74e896222 100644 --- a/crates/web-client/test/new_transactions.test.ts +++ b/crates/web-client/test/new_transactions.test.ts @@ -356,7 +356,6 @@ export const customTransaction = async ( use miden::core::sys use miden::core::mem use miden::standards::wallets::basic->basic_wallet - begin # push data from the advice map into the advice stack adv.push_mapval diff --git a/crates/web-client/test/notes.test.ts b/crates/web-client/test/notes.test.ts index 1c815490c..831b20fbb 100644 --- a/crates/web-client/test/notes.test.ts +++ b/crates/web-client/test/notes.test.ts @@ -133,6 +133,56 @@ test.describe("get_input_note", () => { expect(retrievedScript.hasScript).toBe(true); expect(retrievedScript.scriptRoot).toEqual(noteData.scriptRoot); }); + + test("sync notes by tag and check nullifier commit height", async ({ + page, + }) => { + const { consumedNoteId } = await setupConsumedNote(page, true); + + const result = await page.evaluate(async (_consumedNoteId: string) => { + const endpoint = new window.Endpoint(window.rpcUrl); + const rpcClient = new window.RpcClient(endpoint); + + const noteId = window.NoteId.fromHex(_consumedNoteId); + const fetchedNotes = await rpcClient.getNotesById([noteId]); + + if (fetchedNotes.length === 0) { + return { found: false }; + } + + const note = fetchedNotes[0].note; + const tag = fetchedNotes[0].metadata.tag(); + + const syncInfo = await rpcClient.syncNotes(0, undefined, [tag]); + const syncedNoteIds = syncInfo + .notes() + .map((synced) => synced.noteId().toString()); + + const inputNote = await window.client.getInputNote(_consumedNoteId); + const nullifierWord = note + ? note.nullifier() + : inputNote + ? window.Word.fromHex(inputNote.nullifier()) + : undefined; + const commitHeight = nullifierWord + ? await rpcClient.getNullifierCommitHeight(nullifierWord, 0) + : undefined; + + return { + found: true, + syncedNoteIds, + noteNullifierHex: note ? note.nullifier().toHex() : undefined, + noteNullifierWord: note ? note.nullifier().toHex() : undefined, + commitHeight, + }; + }, consumedNoteId); + + expect(result.found).toBe(true); + expect(result.syncedNoteIds).toContain(consumedNoteId); + expect(result.noteNullifierHex).toMatch(/^0x[0-9a-fA-F]+$/); + expect(result.noteNullifierWord).toEqual(result.noteNullifierHex); + expect(result.commitHeight).not.toBeUndefined(); + }); }); test.describe("get_input_notes", () => { diff --git a/crates/web-client/yarn.lock b/crates/web-client/yarn.lock index 54514e86f..7ed42a49c 100644 --- a/crates/web-client/yarn.lock +++ b/crates/web-client/yarn.lock @@ -93,7 +93,7 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": +"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": version "2.0.5" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -195,7 +195,7 @@ dependencies: "@shikijs/types" "3.13.0" -"@shikijs/types@3.13.0", "@shikijs/types@^3.13.0": +"@shikijs/types@^3.13.0", "@shikijs/types@3.13.0": version "3.13.0" resolved "https://registry.npmjs.org/@shikijs/types/-/types-3.13.0.tgz" integrity sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw== @@ -463,6 +463,11 @@ binary-extensions@^2.0.0: resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz" integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== +binaryen@^121.0.0: + version "121.0.0" + resolved "https://registry.npmjs.org/binaryen/-/binaryen-121.0.0.tgz" + integrity sha512-St5LX+CmVdDQMf+DDHWdne7eDK+8tH9TE4Kc+Xk3s5+CzVYIKeJbWuXgsKVbkdLJXGUc2eflFqjThQy555mBag== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" @@ -628,16 +633,16 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - color-name@~1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + colorette@^1.1.0: version "1.4.0" resolved "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz" @@ -709,13 +714,6 @@ data-uri-to-buffer@^6.0.2: resolved "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz" integrity sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw== -debug@4, debug@^4.1.1, debug@^4.3.4, debug@^4.3.5, debug@^4.3.6: - version "4.4.3" - resolved "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz" - integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== - dependencies: - ms "^2.1.3" - debug@^3.2.7: version "3.2.7" resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" @@ -723,6 +721,13 @@ debug@^3.2.7: dependencies: ms "^2.1.1" +debug@^4.1.1, debug@^4.3.4, debug@^4.3.5, debug@^4.3.6, debug@4: + version "4.4.3" + resolved "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== + dependencies: + ms "^2.1.3" + decamelize@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz" @@ -756,7 +761,7 @@ degenerator@^5.0.0: escodegen "^2.1.0" esprima "^4.0.1" -devtools-protocol@0.0.1330662: +devtools-protocol@*, devtools-protocol@0.0.1330662: version "0.0.1330662" resolved "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1330662.tgz" integrity sha512-pzh6YQ8zZfz3iKlCvgzVCu22NdpZ8hNmwU6WnQjNVquh0A9iVosPtNLWDwaWVGyrntQlltPFztTMK5Cg6lfCuw== @@ -1002,16 +1007,16 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@2.3.2: - version "2.3.2" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - fsevents@~2.3.2: version "2.3.3" resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== +fsevents@2.3.2: + version "2.3.2" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + function-bind@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" @@ -1098,7 +1103,18 @@ glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^8.0.3, glob@^8.1.0: +glob@^8.0.3: + version "8.1.0" + resolved "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + +glob@^8.1.0: version "8.1.0" resolved "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz" integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== @@ -1534,7 +1550,14 @@ minimatch@^5.0.1, minimatch@^5.1.6: dependencies: brace-expansion "^2.0.1" -minimatch@^9.0.4, minimatch@^9.0.5: +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^9.0.5: version "9.0.5" resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz" integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== @@ -1949,7 +1972,7 @@ rollup-plugin-copy@^3.5.0: globby "10.0.1" is-plain-object "^3.0.0" -rollup@^3.27.2: +rollup@^1.20.0||^2.0.0||^3.0.0||^4.0.0, rollup@^2.14.0||^3.0.0||^4.0.0, rollup@^2.68.0||^3.0.0||^4.0.0, rollup@^2.78.0||^3.0.0||^4.0.0, rollup@^3.27.2: version "3.29.4" resolved "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz" integrity sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw== @@ -1963,7 +1986,7 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -safe-buffer@5.1.2, safe-buffer@^5.1.0: +safe-buffer@^5.1.0, safe-buffer@5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== @@ -2226,7 +2249,7 @@ ts-node@^10.9.2: v8-compile-cache-lib "^3.0.1" yn "3.1.1" -tslib@^2.0.1: +tslib@*, tslib@^2.0.1: version "2.8.1" resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== @@ -2241,7 +2264,7 @@ typedoc-plugin-markdown@^4.8.1: resolved "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-4.9.0.tgz" integrity sha512-9Uu4WR9L7ZBgAl60N/h+jqmPxxvnC9nQAlnnO/OujtG2ubjnKTVUFY1XDhcMY+pCqlX3N2HsQM2QTYZIU9tJuw== -typedoc@^0.28.1: +typedoc@^0.28.1, typedoc@0.28.x: version "0.28.13" resolved "https://registry.npmjs.org/typedoc/-/typedoc-0.28.13.tgz" integrity sha512-dNWY8msnYB2a+7Audha+aTF1Pu3euiE7ySp53w8kEsXoYw7dMouV5A1UsTUY345aB152RHnmRMDiovuBi7BD+w== @@ -2252,7 +2275,7 @@ typedoc@^0.28.1: minimatch "^9.0.5" yaml "^2.8.1" -typescript@^5.5.4: +typescript@^5.5.4, typescript@>=2.7, typescript@>=3.7.0, typescript@>=4.9.5, "typescript@5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x": version "5.5.4" resolved "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz" integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== diff --git a/docs/typedoc/web-client/README.md b/docs/typedoc/web-client/README.md index 7f2ab019d..a93447e55 100644 --- a/docs/typedoc/web-client/README.md +++ b/docs/typedoc/web-client/README.md @@ -13,6 +13,7 @@ - [NetworkType](enumerations/NetworkType.md) - [NoteFilterTypes](enumerations/NoteFilterTypes.md) - [NoteType](enumerations/NoteType.md) +- [OutputNoteState](enumerations/OutputNoteState.md) - [SigningInputsType](enumerations/SigningInputsType.md) ## Classes @@ -42,11 +43,13 @@ - [BasicFungibleFaucetComponent](classes/BasicFungibleFaucetComponent.md) - [BlockHeader](classes/BlockHeader.md) - [CodeBuilder](classes/CodeBuilder.md) +- [CommittedNote](classes/CommittedNote.md) - [ConsumableNoteRecord](classes/ConsumableNoteRecord.md) - [Endpoint](classes/Endpoint.md) - [ExecutedTransaction](classes/ExecutedTransaction.md) - [Felt](classes/Felt.md) - [FeltArray](classes/FeltArray.md) +- [FetchedAccount](classes/FetchedAccount.md) - [FetchedNote](classes/FetchedNote.md) - [FlattenedU8Vec](classes/FlattenedU8Vec.md) - [ForeignAccount](classes/ForeignAccount.md) @@ -92,9 +95,11 @@ - [NoteRecipient](classes/NoteRecipient.md) - [NoteRecipientArray](classes/NoteRecipientArray.md) - [NoteScript](classes/NoteScript.md) +- [NoteSyncInfo](classes/NoteSyncInfo.md) - [NoteTag](classes/NoteTag.md) - [OutputNote](classes/OutputNote.md) - [OutputNoteArray](classes/OutputNoteArray.md) +- [OutputNoteRecord](classes/OutputNoteRecord.md) - [OutputNotes](classes/OutputNotes.md) - [OutputNotesArray](classes/OutputNotesArray.md) - [Package](classes/Package.md) @@ -110,6 +115,7 @@ - [Signature](classes/Signature.md) - [SigningInputs](classes/SigningInputs.md) - [SlotAndKeys](classes/SlotAndKeys.md) +- [SparseMerklePath](classes/SparseMerklePath.md) - [StorageMap](classes/StorageMap.md) - [StorageSlot](classes/StorageSlot.md) - [StorageSlotArray](classes/StorageSlotArray.md) diff --git a/docs/typedoc/web-client/classes/AccountFile.md b/docs/typedoc/web-client/classes/AccountFile.md index d8c03e20e..1fb7a29f1 100644 --- a/docs/typedoc/web-client/classes/AccountFile.md +++ b/docs/typedoc/web-client/classes/AccountFile.md @@ -18,6 +18,42 @@ *** +### account() + +> **account**(): [`Account`](Account.md) + +Returns the account data. + +#### Returns + +[`Account`](Account.md) + +*** + +### accountId() + +> **accountId**(): [`AccountId`](AccountId.md) + +Returns the account ID. + +#### Returns + +[`AccountId`](AccountId.md) + +*** + +### authSecretKeyCount() + +> **authSecretKeyCount**(): `number` + +Returns the number of auth secret keys included. + +#### Returns + +`number` + +*** + ### free() > **free**(): `void` diff --git a/docs/typedoc/web-client/classes/CommittedNote.md b/docs/typedoc/web-client/classes/CommittedNote.md new file mode 100644 index 000000000..7b175ec89 --- /dev/null +++ b/docs/typedoc/web-client/classes/CommittedNote.md @@ -0,0 +1,77 @@ +[**@demox-labs/miden-sdk**](../README.md) + +*** + +[@demox-labs/miden-sdk](../README.md) / CommittedNote + +# Class: CommittedNote + +Represents a note committed on chain, as returned by `syncNotes`. + +## Methods + +### \[dispose\]() + +> **\[dispose\]**(): `void` + +#### Returns + +`void` + +*** + +### free() + +> **free**(): `void` + +#### Returns + +`void` + +*** + +### inclusionPath() + +> **inclusionPath**(): [`SparseMerklePath`](SparseMerklePath.md) + +Returns the inclusion path for the note. + +#### Returns + +[`SparseMerklePath`](SparseMerklePath.md) + +*** + +### metadata() + +> **metadata**(): [`NoteMetadata`](NoteMetadata.md) + +Returns the note metadata. + +#### Returns + +[`NoteMetadata`](NoteMetadata.md) + +*** + +### noteId() + +> **noteId**(): [`NoteId`](NoteId.md) + +Returns the note ID. + +#### Returns + +[`NoteId`](NoteId.md) + +*** + +### noteIndex() + +> **noteIndex**(): `number` + +Returns the note index in the block's note tree. + +#### Returns + +`number` diff --git a/docs/typedoc/web-client/classes/FetchedAccount.md b/docs/typedoc/web-client/classes/FetchedAccount.md new file mode 100644 index 000000000..a31a38b55 --- /dev/null +++ b/docs/typedoc/web-client/classes/FetchedAccount.md @@ -0,0 +1,113 @@ +[**@demox-labs/miden-sdk**](../README.md) + +*** + +[@demox-labs/miden-sdk](../README.md) / FetchedAccount + +# Class: FetchedAccount + +Account details returned by the node. + +## Methods + +### \[dispose\]() + +> **\[dispose\]**(): `void` + +#### Returns + +`void` + +*** + +### account() + +> **account**(): [`Account`](Account.md) + +Returns the full account data when the account is public. + +#### Returns + +[`Account`](Account.md) + +*** + +### accountId() + +> **accountId**(): [`AccountId`](AccountId.md) + +Returns the account ID. + +#### Returns + +[`AccountId`](AccountId.md) + +*** + +### commitment() + +> **commitment**(): [`Word`](Word.md) + +Returns the account commitment reported by the node. + +#### Returns + +[`Word`](Word.md) + +*** + +### free() + +> **free**(): `void` + +#### Returns + +`void` + +*** + +### isNetwork() + +> **isNetwork**(): `boolean` + +Returns true when the account is a network account. + +#### Returns + +`boolean` + +*** + +### isPrivate() + +> **isPrivate**(): `boolean` + +Returns true when the account is private. + +#### Returns + +`boolean` + +*** + +### isPublic() + +> **isPublic**(): `boolean` + +Returns true when the account is public. + +#### Returns + +`boolean` + +*** + +### lastBlockNum() + +> **lastBlockNum**(): `number` + +Returns the last block height where the account was updated. + +#### Returns + +`number` diff --git a/docs/typedoc/web-client/classes/Note.md b/docs/typedoc/web-client/classes/Note.md index 7d76b60ff..87b49acb1 100644 --- a/docs/typedoc/web-client/classes/Note.md +++ b/docs/typedoc/web-client/classes/Note.md @@ -108,6 +108,18 @@ Returns the public metadata associated with the note. *** +### nullifier() + +> **nullifier**(): [`Word`](Word.md) + +Returns the note nullifier as a word. + +#### Returns + +[`Word`](Word.md) + +*** + ### recipient() > **recipient**(): [`NoteRecipient`](NoteRecipient.md) diff --git a/docs/typedoc/web-client/classes/NoteDetails.md b/docs/typedoc/web-client/classes/NoteDetails.md index f8d9edce9..c6f7d667a 100644 --- a/docs/typedoc/web-client/classes/NoteDetails.md +++ b/docs/typedoc/web-client/classes/NoteDetails.md @@ -78,6 +78,18 @@ Returns the note identifier derived from these details. *** +### nullifier() + +> **nullifier**(): [`Word`](Word.md) + +Returns the note nullifier as a word. + +#### Returns + +[`Word`](Word.md) + +*** + ### recipient() > **recipient**(): [`NoteRecipient`](NoteRecipient.md) diff --git a/docs/typedoc/web-client/classes/NoteFile.md b/docs/typedoc/web-client/classes/NoteFile.md index 0fb42006d..e1eda8531 100644 --- a/docs/typedoc/web-client/classes/NoteFile.md +++ b/docs/typedoc/web-client/classes/NoteFile.md @@ -20,6 +20,18 @@ A serialized representation of a note. *** +### afterBlockNum() + +> **afterBlockNum**(): `number` + +Returns the after-block hint when present. + +#### Returns + +`number` + +*** + ### free() > **free**(): `void` @@ -30,6 +42,66 @@ A serialized representation of a note. *** +### inclusionProof() + +> **inclusionProof**(): [`NoteInclusionProof`](NoteInclusionProof.md) + +Returns the inclusion proof if present. + +#### Returns + +[`NoteInclusionProof`](NoteInclusionProof.md) + +*** + +### note() + +> **note**(): [`Note`](Note.md) + +Returns the full note when the file includes it. + +#### Returns + +[`Note`](Note.md) + +*** + +### noteDetails() + +> **noteDetails**(): [`NoteDetails`](NoteDetails.md) + +Returns the note details if present. + +#### Returns + +[`NoteDetails`](NoteDetails.md) + +*** + +### noteId() + +> **noteId**(): [`NoteId`](NoteId.md) + +Returns the note ID for any `NoteFile` variant. + +#### Returns + +[`NoteId`](NoteId.md) + +*** + +### noteTag() + +> **noteTag**(): [`NoteTag`](NoteTag.md) + +Returns the note tag hint when present. + +#### Returns + +[`NoteTag`](NoteTag.md) + +*** + ### noteType() > **noteType**(): `string` @@ -42,6 +114,18 @@ Returns this `NoteFile`'s types. *** +### nullifier() + +> **nullifier**(): `string` + +Returns the note nullifier when present. + +#### Returns + +`string` + +*** + ### serialize() > **serialize**(): `Uint8Array` diff --git a/docs/typedoc/web-client/classes/NoteSyncInfo.md b/docs/typedoc/web-client/classes/NoteSyncInfo.md new file mode 100644 index 000000000..d509f9c05 --- /dev/null +++ b/docs/typedoc/web-client/classes/NoteSyncInfo.md @@ -0,0 +1,77 @@ +[**@demox-labs/miden-sdk**](../README.md) + +*** + +[@demox-labs/miden-sdk](../README.md) / NoteSyncInfo + +# Class: NoteSyncInfo + +Represents the response data from `syncNotes`. + +## Methods + +### \[dispose\]() + +> **\[dispose\]**(): `void` + +#### Returns + +`void` + +*** + +### blockHeader() + +> **blockHeader**(): [`BlockHeader`](BlockHeader.md) + +Returns the block header associated with the matching notes. + +#### Returns + +[`BlockHeader`](BlockHeader.md) + +*** + +### chainTip() + +> **chainTip**(): `number` + +Returns the latest block number in the chain. + +#### Returns + +`number` + +*** + +### free() + +> **free**(): `void` + +#### Returns + +`void` + +*** + +### mmrPath() + +> **mmrPath**(): [`MerklePath`](MerklePath.md) + +Returns the MMR path for the block header. + +#### Returns + +[`MerklePath`](MerklePath.md) + +*** + +### notes() + +> **notes**(): [`CommittedNote`](CommittedNote.md)[] + +Returns the committed notes returned by the node. + +#### Returns + +[`CommittedNote`](CommittedNote.md)[] diff --git a/docs/typedoc/web-client/classes/NoteTag.md b/docs/typedoc/web-client/classes/NoteTag.md index 098f6def8..1184ec656 100644 --- a/docs/typedoc/web-client/classes/NoteTag.md +++ b/docs/typedoc/web-client/classes/NoteTag.md @@ -132,3 +132,39 @@ Builds a single-target tag derived from an account ID. #### Returns `NoteTag` + +*** + +### fromHex() + +> `static` **fromHex**(`hex`): `NoteTag` + +Builds a note tag from a hex-encoded string (with or without 0x prefix). + +#### Parameters + +##### hex + +`string` + +#### Returns + +`NoteTag` + +*** + +### fromU32() + +> `static` **fromU32**(`raw`): `NoteTag` + +Builds a note tag from its raw u32 representation. + +#### Parameters + +##### raw + +`number` + +#### Returns + +`NoteTag` diff --git a/docs/typedoc/web-client/classes/OutputNoteRecord.md b/docs/typedoc/web-client/classes/OutputNoteRecord.md new file mode 100644 index 000000000..b07403f97 --- /dev/null +++ b/docs/typedoc/web-client/classes/OutputNoteRecord.md @@ -0,0 +1,161 @@ +[**@demox-labs/miden-sdk**](../README.md) + +*** + +[@demox-labs/miden-sdk](../README.md) / OutputNoteRecord + +# Class: OutputNoteRecord + +Represents an output note tracked by the client store. + +## Methods + +### \[dispose\]() + +> **\[dispose\]**(): `void` + +#### Returns + +`void` + +*** + +### assets() + +> **assets**(): [`NoteAssets`](NoteAssets.md) + +Returns the note assets. + +#### Returns + +[`NoteAssets`](NoteAssets.md) + +*** + +### expectedHeight() + +> **expectedHeight**(): `number` + +Returns the expected block height for the note. + +#### Returns + +`number` + +*** + +### free() + +> **free**(): `void` + +#### Returns + +`void` + +*** + +### id() + +> **id**(): [`NoteId`](NoteId.md) + +Returns the note ID. + +#### Returns + +[`NoteId`](NoteId.md) + +*** + +### inclusionProof() + +> **inclusionProof**(): [`NoteInclusionProof`](NoteInclusionProof.md) + +Returns the inclusion proof when the note is committed. + +#### Returns + +[`NoteInclusionProof`](NoteInclusionProof.md) + +*** + +### isCommitted() + +> **isCommitted**(): `boolean` + +Returns true if the note is committed on chain. + +#### Returns + +`boolean` + +*** + +### isConsumed() + +> **isConsumed**(): `boolean` + +Returns true if the note has been consumed on chain. + +#### Returns + +`boolean` + +*** + +### metadata() + +> **metadata**(): [`NoteMetadata`](NoteMetadata.md) + +Returns the note metadata. + +#### Returns + +[`NoteMetadata`](NoteMetadata.md) + +*** + +### nullifier() + +> **nullifier**(): `string` + +Returns the nullifier when the recipient is known. + +#### Returns + +`string` + +*** + +### recipient() + +> **recipient**(): [`NoteRecipient`](NoteRecipient.md) + +Returns the recipient details if available. + +#### Returns + +[`NoteRecipient`](NoteRecipient.md) + +*** + +### recipientDigest() + +> **recipientDigest**(): [`Word`](Word.md) + +Returns the recipient digest committed for the note. + +#### Returns + +[`Word`](Word.md) + +*** + +### state() + +> **state**(): [`OutputNoteState`](../enumerations/OutputNoteState.md) + +Returns the current processing state for this note. + +#### Returns + +[`OutputNoteState`](../enumerations/OutputNoteState.md) diff --git a/docs/typedoc/web-client/classes/RpcClient.md b/docs/typedoc/web-client/classes/RpcClient.md index 38d5c0465..9036835b0 100644 --- a/docs/typedoc/web-client/classes/RpcClient.md +++ b/docs/typedoc/web-client/classes/RpcClient.md @@ -50,6 +50,42 @@ Endpoint to connect to. *** +### getAccountDetails() + +> **getAccountDetails**(`account_id`): `Promise`\<[`FetchedAccount`](FetchedAccount.md)\> + +Fetches account details for a specific account ID. + +#### Parameters + +##### account\_id + +[`AccountId`](AccountId.md) + +#### Returns + +`Promise`\<[`FetchedAccount`](FetchedAccount.md)\> + +*** + +### getBlockHeaderByNumber() + +> **getBlockHeaderByNumber**(`block_num?`): `Promise`\<[`BlockHeader`](BlockHeader.md)\> + +Fetches a block header by number. When `block_num` is undefined, returns the latest header. + +#### Parameters + +##### block\_num? + +`number` + +#### Returns + +`Promise`\<[`BlockHeader`](BlockHeader.md)\> + +*** + ### getNotesById() > **getNotesById**(`note_ids`): `Promise`\<[`FetchedNote`](FetchedNote.md)[]\> @@ -94,3 +130,51 @@ The root hash of the note script to fetch. `Promise`\<[`NoteScript`](NoteScript.md)\> Promise that resolves to the `NoteScript`. + +*** + +### getNullifierCommitHeight() + +> **getNullifierCommitHeight**(`nullifier`, `block_num`): `Promise`\<`number`\> + +Fetches the block height at which a nullifier was committed, if any. + +#### Parameters + +##### nullifier + +[`Word`](Word.md) + +##### block\_num + +`number` + +#### Returns + +`Promise`\<`number`\> + +*** + +### syncNotes() + +> **syncNotes**(`block_num`, `block_to`, `note_tags`): `Promise`\<[`NoteSyncInfo`](NoteSyncInfo.md)\> + +Fetches notes matching the provided tags from the node. + +#### Parameters + +##### block\_num + +`number` + +##### block\_to + +`number` + +##### note\_tags + +[`NoteTag`](NoteTag.md)[] + +#### Returns + +`Promise`\<[`NoteSyncInfo`](NoteSyncInfo.md)\> diff --git a/docs/typedoc/web-client/classes/SparseMerklePath.md b/docs/typedoc/web-client/classes/SparseMerklePath.md new file mode 100644 index 000000000..711e1ddbe --- /dev/null +++ b/docs/typedoc/web-client/classes/SparseMerklePath.md @@ -0,0 +1,79 @@ +[**@demox-labs/miden-sdk**](../README.md) + +*** + +[@demox-labs/miden-sdk](../README.md) / SparseMerklePath + +# Class: SparseMerklePath + +Represents a sparse Merkle path. + +## Methods + +### \[dispose\]() + +> **\[dispose\]**(): `void` + +#### Returns + +`void` + +*** + +### emptyNodesMask() + +> **emptyNodesMask**(): `bigint` + +Returns the empty nodes mask used by this path. + +#### Returns + +`bigint` + +*** + +### free() + +> **free**(): `void` + +#### Returns + +`void` + +*** + +### nodes() + +> **nodes**(): [`Word`](Word.md)[] + +Returns the sibling nodes that make up the path. + +#### Returns + +[`Word`](Word.md)[] + +*** + +### verify() + +> **verify**(`index`, `node`, `root`): `boolean` + +Verifies the path against a root. + +#### Parameters + +##### index + +`bigint` + +##### node + +[`Word`](Word.md) + +##### root + +[`Word`](Word.md) + +#### Returns + +`boolean` diff --git a/docs/typedoc/web-client/classes/TransactionRecord.md b/docs/typedoc/web-client/classes/TransactionRecord.md index 74505be94..16405558f 100644 --- a/docs/typedoc/web-client/classes/TransactionRecord.md +++ b/docs/typedoc/web-client/classes/TransactionRecord.md @@ -56,6 +56,18 @@ Returns the timestamp when the record was created. *** +### expirationBlockNum() + +> **expirationBlockNum**(): `number` + +Returns the expiration block height for the transaction. + +#### Returns + +`number` + +*** + ### finalAccountState() > **finalAccountState**(): [`Word`](Word.md) @@ -126,6 +138,18 @@ Returns the output notes created by this transaction. *** +### submissionHeight() + +> **submissionHeight**(): `number` + +Returns the block height at which the transaction was submitted. + +#### Returns + +`number` + +*** + ### transactionStatus() > **transactionStatus**(): [`TransactionStatus`](TransactionStatus.md) diff --git a/docs/typedoc/web-client/classes/WebClient.md b/docs/typedoc/web-client/classes/WebClient.md index 6afb6e897..710b90ba2 100644 --- a/docs/typedoc/web-client/classes/WebClient.md +++ b/docs/typedoc/web-client/classes/WebClient.md @@ -409,7 +409,7 @@ Uses an internal pagination mechanism to avoid fetching duplicate notes. ### getOutputNote() -> **getOutputNote**(`note_id`): `Promise`\<`any`\> +> **getOutputNote**(`note_id`): `Promise`\<[`OutputNoteRecord`](OutputNoteRecord.md)\> #### Parameters @@ -419,13 +419,13 @@ Uses an internal pagination mechanism to avoid fetching duplicate notes. #### Returns -`Promise`\<`any`\> +`Promise`\<[`OutputNoteRecord`](OutputNoteRecord.md)\> *** ### getOutputNotes() -> **getOutputNotes**(`filter`): `Promise`\<`any`\> +> **getOutputNotes**(`filter`): `Promise`\<[`OutputNoteRecord`](OutputNoteRecord.md)[]\> #### Parameters @@ -435,7 +435,7 @@ Uses an internal pagination mechanism to avoid fetching duplicate notes. #### Returns -`Promise`\<`any`\> +`Promise`\<[`OutputNoteRecord`](OutputNoteRecord.md)[]\> *** diff --git a/docs/typedoc/web-client/enumerations/OutputNoteState.md b/docs/typedoc/web-client/enumerations/OutputNoteState.md new file mode 100644 index 000000000..eb6dc1ac2 --- /dev/null +++ b/docs/typedoc/web-client/enumerations/OutputNoteState.md @@ -0,0 +1,37 @@ +[**@demox-labs/miden-sdk**](../README.md) + +*** + +[@demox-labs/miden-sdk](../README.md) / OutputNoteState + +# Enumeration: OutputNoteState + +## Enumeration Members + +### CommittedFull + +> **CommittedFull**: `3` + +*** + +### CommittedPartial + +> **CommittedPartial**: `2` + +*** + +### Consumed + +> **Consumed**: `4` + +*** + +### ExpectedFull + +> **ExpectedFull**: `1` + +*** + +### ExpectedPartial + +> **ExpectedPartial**: `0` From 86b03962f349b97f16c6ac8573eb11978f2ab0e3 Mon Sep 17 00:00:00 2001 From: Ignacio Amigo Date: Wed, 7 Jan 2026 12:29:03 -0300 Subject: [PATCH 2/2] chore: bindgen typings --- crates/web-client/js/types/index.d.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/web-client/js/types/index.d.ts b/crates/web-client/js/types/index.d.ts index d24dd92c1..81442c3bb 100644 --- a/crates/web-client/js/types/index.d.ts +++ b/crates/web-client/js/types/index.d.ts @@ -33,11 +33,13 @@ export { AuthSecretKey, BasicFungibleFaucetComponent, BlockHeader, + CommittedNote, ConsumableNoteRecord, Endpoint, ExecutedTransaction, Felt, FeltArray, + FetchedAccount, FetchedNote, FlattenedU8Vec, ForeignAccount, @@ -86,12 +88,15 @@ export { NoteRecipient, NoteRecipientArray, NoteScript, + NoteSyncInfo, NoteTag, NoteType, OutputNote, OutputNoteArray, OutputNotes, OutputNotesArray, + OutputNoteRecord, + OutputNoteState, Package, PartialNote, Program, @@ -108,6 +113,7 @@ export { SigningInputs, SigningInputsType, SlotAndKeys, + SparseMerklePath, StorageMap, StorageSlot, StorageSlotArray,