@@ -1114,65 +1114,77 @@ pub(crate) fn create_increment_script() -> Result<NoteScript> {
11141114
11151115/// Build the transaction script for one increment.
11161116///
1117- /// The script does two things atomically in the wallet's transaction:
1118- /// 1. `call`s the wallet's own `increment` procedure, bumping the wallet's on-chain counter slot
1119- /// 2. Emits the network note that targets the counter account (the `observed` value).
1117+ /// The whole transaction is a single `call` into the wallet's `increment_and_create_note` account
1118+ /// procedure, which atomically (1) creates the network note targeting the counter account (the
1119+ /// `observed` value) and (2) bumps the wallet's own on-chain counter slot (the authoritative
1120+ /// `expected` value).
11201121///
1121- /// The note-emission section mirrors `miden_standards`' `build_send_notes_script` for an
1122- /// asset-less note with attachments; it is not reused directly because that builder produces a
1123- /// complete, non-composable script. Keep it in sync with `miden-standards` on version bumps; the
1124- /// `wallet_self_increment_tx` test exercises it end-to-end.
1122+ /// The note attachments (the `NetworkAccountTarget`) are added afterwards with
1123+ /// `output_note::add_attachment`, which is not account-restricted, mirroring `miden_standards`'
1124+ /// `SendNotesTransactionScript`. The `wallet_self_increment_tx` test exercises this end-to-end.
11251125fn create_increment_tx_script ( network_note : & Note ) -> Result < TransactionScript > {
1126- let wallet_program = include_str ! ( concat!(
1127- env!( "CARGO_MANIFEST_DIR" ) ,
1128- "/src/assets/wallet_counter_program.masm"
1129- ) ) ;
1126+ let wallet_component = crate :: deploy:: wallet:: wallet_counter_component_code ( )
1127+ . context ( "failed to compile wallet counter component code" ) ?;
11301128
11311129 let partial: PartialNote = network_note. clone ( ) . into ( ) ;
11321130 let recipient = partial. recipient_digest ( ) ;
11331131 let note_type = Felt :: from ( partial. metadata ( ) . note_type ( ) ) ;
11341132 let tag = Felt :: from ( partial. metadata ( ) . tag ( ) ) ;
11351133
1134+ // The wallet's own account procedure creates the note *and* bumps the counter atomically, so
1135+ // the whole transaction is a single `call` into the wallet component.
1136+ // `increment_and_create_note` shares `create_note`'s stack contract: it consumes `[tag,
1137+ // note_type, RECIPIENT, pad(10)]` and returns `[note_idx, pad(15)]`. We build the padded input
1138+ // explicitly and reduce the trailing pads back to `[note_idx]`, otherwise the extra pads
1139+ // survive on the overflow stack and `main` returns with the wrong depth ("stack depth must be
1140+ // 16, but was 21").
1141+ let increment_and_create_note = format ! (
1142+ "::{}::increment_and_create_note" ,
1143+ crate :: deploy:: wallet:: WALLET_COUNTER_COMPONENT_PATH
1144+ ) ;
11361145 let mut note_section = format ! (
11371146 "
1147+ padw padw push.0.0
11381148 push.{recipient}
11391149 push.{note_type}
11401150 push.{tag}
1141- # => [tag, note_type, RECIPIENT, pad(16)]
1142- exec.::miden::protocol::output_note::create
1143- # => [note_idx, pad(16)]
1151+ # => [tag, note_type, RECIPIENT, pad(10)]
1152+ call.{increment_and_create_note}
1153+ # => [note_idx, pad(15)]
1154+ movdn.15 dropw dropw dropw drop drop drop
1155+ # => [note_idx]
11441156 "
11451157 ) ;
11461158 for attachment in partial. attachments ( ) . iter ( ) {
11471159 let scheme = attachment. attachment_scheme ( ) . as_u16 ( ) ;
11481160 let commitment = attachment. content ( ) . to_commitment ( ) ;
1161+ // `add_attachment` consumes `[attachment_scheme, ATTACHMENT_COMMITMENT, note_idx]`, so dup
1162+ // the note index for it to consume and keep our own copy for the next attachment / drop.
11491163 write ! (
11501164 note_section,
11511165 "
11521166 dup
11531167 push.{commitment}
11541168 push.{scheme}
1169+ # => [attachment_scheme, ATTACHMENT_COMMITMENT, note_idx, note_idx]
11551170 exec.::miden::protocol::output_note::add_attachment
1156- # => [note_idx, pad(16) ]
1171+ # => [note_idx]
11571172 "
11581173 )
11591174 . expect ( "writing to a String cannot fail" ) ;
11601175 }
11611176 note_section. push_str ( " drop\n " ) ;
11621177
11631178 let script_src = format ! (
1164- "use external_contract::wallet_counter
1165-
1166- @transaction_script
1179+ "@transaction_script
11671180 pub proc main
1168- call.wallet_counter::increment
11691181{note_section}
11701182 end"
11711183 ) ;
11721184
11731185 let mut code_builder = CodeBuilder :: new ( )
1174- . with_linked_module ( "external_contract::wallet_counter" , wallet_program )
1175- . context ( "Failed to link wallet counter module " ) ?;
1186+ . with_dynamically_linked_library ( & wallet_component )
1187+ . context ( "Failed to dynamically link wallet counter component " ) ?;
11761188
11771189 // The note's attachments (e.g. the network-account target) are resolved at runtime from the
11781190 // advice map keyed by their commitment, matching `build_send_notes_script`.
0 commit comments