1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
use js_export_macro::js_export;
use miden_client::note::Note as NativeNote;
use miden_client::store::InputNoteRecord as NativeInputNoteRecord;
use miden_client::transaction::InputNote as NativeInputNote;
use super::input_note_state::InputNoteState;
use super::note_attachment::NoteAttachment;
use super::note_details::NoteDetails;
use super::note_id::NoteId;
use super::note_inclusion_proof::NoteInclusionProof;
use super::note_metadata::NoteMetadata;
use super::word::Word;
use crate::js_error_with_context;
use crate::models::input_note::InputNote;
use crate::models::note::Note;
use crate::platform::JsErr;
/// Represents a Note of which the Store can keep track and retrieve.
///
/// An `InputNoteRecord` contains all the information of a `NoteDetails`, in addition to specific
/// information about the note state.
///
/// Once a proof is received, the `InputNoteRecord` can be transformed into an `InputNote` and used
/// as input for transactions. It is also possible to convert `Note` and `InputNote` into
/// `InputNoteRecord` (we fill the `metadata` and `inclusion_proof` fields if possible).
///
/// Notes can also be consumed as unauthenticated notes, where their existence is verified by the
/// network.
#[derive(Clone)]
#[js_export]
pub struct InputNoteRecord(NativeInputNoteRecord);
#[js_export]
impl InputNoteRecord {
/// Returns the note ID when available.
///
/// Migration note (miden-client PR #2214): `InputNoteRecord::id()`
/// returns `Option<NoteId>` — partial / metadata-less notes have no
/// metadata-bearing ID yet.
pub fn id(&self) -> Option<NoteId> {
self.0.id().map(Into::into)
}
/// Returns the current processing state for this note.
pub fn state(&self) -> InputNoteState {
self.0.state().into()
}
/// Returns the note details, if present.
pub fn details(&self) -> NoteDetails {
self.0.details().into()
}
/// Returns the note metadata if available.
pub fn metadata(&self) -> Option<NoteMetadata> {
self.0.metadata().map(Into::into)
}
/// Returns the note's attachments.
///
/// On the 0.15 surface the full attachment content (the packed words) lives
/// on the note record itself rather than on `NoteMetadata` (which only
/// carries the attachment headers). This exposes that content so JS callers
/// can decode payloads packed via the `createNoteAttachment` helper. An
/// empty array means the note carries no attachments.
pub fn attachments(&self) -> Vec<NoteAttachment> {
self.0.attachments().iter().map(Into::into).collect()
}
/// Returns the note commitment (id + metadata), if available.
pub fn commitment(&self) -> Option<Word> {
self.0.commitment().map(Into::into)
}
/// Returns the inclusion proof when the note is authenticated.
#[js_export(js_name = "inclusionProof")]
pub fn inclusion_proof(&self) -> Option<NoteInclusionProof> {
self.0.inclusion_proof().map(Into::into)
}
/// Returns the transaction ID that consumed this note, if any.
#[js_export(js_name = "consumerTransactionId")]
pub fn consumer_transaction_id(&self) -> Option<String> {
self.0.consumer_transaction_id().map(ToString::to_string)
}
/// Returns the nullifier for this note when available.
///
/// Migration note (miden-client PR #2214): `InputNoteRecord::nullifier()`
/// returns `Option<Nullifier>` — partial notes have no nullifier yet.
pub fn nullifier(&self) -> Option<String> {
self.0.nullifier().map(|n| n.to_hex())
}
/// Returns true if the record contains authentication data (proof).
#[js_export(js_name = "isAuthenticated")]
pub fn is_authenticated(&self) -> bool {
self.0.is_authenticated()
}
/// Returns true if the note has already been consumed.
#[js_export(js_name = "isConsumed")]
pub fn is_consumed(&self) -> bool {
self.0.is_consumed()
}
/// Returns true if the note is currently being processed.
#[js_export(js_name = "isProcessing")]
pub fn is_processing(&self) -> bool {
self.0.is_processing()
}
/// Converts the record into an `InputNote` (including proof when available).
#[js_export(js_name = "toInputNote")]
pub fn to_input_note(&self) -> Result<InputNote, JsErr> {
let input_note: NativeInputNote = self.0.clone().try_into().map_err(|err| {
js_error_with_context(err, "could not create InputNote from InputNoteRecord")
})?;
Ok(InputNote(input_note))
}
/// Converts the record into a `Note` (including proof when available).
#[js_export(js_name = "toNote")]
pub fn to_note(&self) -> Result<Note, JsErr> {
let note: NativeNote = self.0.clone().try_into().map_err(|err| {
js_error_with_context(err, "could not create InputNote from InputNoteRecord")
})?;
Ok(Note(note))
}
}
// CONVERSIONS
// ================================================================================================
impl From<NativeInputNoteRecord> for InputNoteRecord {
fn from(native_note: NativeInputNoteRecord) -> Self {
InputNoteRecord(native_note)
}
}
impl From<&NativeInputNoteRecord> for InputNoteRecord {
fn from(native_note: &NativeInputNoteRecord) -> Self {
InputNoteRecord(native_note.clone())
}
}
impl_napi_from_value!(InputNoteRecord);