1use alloc::{string::String, vec::Vec};
2
3use miden_lib::transaction::{TransactionKernel, memory};
4use miden_objects::{
5 account::AccountId,
6 asset::Asset,
7 note::Note,
8 testing::{note::NoteBuilder, storage::prepare_assets},
9};
10use miden_tx::utils::word_to_masm_push_string;
11use rand::{SeedableRng, rngs::SmallRng};
12use vm_processor::Felt;
13
14pub fn input_note_data_ptr(note_idx: u32) -> memory::MemoryAddress {
18 memory::INPUT_NOTE_DATA_SECTION_OFFSET + note_idx * memory::NOTE_MEM_SIZE
19}
20
21pub fn create_p2any_note(sender: AccountId, assets: &[Asset]) -> Note {
31 let mut code_body = String::new();
32 for i in 0..assets.len() {
33 if i == 0 {
34 code_body.push_str(
36 "
37 # add first asset
38
39 padw dup.4 mem_loadw
40 padw swapw padw padw swapdw
41 call.wallet::receive_asset
42 dropw movup.12
43 # => [dest_ptr, pad(12)]
44 ",
45 );
46 } else {
47 code_body.push_str(
48 "
49 # add next asset
50
51 add.4 dup movdn.13
52 padw movup.4 mem_loadw
53 call.wallet::receive_asset
54 dropw movup.12
55 # => [dest_ptr, pad(12)]",
56 );
57 }
58 }
59 code_body.push_str("dropw dropw dropw dropw");
60
61 let code = format!(
62 "
63 use.test::account
64 use.miden::note
65 use.miden::contracts::wallets::basic->wallet
66
67 begin
68 # fetch pointer & number of assets
69 push.0 exec.note::get_assets # [num_assets, dest_ptr]
70
71 # runtime-check we got the expected count
72 push.{num_assets} assert_eq # [dest_ptr]
73
74 {code_body}
75 dropw dropw dropw dropw
76 end
77 ",
78 num_assets = assets.len(),
79 );
80
81 NoteBuilder::new(sender, SmallRng::from_seed([0; 32]))
82 .add_assets(assets.iter().copied())
83 .code(code)
84 .build(&TransactionKernel::testing_assembler_with_mock_account())
85 .expect("generated note script should compile")
86}
87
88pub fn create_spawn_note(sender_id: AccountId, output_notes: Vec<&Note>) -> anyhow::Result<Note> {
93 let note_code = note_script_that_creates_notes(output_notes);
94
95 let note = NoteBuilder::new(sender_id, SmallRng::from_os_rng())
96 .code(note_code)
97 .build(&TransactionKernel::testing_assembler_with_mock_account())?;
98
99 Ok(note)
100}
101
102fn note_script_that_creates_notes(output_notes: Vec<&Note>) -> String {
104 let mut out = String::from("use.miden::tx\nuse.test::account\n\nbegin\n");
105
106 for (idx, note) in output_notes.iter().enumerate() {
107 if idx == 0 {
108 out.push_str("padw padw\n");
109 } else {
110 out.push_str("dropw dropw dropw\n");
111 }
112 let assets_str = prepare_assets(note.assets());
113 out.push_str(&format!(
114 " push.{recipient}
115 push.{hint}
116 push.{note_type}
117 push.{aux}
118 push.{tag}
119 call.tx::create_note\n",
120 recipient = word_to_masm_push_string(¬e.recipient().digest()),
121 hint = Felt::from(note.metadata().execution_hint()),
122 note_type = note.metadata().note_type() as u8,
123 aux = note.metadata().aux(),
124 tag = note.metadata().tag(),
125 ));
126
127 for asset in assets_str {
128 out.push_str(&format!(
129 " push.{asset}
130 call.tx::add_asset_to_note\n",
131 ));
132 }
133 }
134
135 out.push_str("repeat.5 dropw end\nend");
136 out
137}