Documentation
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
# Migration Guide

This guide explains how to update Rust code and project configuration written against the Miden
SDK (the `miden` crate) and compiler when upgrading between released versions. Each section covers
one release step and shows the concrete *before*/*after* edits a breaking change requires.

The most recent migration is at the top. When cutting a new release, add its migration section
directly below this paragraph, above the previous one (newest first, like the
[CHANGELOG](./CHANGELOG.md)).

<!-- Add the next migration section here, above `## Unreleased`. -->

## Unreleased

### Transaction summaries are six words (protocol 0.16)

Custom authentication components sign a commitment to the transaction summary. Protocol 0.16
extends the summary from four words to six: it now also binds the reference block commitment,
the transaction's expiration block delta, and seven user-defined parameters. The host rebuilds
the summary from the advice-map preimage and rejects the signing request unless its commitment
matches, so a component that still hashes the old four-word layout fails at runtime with
`TransactionSummaryConstructionFailed` even though it compiles unchanged.

Build the six words in this order and place the final nonce in the first user parameter, as the
standards components do:

Before:

```rust
let salt = Word::from([felt!(0), felt!(0), ref_block_num.into(), final_nonce.into()]);
let tx_summary = [acct_delta_commit, input_notes_commit, output_notes_commit, salt];
let msg: Word = hash_words(&tx_summary).into();
adv_insert(msg, &tx_summary);
```

After:

```rust
let block_commit = tx::get_block_commitment();
let expiration_delta = tx::get_expiration_block_delta();

// [expiration_delta, user_param0..2] and [user_param3..6]; the first user parameter carries
// the final nonce for replay protection.
let params_head = Word::from([expiration_delta.into(), final_nonce.into(), felt!(0), felt!(0)]);
let params_tail = Word::from([felt!(0), felt!(0), felt!(0), felt!(0)]);

let tx_summary = [
    acct_delta_commit,
    input_notes_commit,
    output_notes_commit,
    block_commit,
    params_head,
    params_tail,
];
let msg: Word = hash_words(&tx_summary).into();
adv_insert(msg, &tx_summary);
```

See `examples/auth-component-rpo-falcon512` for the complete component.

### Attachment setter aliases are removed

`output_note::set_word_attachment` and `output_note::set_array_attachment` are removed. They
were aliases from the protocol 0.15 rename, and their names promised replace semantics the
transaction kernel does not have: attachments are append-only.

Before:

```rust
output_note::set_word_attachment(note_idx, scheme, word);
output_note::set_array_attachment(note_idx, scheme, attachment_commitment);
```

After:

```rust
output_note::add_word_attachment(note_idx, scheme, word);
output_note::add_attachment(note_idx, scheme, attachment_commitment);
```

Both functions take a `Word`: `add_word_attachment` takes the attachment value itself, and
`add_attachment` takes a commitment to attachment elements that the advice map holds. If your
code holds the attachment contents as words in memory, call
`output_note::add_attachment_from_memory(note_idx, scheme, &words)` instead.

### `#[note]` reserves `get_entrypoint_root`

The `#[note]` macro now generates a `get_entrypoint_root()` associated method on the note type so
constructors can commit to the note script's MAST root. Rename any inherent item with that name,
including methods, `#[note_constructor]` methods, associated constants, and items declared in a
separate impl block.

### Contract crates gain a `build.rs` for IDE and plain-cargo builds

New projects created by `cargo miden new` include a small `build.rs` in each contract crate and a
build dependency on `miden-sdk-build-script-support` at the same version as the SDK. The script
delegates to [`prepare_package_cache`](https://docs.rs/miden-sdk-build-script-support/latest/miden_sdk_build_script_support/fn.prepare_package_cache.html),
which makes plain `cargo check`, `cargo build`, and IDE analysis (rust-analyzer) resolve compiled
dependency packages: outside a `cargo miden build`, it stages package-cache
generations under its `OUT_DIR`, fills a private generation with a nested
`cargo miden build --release` that adopts it through `MIDENC_PACKAGE_CACHE`, and exports the
same variable to the crate's macro expansion. Inside a midenc-driven build the script does
nothing: the compiler exchanges packages with its nested builds through a directory of its
own, which it deletes when the build ends.

The nested build runs whenever Cargo re-runs the script. The compiler writes a versioned input
record next to the staged packages. Inputs a frontend can enumerate completely — local MASM
source trees and preassembled packages, for example — become selective Cargo change directives
when the cargo-miden launcher and Miden workspace boundary are also explicit. Rust/Cargo source
dependencies, launchers resolved through `PATH`, and packages whose future parent workspace
cannot be watched completely are marked opaque; those graphs deliberately re-stage dependencies
on every relevant Cargo invocation instead of risking stale metadata. Set `CARGO_MIDEN` to an
explicit binary path and build from an established Miden workspace to enable selective behavior
for an otherwise-complete dependency graph.

The build script is now required for plain cargo builds of crates with Miden source
dependencies. The SDK macros read dependency packages only from the `MIDENC_PACKAGE_CACHE`
directory (or from a manifest path naming a `.masp` file directly); they no longer search
`target/miden/<profile>` output directories, so a plain `cargo check` without the script fails
with instructions instead of finding previously built artifacts. Add the support crate and the
following wrapper to every contract crate (using the same version requirement as `miden`):

```toml
[build-dependencies]
miden-sdk-build-script-support = "0.14.0-rc.1"
```

```rust
fn main() {
    miden_sdk_build_script_support::prepare_package_cache();
}
```

The helper needs `cargo miden` on `PATH`; set the `CARGO_MIDEN` environment variable to use a
specific `cargo-miden` binary instead. A missing tool fails the build script with an install
hint.

Each successful staging run publishes an immutable content-addressed generation. Changed
generations remain until Cargo removes `OUT_DIR`, so an IDE expansion that still references an
older path continues to see one coherent dependency set; byte-identical staging reuses the
existing generation. If the nested `cargo miden build` fails, the outer check fails with its error
rather than compiling against stale dependency metadata.

One sharing caveat: cargo keys build-script output by crate name and version, not by project
path. Two different projects that contain a contract crate with the same package name and
version and share one `CARGO_TARGET_DIR` reuse each other's build-script output — including
the staged package cache. Use per-checkout target directories for such layouts.

### Kernel scalars are typed instead of `Felt` (counts, block heights, nonces, attachments)

Binding surfaces whose values are counts now return `u32`: `tx::get_num_input_notes`,
`tx::get_num_output_notes`, `active_account::get_num_procedures`, and the
`num_assets` / `num_storage_items` fields of the note info structs. Matching this,
`active_account::get_procedure_root` takes the procedure index as `u32` (previously `u8`), so
count-driven loops index directly. Code that compared or computed with these as felts now works
with plain integers:

```rust
// before
let all_consumed: Felt = tx::get_num_input_notes();
assert_eq!(all_consumed, felt!(2));

// after
let all_consumed: u32 = tx::get_num_input_notes();
assert_eq!(all_consumed, 2);
```

Block heights are wrapped in the new `BlockNumber` type (comparable as integers; heights read
from note storage convert with the validated `BlockNumber::try_from(felt)`), block timestamps
are `u32` seconds, and expiration deltas are `u16`:

```rust
// before
let timelock_height: Felt = inputs[3];
assert!(tx::get_block_number() >= timelock_height);
tx::update_expiration_block_delta(Felt::new(42).unwrap());

// after
let timelock_height = BlockNumber::try_from(inputs[3]).unwrap();
assert!(tx::get_block_number() >= timelock_height);
tx::update_expiration_block_delta(42);
```

Account nonces are wrapped in the new `Nonce` type (comparable as integers; use
`as_felt()`/`as_u64()` or `Felt::from(nonce)` where the raw value is needed, e.g. when packing a
nonce into a `Word` — `ref_block_num` below is a `BlockNumber` from `tx::get_block_number()` and
converts the same way):

```rust
// before
let final_nonce: Felt = self.incr_nonce();
let params = Word::from([felt!(0), felt!(0), ref_block_num, final_nonce]);

// after
let final_nonce: Nonce = self.incr_nonce();
let params = Word::from([felt!(0), felt!(0), ref_block_num.into(), final_nonce.into()]);
```

This example shows only the type conversions. Do not reuse the word layout: protocol 0.16
replaces the four-word transaction summary that packed the nonce this way — see
[Transaction summaries are six words (protocol 0.16)](#transaction-summaries-are-six-words-protocol-016)
at the top of this guide for the required six-word layout.

Attachment lookups return `Option<u32>` instead of the removed `AttachmentLocation` struct, and
attachment indexes are passed as `u32`:

```rust
// before
let location = active_note::find_attachment(scheme);
if location.found() {
    let attachment = active_note::write_attachment_to_memory(location.index);
}

// after
if let Some(index) = active_note::find_attachment(scheme) {
    let attachment = active_note::write_attachment_to_memory(index);
}
```

### Typed transaction-script arguments

`#[tx_script]` entrypoints now receive typed script arguments decoded from the `TX_SCRIPT_ARGS`
word. Existing `fn run(arg: Word, ...)` entrypoints keep compiling and behave unchanged (`Word`
decodes as itself), so no edit is required — but scripts that manually fetch their arguments from
the advice provider can delete that plumbing: declare a struct deriving
`FromFeltRepr`/`ToFeltRepr` and take it by value. The entrypoint may have any name and accept
the script-args and account parameters in any order (the account reference is optional);
encodings of at most 4 felts
travel in the args word directly, longer or variable-length ones travel through the advice
provider, hash-verified against the args word. The derives' generated code refers to the
`miden_field_repr` crate, which the `miden` crate re-exports under its own name: `use miden::*;`
makes it resolve. A module that does not glob-import `miden` needs `use miden::miden_field_repr;`
(or a direct `miden-field-repr` dependency) alongside the struct.

Before:

```rust
use miden::{intrinsics::advice::adv_push_mapvaln, *};

#[tx_script]
fn run(arg: Word, account: &mut Wallet) {
    let num_felts = adv_push_mapvaln(arg);
    let num_felts_u64 = num_felts.as_canonical_u64();
    assert_eq(Felt::from_u32((num_felts_u64 % 4) as u32), felt!(0));
    let num_words = Felt::new(num_felts_u64 / 4).unwrap();
    let input = adv_load_preimage(num_words, arg);
    let tag = input[0];
    let note_type = input[1];
    let recipient: [Felt; 4] = input[2..6].try_into().unwrap();
    let note_idx = account.create_note(tag.into(), note_type.into(), recipient.into());
    // ...
}
```

After:

```rust
use miden::*;

/// Arguments of the transaction script, transported via the `TX_SCRIPT_ARGS` word.
#[derive(FromFeltRepr, ToFeltRepr)]
pub struct TxScriptArgs {
    pub tag: Tag,
    pub note_type: NoteType,
    pub recipient: Recipient,
}

#[tx_script]
fn run(args: TxScriptArgs, account: &mut Wallet) {
    let note_idx = account.create_note(args.tag, args.note_type, args.recipient);
    // ...
}
```

On the host, build the transaction with `ScriptArgs::encode` on a mirror struct that reproduces
the guest type's *felt-repr wire sequence* — the felts, in order; the Rust fields may differ, e.g.
a guest `Asset` field can be mirrored as its key and value `Word`s (sharing the schema through
the Miden package is planned). Pin the mirror against drift: assert its
`<Mirror as ScriptArgs>::FIXED_LEN` equals the guest type's, and ideally assert a golden encoding
with distinct sentinel values, which also catches same-length field reorders. This matters
because one drift direction fails silently: if the guest type is word mode and the mirror grows
past 4 felts, the host switches to commitment mode and the guest decodes the hash limbs as
argument values. The trait lives in the `miden-tx-script-args` crate, whose off-chain
dependencies are only `miden-field` and `miden-field-repr` — host code does not need the
on-chain SDK.

`EncodedScriptArgs` carries `miden-field` felts, while the protocol crates use their own felt
type — convert between them via `as_canonical_u64`:

```rust
/// Converts `miden-field` felts into the protocol crate's felt type.
fn to_protocol_felts(felts: &[miden_field::Felt]) -> Vec<Felt> {
    felts.iter().map(|felt| Felt::new_unchecked(felt.as_canonical_u64())).collect()
}

match script_args.encode() {
    // Word mode: the encoding is the script-args word; no advice map involved.
    EncodedScriptArgs::Word(word) => builder.tx_script_args(Word::new(
        [0, 1, 2, 3].map(|i| Felt::new_unchecked(word[i].as_canonical_u64())),
    )),
    // Commitment mode: hash the preimage into the script-args word and register the
    // advice-map entry (Poseidon2 is the Miden VM's native hash).
    EncodedScriptArgs::Preimage(felts) => {
        let preimage = to_protocol_felts(&felts);
        let args_word = Poseidon2::hash_elements(&preimage);
        builder.tx_script_args(args_word).extend_advice_map([(args_word, preimage)])
    }
}
```

### Mark account interface procedures with `#[account_procedure]`

A component's methods are no longer implicitly part of the account interface. Mark every method that
must be callable as an account procedure — from transaction scripts, notes, foreign procedure
invocation (FPI), or sibling components — with `#[account_procedure]` on the `#[component]` **trait**
declaration (not the `impl`). Any number of methods may be marked. Unmarked methods still compile
and are still exported, but are not account procedures.

`#[auth_script]` and `#[account_procedure]` belong to different component kinds — an authentication
component versus a regular account component — and cannot be combined in one component. An
authentication component keeps using `#[auth_script]` alone (its method is the account interface
implicitly).

The `#[account_procedure]` marker is recognized by the surrounding `#[component]` macro, so it needs
no import (just like `#[auth_script]`).

Before:

```rust
use miden::{Asset, component, component_storage};

#[component]
trait BasicWallet {
    fn receive_asset(&mut self, asset: Asset);
}
```

After:

```rust
use miden::{Asset, component, component_storage};

#[component]
trait BasicWallet {
    #[account_procedure]
    fn receive_asset(&mut self, asset: Asset);
}
```

### `#[account(...)]` generates one trait per component

In 0.13 the `#[account(...)]` macro generated each component's methods as inherent methods on the
wrapper struct. In 0.14 it generates **one trait per referenced interface** (named after the
interface, with the wrapper's visibility) and implements it for the wrapper, so two components that
export the same method name can coexist on one wrapper. Single-component accounts keep calling
`account.method(..)` unchanged **when the generated trait is in scope** — a same-module
`#[note]`/`#[tx_script]` entrypoint sees it automatically, but a call site in a different module
than the wrapper needs `use` of the generated trait (e.g. `use crate::BasicWallet;`).

Because the methods are now on a generated trait, a referenced interface must export at least one
method: `#[account(...)]` now errors if a selected interface has no callable exports, where 0.13
silently generated nothing for it.

**The wrapper struct must be named differently from every generated trait.**
`#[account(counter_contract::CounterContract)] struct CounterContract;` no longer compiles; rename
the struct (e.g. `Counter`):

```rust
#[account(counter_contract::CounterContract)]
struct Counter;

let counter = Counter::new(counter_account_id);
let count = counter.get_count();
```

**Shared method names are disambiguated with UFCS.** When an account derives two components that
export the same method name — or a component method shares a name with an `ActiveAccount` built-in
such as `get_id` — the bare call is ambiguous:

```rust
#[account(basic_wallet::BasicWallet, vault::Vault)]
struct Wallet;

// both BasicWallet and Vault export `deposit`:
<Wallet as BasicWallet>::deposit(account, asset);
<Wallet as Vault>::deposit(account, asset);
```

Generated component traits are same-module, so `<Wallet as Interface>::…` needs no import. The
`ActiveAccount` built-in trait, however, is not in the `miden::*` prelude, so disambiguating a
component method against a built-in needs an explicit import:

```rust
use miden::active_account::ActiveAccount;

// a component method named `get_id` shares the `ActiveAccount::get_id` name:
<Wallet as CounterContract>::get_id(account); // the component method
<Wallet as ActiveAccount>::get_id(account);   // the built-in
```

For the same reason, a component method named `new` is now permitted (it was previously rejected):
it lives on the generated trait and coexists with the inherent `Wallet::new(account_id)`
constructor — `Wallet::new(id)` resolves to the constructor, `wallet.new()` to the component method.

**Name clashes between generated traits are resolved with `as`.** When the generated trait *name*
would clash — the struct shares the interface name, two packages export the same interface name,
two separate `#[account]` wrappers in one module select the same interface, or the crate already
uses the interface as a sibling `#[component(...)]` — rename the generated trait with `as` (the path
still selects the interface):

```rust
// a component that both calls a sibling counter and reaches a remote counter through FPI:
#[account(counter_contract::CounterContract as RemoteCounter)] // FPI trait `RemoteCounter`
struct Remote;

#[component(counter_contract::CounterContract)]                // sibling trait `CounterContract`
trait Caller: NativeAccount + CounterContract { /* ... */ }
```

### Tx-kernel bindings: protocol 0.16.0-beta.1

The SDK bindings were aligned with VM v0.25 / protocol 0.16.0-beta.1. Several tx-kernel bindings
were renamed, moved, or removed to match the protocol procedures.

**The "initial asset" getters are renamed.** They read the note's assets at creation time,
unaffected by any in-transaction removal, so the names now say so:

```rust
// before                              // after
active_note::get_assets();             active_note::get_initial_assets();
input_note::get_assets(idx);           input_note::get_initial_assets(idx);
input_note::get_assets_info(idx);      input_note::get_initial_assets_info(idx);
```

**`active_account::has_non_fungible_asset` became `has_asset`** and now takes an asset id `Word`
instead of an `Asset`, testing membership of any asset (fungible or non-fungible) by id:

```rust
// before
if account.has_non_fungible_asset(asset) { /* ... */ }
// after
if account.has_asset(asset.key) { /* ... */ }
```

**The initial-state getters moved from `active_account` to `native_account`.**
`get_initial_commitment`, `get_initial_storage_commitment`, `get_initial_vault_root`, and
`get_initial_asset` are now free functions on `native_account` (they are no longer `ActiveAccount`
trait methods). `storage::{get_initial_item, get_initial_map_item}` keep their API but now read the
native account's initial state.

```rust
// before (ActiveAccount trait method)
let init = self.get_initial_commitment();
let asset = self.get_initial_asset(asset_key);
// after (native_account free function)
let init = miden::native_account::get_initial_commitment();
let asset = miden::native_account::get_initial_asset(asset_key);
```

**In-transaction asset construction and balance getters were removed.**

- `active_account::{get_balance, get_initial_balance}` are gone. Read the asset value word with
  `active_account::get_asset` (or `native_account::get_initial_asset`) and extract the fungible
  amount from the returned `AssetValue` word (see the protocol `fungible_value_into_amount`
  helper).
- `faucet::{create_fungible_asset, create_non_fungible_asset, has_callbacks}` and the whole
  `asset` module (`asset::{create_fungible_asset, create_non_fungible_asset}`) are gone. The kernel
  no longer exposes in-transaction asset construction; `faucet::{mint, burn}` take a pre-built
  `Asset`.

**`output_note::create` is account-context only.** It can now only be called from account-component
context (runtime-enforced). Tx/note scripts must create notes through an account component wrapper
method (see the `basic-wallet` example's `create_note`).

### `#[note]` structs now also implement `ToFeltRepr`

`#[note]` on a struct now generates a `felt_repr::ToFeltRepr` impl encoding the note inputs in
field order (mirroring the generated `TryFrom<&[Felt]>` decoding), so note constructors can
serialize the inputs when computing the note recipient.

Both directions are generated by the macro — do not add `FromFeltRepr`/`ToFeltRepr` derives to
the note struct itself. For the typical note struct, whose fields are SDK-provided types
(`Felt`, `AccountId`, primitives, ...), upgrading requires no changes.

Changes are only required if:

1. The note type has a manual `ToFeltRepr` impl: remove it — it now conflicts with the
   generated impl. If its encoding differed from the generated field-order encoding, move the
   logic to a differently named helper method instead.

2. A field has a custom type that only implements `FromFeltRepr`: that field type (not the note
   struct) must now also implement `ToFeltRepr`, e.g. via `#[derive(ToFeltRepr)]` next to its
   existing `FromFeltRepr`.

### Component WIT is embedded in the compiled package

The component WIT generated by `#[component]` is now embedded in the compiled Miden package (a
`wit` section of the `.masp`) instead of being written to `target/generated-wit/`. The
`#[account(...)]`, sibling `#[component(pkg::Interface)]`, `#[note]`, and `#[tx_script]` macros
read dependency WIT from the dependency's compiled `.masp`, and every Miden path dependency must
be a built package (cargo-miden builds path dependencies automatically; a dependency that points
directly at a prebuilt `.masp` file is self-contained).

Remove the `wit = "..."` entries from `[package.metadata.miden.dependencies]` in
`miden-project.toml` for dependencies whose packages embed WIT — a leftover key is now an error
("remove the `wit` key"). The key remains available as an escape hatch for dependency packages
*without* embedded WIT (e.g. produced by another toolchain); it must point at a single
self-contained `.wit` file, or a directory containing exactly one top-level `.wit` file.

Before:

```toml
[dependencies]
basic-wallet = { path = "../basic-wallet" }

[package.metadata.miden.dependencies]
basic-wallet = { wit = "../basic-wallet/target/generated-wit/" }
```

After:

```toml
[dependencies]
basic-wallet = { path = "../basic-wallet" }
```

A `.masp` built by an older SDK has no embedded WIT: the macros skip it, and a macro that
references it reports the missing interface at the reference site; rebuild each dependency with
the current toolchain (`cargo miden build`), or supply the WIT manually via the `wit` key as
above. Components written
without the `#[component]` macro — a hand-written `wit/` directory and a bare
`miden::generate!()` — embed their WIT automatically when the `wit/` directory contains a single
`.wit` file, so no changes are needed there. WIT split across multiple files, or referencing
packages under `wit/deps/` other than the bundled SDK WIT, cannot be embedded verbatim yet;
consolidate it into one self-contained file if the component is consumed as a Miden dependency.

Note for the editor workflow: previously, `cargo check` (or rust-analyzer) of the dependency crate
regenerated its WIT under `target/generated-wit` as a macro side effect. Dependency WIT now comes
from the compiled package. A consumer crate carrying the contract `build.rs` (see "Contract
crates gain a `build.rs`" above) rebuilds its dependencies automatically; without the script,
run `cargo miden build` for the dependency once (and again after changing its interface) before
checking a dependent crate.

## 0.13.0 -> 0.13.1

### `*_note::get_metadata` returns a single-word `NoteMetadata`

`get_metadata` no longer includes the note attachment word — it returns only the metadata header,
and `NoteMetadata` is now a single-field struct `{ header: Word }`. Retrieve attachments through the
dedicated attachment procedures instead.

```rust
// before — NoteMetadata { attachment: Word, header: Word }
let meta = active_note::get_metadata();
let attachment = meta.attachment;
let header = meta.header;

// after — NoteMetadata { header: Word }
let meta = active_note::get_metadata();
let header = meta.header;
// attachments are now retrieved separately:
let attachments_commitment = active_note::get_attachments_commitment();
```

## 0.12.0 -> 0.13.0

This release reworks how account components, accounts, and authentication are declared, introduces
a required `miden-project.toml` project manifest, and aligns the tx-kernel bindings with
VM v0.23 / protocol v0.15. The macro changes touch every account component, every authentication
component, and every note/tx-script that references an account. Work through the sections in order:
rewrite the component (1), add the project manifest (2), update account references (3), then the
bindings (4).

### 1. Account and authentication components: `#[component]` is now a trait + a storage struct

`#[component]` no longer applies to a `struct` or an inherent `impl`. An account component is now
three pieces:

1. a `#[component_storage]` struct holding the `#[storage(...)]` fields,
2. a `#[component]` **trait** declaring the API (the trait name yields the WIT interface), and
3. a `#[component] impl Trait for Storage` block providing the behavior.

Method receivers (`&self` / `&mut self`) and method bodies are unchanged.

Before (0.12.0):

```rust
use miden::{component, felt, Felt, StorageMap, Word};

#[component]
struct CounterContract {
    #[storage(description = "counter contract storage map")]
    count_map: StorageMap<Word, Felt>,
}

#[component]
impl CounterContract {
    pub fn get_count(&self) -> Felt {
        let key = Word::new([felt!(0), felt!(0), felt!(0), felt!(1)]);
        self.count_map.get(key)
    }

    pub fn increment_count(&mut self) -> Felt {
        let key = Word::new([felt!(0), felt!(0), felt!(0), felt!(1)]);
        let new_value = self.count_map.get(key) + felt!(1);
        self.count_map.set(key, new_value);
        new_value
    }
}
```

After (0.13.0):

```rust
use miden::{component, component_storage, felt, Felt, StorageMap, Word};

// 1. storage fields move to a `#[component_storage]` struct
#[component_storage]
struct CounterContractStorage {
    #[storage(description = "counter contract storage map")]
    count_map: StorageMap<Word, Felt>,
}

// 2. the API becomes a `#[component]` trait (its name is the WIT interface)
#[component]
trait CounterContract {
    fn get_count(&self) -> Felt;
    fn increment_count(&mut self) -> Felt;
}

// 3. the behavior is a `#[component] impl Trait for Storage` block
#[component]
impl CounterContract for CounterContractStorage {
    fn get_count(&self) -> Felt {
        let key = Word::new([felt!(0), felt!(0), felt!(0), felt!(1)]);
        self.count_map.get(key)
    }

    fn increment_count(&mut self) -> Felt {
        let key = Word::new([felt!(0), felt!(0), felt!(0), felt!(1)]);
        let new_value = self.count_map.get(key) + felt!(1);
        self.count_map.set(key, new_value);
        new_value
    }
}
```

**Authentication components migrate the same way.** `#[auth_script]` was already required in
0.12.0; in 0.13.0 it simply moves onto the trait method declaration (the `impl` method no longer
repeats it):

```rust
// before (0.12.0): inherent impl
#[component]
struct AuthComponent;
#[component]
impl AuthComponent {
    #[auth_script]
    pub fn auth_procedure(&mut self, _arg: Word) { /* ... */ }
}

// after (0.13.0): trait + storage, `#[auth_script]` on the trait method
#[component_storage]
struct AuthComponentStorage;
#[component]
trait AuthComponent {
    #[auth_script]
    fn auth_procedure(&mut self, _arg: Word);
}
#[component]
impl AuthComponent for AuthComponentStorage {
    fn auth_procedure(&mut self, _arg: Word) { /* ... */ }
}
```

### 2. `miden-project.toml` is now a required file

0.13.0 introduces a dedicated project manifest, `miden-project.toml`, placed next to `Cargo.toml`
at the crate root. The Miden-specific configuration that previously lived in `Cargo.toml`
`[package.metadata.*]` now lives here, and the proc-macros read it to resolve the WIT interface
name, the project kind, and any FPI/sibling dependencies. **Building a 0.13.0 project without it
fails** (for components, with an undefined `::init` link error).

Create `miden-project.toml` like this (account component without dependencies):

```toml
[package]
name = "counter-contract"   # crate name; kebab-case
version = "0.1.0"           # project version; supplies the WIT `@version`

[lib]
kind = "account-component"  # project kind: "account-component" | "note" | "tx-script"
# Full WIT id: miden:<package>/<interface>@<version>
#   <package>   = the kebab-cased [package].name
#   <interface> = the kebab-cased `#[component]` trait name  (here: `CounterContract`)
#   <version>   = the [package].version above
namespace = "miden:counter-contract/counter-contract@0.1.0"

[dependencies]
miden-core = "*"
miden-protocol = "*"

# account components only: which account types may host this component
[package.metadata.miden]
supported-types = ["RegularAccountUpdatableCode"]
```

Walking through the fields:

- **`[package]`**`name` and `version`. The version feeds the `@version` suffix of the WIT id,
  so bumping it changes the component's interface id.
- **`[lib].kind`** — the project kind: `account-component`, `note`, or `tx-script`.
- **`[lib].namespace`** — the full `miden:<package>/<interface>@<version>` WIT id. The
  **interface segment must equal the kebab-cased `#[component]` trait name**; a mismatch fails to
  link with an undefined `::init`. (For `note`/`tx-script` projects, the interface segment is the
  project's own name rather than a component trait.)
- **`[dependencies]`** — the Miden crates the project links against (`miden-core`,
  `miden-protocol`), plus any FPI/sibling dependency packages by `path` (see section 3).
- **`[package.metadata.miden].supported-types`** — account components only.

> **Storage-slot caution.** Storage slot names derive from the `[lib].namespace` interface
> segment (which mirrors the component trait name), and slot names feed `StorageSlotId` derivation.
> Renaming the component trait (and updating `[lib].namespace` to match) **re-keys the storage
> slot ids of an already-deployed component**. Keep the trait name stable across upgrades of a
> live component.

For a project that calls another account/component (FPI or sibling), add the dependency in both
`[dependencies]` (the package) and `[package.metadata.miden.dependencies]` (its generated WIT):

```toml
[dependencies]
miden-core = "*"
miden-protocol = "*"
basic-wallet = { path = "../basic-wallet" }

# the dependency's generated WIT, used to generate the call bindings
[package.metadata.miden.dependencies]
basic-wallet = { wit = "../basic-wallet/target/generated-wit/" }
```

The `[package.metadata.miden.dependencies].<name>.wit` entry is what the macros read to generate
the typed call bindings, and it is the **same entry used by note scripts, by account components
doing FPI, and by sibling component calls**.

### 3. Accounts: declare `#[account(...)]` explicitly with an interface

The auto-generated `crate::bindings::Account` struct is gone. Declare the account explicitly with
`#[account(...)]` and use that type as the note/tx-script entrypoint account parameter. The
dependency reference now **requires the exported WIT interface** (kebab-cased and validated):
write `#[account(basic_wallet::BasicWallet)]`, not `#[account(basic_wallet)]`.

Before (0.12.0):

```rust
use miden::{active_note, note, AccountId, Word};
use crate::bindings::Account; // auto-generated

#[note]
struct P2idNote {
    target_account_id: AccountId,
}

#[note]
impl P2idNote {
    #[note_script]
    pub fn script(self, _arg: Word, account: &mut Account) {
        for asset in active_note::get_assets() {
            account.receive_asset(asset);
        }
    }
}
```

After (0.13.0):

```rust
use miden::{account, active_note, note, AccountId, Word};

// declare the native account explicitly; pick the package's WIT interface
#[account(basic_wallet::BasicWallet)]
pub struct Wallet;

#[note]
struct P2idNote {
    target_account_id: AccountId,
}

#[note]
impl P2idNote {
    #[note_script]
    pub fn script(self, _arg: Word, account: &mut Wallet) {
        for asset in active_note::get_assets() {
            account.receive_asset(asset);
        }
    }
}
```

The same `#[account(...)]` type serves two roles. Passed to a `#[note]`/`#[tx_script]` entrypoint
it is the transaction's native (active) account. Constructed with `new(account_id)` it is a
**foreign account caller**, whose method calls are routed through `execute_foreign_procedure`
(FPI):

```rust
let counter = CounterContract::new(counter_account_id);
let count = counter.get_count();
```

**FPI is not limited to note/tx scripts — an account component can call another account through
FPI too.** Declare the `#[account(...)]` wrapper in the component crate (and the dependency in
`miden-project.toml`, section 2) and use it from inside the `#[component] impl`:

```rust
#[account(callee_account::CounterContract)]
struct CalleeAccount;

#[component]
impl CallerAccount for CallerAccountStorage {
    fn read_foreign_count(&self, callee_account_id: AccountId) -> Felt {
        let callee = CalleeAccount::new(callee_account_id);
        callee.get_count(key)
    }
}
```

### 4. Tx-kernel bindings: protocol v0.15

The SDK bindings were aligned with VM v0.23 / protocol v0.15 (`miden-field` bumped to `^0.25`).

- **`Felt::new` is now fallible** — it returns `Result<Felt, _>` instead of `Felt`. Replace
  `Felt::new(x)` with `Felt::new(x).unwrap()` (or handle the error). The `felt!(x)` macro is
  unchanged and remains the preferred constructor for literals.
- **`asset::{create_fungible_asset, create_non_fungible_asset}`** now take a trailing
  `enable_callbacks: bool` argument.
- **`active_account::{get_balance, get_initial_balance}`** (and the corresponding `ActiveAccount`
  trait methods) now take an asset key `Word` instead of a faucet `AccountId`.
- **`faucet::{mint, burn}`** no longer return an `Asset`; the `faucet::{mint_value, burn_value}`
  helpers were removed. Use the returned value-free API to match the tx kernel.
- **`output_note::set_attachment` was removed.** The attachment shape is selected by function
  instead of a runtime `attachment_kind` argument:

  ```rust
  // before: output_note::set_attachment(note_idx, scheme, kind, attachment);
  // after, for a single word:
  output_note::add_word_attachment(note_idx, scheme, attachment);
  // or `add_attachment` for a commitment, `add_attachment_from_memory` for multiple words.
  ```

> **Storage encoding note.** Scalar `Felt` values stored in `StorageValue<Felt>` /
> `StorageMap<_, Felt>` are now packed into the low word limb (`[v, 0, 0, 0]`) instead of the high
> limb (`[0, 0, 0, v]`), matching protocol v0.15. This is transparent when you recompile and
> redeploy, but state written by 0.12.0 code is read back differently by 0.13.0 code.

### New in 0.13.0 (no migration required)

- **Sibling component calls**: `#[component(package::Interface, ...)]` on the component trait lets
  one component call another component deployed on the same account. See the
  [CHANGELOG]./CHANGELOG.md for details.
- **`println!`** macro (and `debug::println`) for emitting a debug message during execution.