miden_standards/note/config/
min_burn_amount_config.rs1use alloc::vec::Vec;
2
3use miden_protocol::account::AccountId;
4use miden_protocol::assembly::Path;
5use miden_protocol::asset::AssetAmount;
6use miden_protocol::crypto::rand::FeltRng;
7use miden_protocol::errors::NoteError;
8use miden_protocol::note::{
9 Note,
10 NoteAssets,
11 NoteAttachment,
12 NoteAttachments,
13 NoteRecipient,
14 NoteScript,
15 NoteScriptRoot,
16 NoteStorage,
17 NoteTag,
18 NoteType,
19 PartialNoteMetadata,
20};
21use miden_protocol::utils::sync::LazyLock;
22use miden_protocol::{Felt, Word};
23
24use crate::StandardsLib;
25use crate::note::NetworkAccountTarget;
26use crate::note::costs::{MIN_BURN_AMOUNT_CONFIG_CONSUMPTION_CYCLES, NoteConsumptionCost};
27
28const MIN_BURN_AMOUNT_CONFIG_SCRIPT_PATH: &str =
33 "::miden::standards::notes::min_burn_amount_config::main";
34
35static MIN_BURN_AMOUNT_CONFIG_SCRIPT: LazyLock<NoteScript> = LazyLock::new(|| {
37 let standards_lib = StandardsLib::default();
38 let path = Path::new(MIN_BURN_AMOUNT_CONFIG_SCRIPT_PATH);
39 NoteScript::from_package_reference(standards_lib.as_ref(), path)
40 .expect("Standards library contains MIN_BURN_AMOUNT_CONFIG note script procedure")
41});
42
43#[derive(Debug, Clone)]
77pub struct MinBurnAmountConfigNote {
78 sender: AccountId,
79 target: AccountId,
80 min_burn_amount: AssetAmount,
81 serial_number: Word,
82 attachments: NoteAttachments,
83}
84
85#[bon::bon]
86impl MinBurnAmountConfigNote {
87 #[builder]
98 pub fn new(
99 #[builder(field)] mut attachments: Vec<NoteAttachment>,
100 sender: AccountId,
101 target: AccountId,
102 min_burn_amount: AssetAmount,
103 serial_number: Word,
104 ) -> Result<Self, NoteError> {
105 NetworkAccountTarget::ensure_presence(&mut attachments, target).map_err(|err| {
108 NoteError::other_with_source(
109 "failed to bind the MinBurnAmountConfig note to its target account",
110 err,
111 )
112 })?;
113
114 let attachments = NoteAttachments::new(attachments)?;
115
116 Ok(Self {
117 sender,
118 target,
119 min_burn_amount,
120 serial_number,
121 attachments,
122 })
123 }
124}
125
126impl MinBurnAmountConfigNote {
127 pub const NUM_STORAGE_ITEMS: usize = 1;
134
135 pub fn script() -> NoteScript {
140 MIN_BURN_AMOUNT_CONFIG_SCRIPT.clone()
141 }
142
143 pub fn script_root() -> NoteScriptRoot {
145 MIN_BURN_AMOUNT_CONFIG_SCRIPT.root()
146 }
147
148 pub fn sender(&self) -> AccountId {
150 self.sender
151 }
152
153 pub fn target(&self) -> AccountId {
156 self.target
157 }
158
159 pub fn min_burn_amount(&self) -> AssetAmount {
161 self.min_burn_amount
162 }
163
164 pub fn serial_number(&self) -> Word {
166 self.serial_number
167 }
168
169 pub fn attachments(&self) -> &NoteAttachments {
171 &self.attachments
172 }
173}
174
175impl<S: min_burn_amount_config_note_builder::State> MinBurnAmountConfigNoteBuilder<S> {
179 pub fn attachment(mut self, attachment: impl Into<NoteAttachment>) -> Self {
181 self.attachments.push(attachment.into());
182 self
183 }
184
185 pub fn attachments(
187 mut self,
188 attachments: impl IntoIterator<Item = impl Into<NoteAttachment>>,
189 ) -> Self {
190 self.attachments.extend(attachments.into_iter().map(Into::into));
191 self
192 }
193}
194
195impl<S: min_burn_amount_config_note_builder::State> MinBurnAmountConfigNoteBuilder<S>
196where
197 S::SerialNumber: min_burn_amount_config_note_builder::IsUnset,
198{
199 pub fn generate_serial_number(
201 self,
202 rng: &mut impl FeltRng,
203 ) -> MinBurnAmountConfigNoteBuilder<min_burn_amount_config_note_builder::SetSerialNumber<S>>
204 {
205 self.serial_number(rng.draw_word())
206 }
207}
208
209impl From<MinBurnAmountConfigNote> for Note {
213 fn from(note: MinBurnAmountConfigNote) -> Self {
214 let metadata = PartialNoteMetadata::new(note.sender, NoteType::Public)
217 .with_tag(NoteTag::with_account_target(note.target));
218 let storage = NoteStorage::new(vec![Felt::from(note.min_burn_amount)])
219 .expect("number of storage items should not exceed max storage items");
220 let recipient =
221 NoteRecipient::new(note.serial_number, MinBurnAmountConfigNote::script(), storage);
222
223 Note::with_attachments(NoteAssets::default(), metadata, recipient, note.attachments)
224 }
225}
226
227impl NoteConsumptionCost for MinBurnAmountConfigNote {
231 fn consumption_cycles() -> u32 {
232 MIN_BURN_AMOUNT_CONFIG_CONSUMPTION_CYCLES
233 }
234}
235
236#[cfg(test)]
240mod tests {
241 use miden_protocol::account::AccountType;
242 use miden_protocol::crypto::rand::RandomCoin;
243
244 use super::*;
245
246 fn account_id(seed: u8) -> AccountId {
247 AccountId::builder()
248 .account_type(AccountType::Public)
249 .build_with_seed([seed; 32])
250 }
251
252 #[test]
254 fn builder_builds_min_burn_amount_config_note() {
255 let mut rng = RandomCoin::new(Word::empty());
256 let faucet = account_id(1);
257 let sender = account_id(2);
258
259 let note = MinBurnAmountConfigNote::builder()
260 .sender(sender)
261 .target(faucet)
262 .min_burn_amount(AssetAmount::new(100).unwrap())
263 .generate_serial_number(&mut rng)
264 .build()
265 .unwrap();
266
267 assert_eq!(note.sender(), sender);
268 assert_eq!(note.target(), faucet);
269 assert_eq!(note.min_burn_amount(), AssetAmount::new(100).unwrap());
270
271 let note = Note::from(note);
272 assert_eq!(note.metadata().note_type(), NoteType::Public);
273 assert_eq!(note.metadata().tag(), NoteTag::with_account_target(faucet));
274 assert_eq!(note.assets().num_assets(), 0);
275 }
276
277 #[test]
280 fn note_is_bound_to_target_account() {
281 let faucet = account_id(1);
282 let note = MinBurnAmountConfigNote::builder()
283 .sender(account_id(2))
284 .target(faucet)
285 .min_burn_amount(AssetAmount::new(100).unwrap())
286 .serial_number(Word::empty())
287 .build()
288 .unwrap();
289
290 let built = Note::from(note);
291 let target = NetworkAccountTarget::try_from(built.attachments())
292 .expect("note should carry a network account target attachment");
293 assert_eq!(target.target_id(), faucet);
294 }
295
296 #[test]
298 fn storage_layout() {
299 let min_burn_amount = AssetAmount::new(777).unwrap();
300
301 let note = MinBurnAmountConfigNote::builder()
302 .sender(account_id(2))
303 .target(account_id(1))
304 .min_burn_amount(min_burn_amount)
305 .serial_number(Word::empty())
306 .build()
307 .unwrap();
308
309 let built = Note::from(note);
310 assert_eq!(built.storage().items(), [Felt::from(min_burn_amount)]);
311 assert_eq!(built.storage().items().len(), MinBurnAmountConfigNote::NUM_STORAGE_ITEMS);
312 }
313
314 #[test]
317 fn script_root_is_registered_standard_note() {
318 use crate::note::StandardNote;
319
320 let standard = StandardNote::from_script_root(MinBurnAmountConfigNote::script_root())
321 .expect("config note script root should be a registered standard note");
322 assert_eq!(standard.name(), "MIN_BURN_AMOUNT_CONFIG");
323 }
324}