Skip to content

Tracking PR for v0.17.0 release - #3518

Draft
bobbinth wants to merge 73 commits into
mainfrom
next
Draft

Tracking PR for v0.17.0 release#3518
bobbinth wants to merge 73 commits into
mainfrom
next

Conversation

@bobbinth

@bobbinth bobbinth commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

This is a tracking PR for v0.17.0 release.

bobbinth and others added 30 commits August 6, 2026 17:35
* refactor: address remaining #3204 comments (standards module moves)

Carries the #3204 follow-up cleanup on top of the unified authenticator:
- [BREAKING] move the `note_tag` MASM module to `miden::standards::note::note_tag`
- [BREAKING] move the `note_creator` component to the `utils` namespace and
  the Rust `NoteCreator` type to `account::note_creator`
- re-export `create_note` from the basic-wallet interface
- standardize the panic-condition wording in the kernel/protocol MASM doc
  comments and update the affected import sites and docs

The authenticator doc comments in api.masm / native_account.masm and the
CHANGELOG entry are kept consistent with the flag-based tracking design from
the parent commit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: small comment fixes

* chore: re-trigger CI

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ency switch (#3520)

* test(standards): pin the freeze-only actor asymmetry under RBAC

* docs(standards): document the freeze-only actor pattern on Authority

* changelog
* refactor: remove asset value from callback outputs

* test: preserve callback value regression coverage

* test: restore account callback value regression

* Apply suggestions from code review

* refactor: make callback wrappers consume inputs

* docs: preserve callback changelog history

---------

Co-authored-by: Philipp Gackstatter <18741416+PhilippGackstatter@users.noreply.github.com>
Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
Co-authored-by: UfukNode <208284577+UfukNode@users.noreply.github.com>
…dings (#3463)

The security/code-reviewer agents sometimes clear a section with prose like
"None. I specifically tried and failed to break the following:" followed by
bullets documenting what was ruled out. `_count_blocking_findings` only
recognized an exact `- None.` bullet as an absence marker, so those
diligence bullets were counted as real findings, producing a false "N
blocking finding(s)" verdict even though the reviewer intended CLEAN.

Require a blocking section's first content line to open with "None"/"N/A"
(bare, bolded, or with a period-terminated explanation on the same line, but
not a real finding like "None of the callers..." - there's no "." or
end-of-line right after "None" there); once matched, the rest of the
section is ignored. A stray absence marker anywhere else only skips itself,
so a real finding followed by a later "- None." isn't double-counted.

This is fail-open for the narrow case of a "None." opener genuinely
followed by real findings. Both prompts already require the response to
open with a `BLOCK:`/`CLEAN:`/`APPROVE:` token (tolerant of markdown bold
around it, and found by searching the preamble before the review body
starts rather than strictly at byte 0 - a model occasionally writes a
sentence or two before the token line even when told to lead with it, which
happened for real during this change's own review); use it as a simple
backstop - missing it is malformed output (blocks), and a self-reported
BLOCK overrides a structured count of 0. A structured count still always
wins over a self-reported CLEAN, so the agent can't talk its way past a
real finding.

Update both reviewer prompts: put the leading token directly into the
Output Format template (as a placeholder, not a literal example that could
get echoed as a real verdict) so it isn't just a trailing instruction the
agent might drift from, align code-reviewer's verdict vocabulary with the
token vocabulary (APPROVE/BLOCK instead of APPROVE/REQUEST CHANGES), and
state the Empty Sections rule as one unambiguous sentence in both
directions in both files.

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
…ezing role management (#3476)

* fix(standards): prevent role delegation to a dead admin role from freezing role management

* changelog

* fix comment

* remove redundant comments

* apply suggestions
…es (#3501)

* refactor(protocol): move shared input note helpers into private modules

* chore: update changelog PR link

* chore: address review comments

* Apply suggestions from code review

Co-authored-by: Marti <marcin.gorny.94@protonmail.com>

---------

Co-authored-by: Marti <marti@miden.team>
Co-authored-by: Marti <marcin.gorny.94@protonmail.com>
…oc to indexed-note path (#3542)

The Panics doc for remove_asset_raw and remove_all_assets_raw stated
unconditionally that calling outside the native account's context
panics. That only holds for the indexed-note path (is_active_note is
false); the active-note path used by active_note::remove_asset /
remove_all_assets is exempt, per the kernel's own doc for the
underlying procs (api.masm input_note_remove_asset /
input_note_remove_all_assets).

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
* feat: track generic assets in `AccountVaultDelta`

* chore: add changelog

* chore: address review comments

* chore: move changelog entry to 0.17
)

* refactor: `TransactionScript` and `AccountComponent` constructors

* refactor: reject NoteScript construction from executable
* feat(agglayer): configure priced fee policies at deployment

* docs: document AggLayer constant fee policies

* refactor(agglayer): add fee policy account builders

* refactor(agglayer): streamline fee policy builders

* test(agglayer): clarify fee manager names

* refactor(agglayer): simplify testing helper imports

* test(agglayer): cover bridge flows with fees enabled

* refactor(tests): unify AggLayer fee policy setup

* fix: address fee policy deployment review

Make the fee policy manager a required argument of the AggLayer account
builders instead of an optional setter whose absence panicked in
`build()`, and expose the faucet's asset callback flag on the builder.

The bridge-in claim-to-P2ID test regained the callback-enabled faucet it
lost when it moved to the priced helper, and the bridge-out test keeps
pinning all 32 bundled Solidity MTF vectors.

* feat(agglayer): make deployed fee schedules repricable

Both AggLayer network accounts install the ConstantFeeManager and
allowlist CONSTANT_FEE_POLICY_CONFIG notes, so their ADMIN role can
reprice a schedule that was otherwise frozen at deployment. The bridge
sizes the sponsorship of every MINT and BURN note it creates from the
faucet's schedule, so leaving the faucet frozen would stall bridging
once the chain's verification base fee moved.

The faucet moves from Authority::OwnerControlled to RbacControlled to
make that reachable at all: with the bridge as its Ownable2Step owner,
every authority-gated procedure was gated on a sender nothing can
produce. Minting and burning are unaffected, since MintOwnerOnly and
BurnOwnerOnly check the owner slot directly rather than going through
Authority.

The config note is scheduled free rather than at its benchmarked cost.
Consuming one is the only route to set_note_fee, so pricing it would let
the schedule put the note that repairs it out of reach.

* docs(agglayer): specify fee schedule administration

Documents what the fee policy work changed: the deployed schedules and
how they are repriced, the faucet's move to RBAC and the resulting split
between owner-gated minting and ADMIN-gated configuration, and the
CONSTANT_FEE_POLICY_CONFIG note.

Also records the operational consequence of a priced schedule that was
previously undocumented: a note with a non-zero schedule entry can only
be consumed alongside FEE_SPONSORSHIP notes covering it, regardless of
the chain's own base fee, so every management note needs a sponsorship
funded with it.

Pins the faucet allowlist the way the bridge's already was, and covers
repricing a paused bridge.

* docs(agglayer): reword the SPEC term flagged by the spellchecker

* chore: condense the AggLayer fee policy changelog entries

* refactor(tests): deduplicate AggLayer fee-enabled test plumbing

Adds a find_output_note helper for the six copies of the
output-note-by-script-root predicate, returns Option<Note> from
add_fee_sponsorship so the fee axis stops being threaded through
if/else blocks, and uses the existing authenticated_input_notes
iterator overload to restore the builder chains.

The priced-account pin test now reuses build_managed_account instead
of rebuilding the same two fixtures verbatim.

* Update CHANGELOG.md

Co-authored-by: zeapoz <zeapo@pm.me>

* refactor(agglayer): return AccountBuilder from the account builder helpers

Address review feedback on the deployment builder API:
- drop the AggLayerBridgeAccountBuilder and AggLayerFaucetAccountBuilder
  wrappers; AggLayerBridge::account_builder and AggLayerFaucet::account_builder
  now return the underlying AccountBuilder directly
- move the test-only helpers (zero_fee_policy_manager, faucet_account_builder,
  create_existing_agglayer_faucet) into miden_agglayer::testing

* refactor(agglayer): rename the note-set accessors

Address review feedback on the note-set naming: the former fee_policy_notes
returned the full set of notes the account actually accepts, so it becomes
allowed_notes, and the component-specific subsets become bridge_notes and
faucet_notes. Record the rename in the changelog and move this PR's entries
back under the unreleased v0.17.0 section, where the released v0.16.0 section
had absorbed them during the merge from next.

* refactor(agglayer): collapse the note-set accessors into allowed_notes

AuthNetworkAccount::new already extends any allowlist it is given with the
default network-account notes, so passing the full set to the builder is
idempotent and the bridge_notes/faucet_notes split served no purpose.

* refactor(agglayer): inline the account builders and drop the one-shot constructors

AggLayerBridge::account_builder and AggLayerFaucet::account_builder now hold
the building logic directly; the faucet builder takes the initial supply so
test fixtures no longer need a separate pass-through, and the unused
create_bridge_account / create_agglayer_faucet wrappers are gone.

* docs(agglayer): explain the zero-priced fee config note and flag #2724

The zero schedule entry only forgoes enforced reimbursement: a voluntary
sponsorship still funds a repricing transaction, and the pricer still
computes the config note's real cost. Also document the price-then-allowlist
ordering for new roots and mark the faucet ownership-rotation question as
tracked by #2724.

* test(agglayer): prove a sponsored repricing note reimburses the bridge

* docs(agglayer): correct the faucet ownership claim - transfer is owner-gated

The SPEC and builder docs claimed the faucet ADMIN can retarget the
Ownable2Step owner. It cannot: transfer_ownership asserts the note sender is
the current owner (the bridge), never consulting Authority, and the bridge
has no flow that authors such a note. Rotation stays unreachable; #2724
tracks removing the dead procedures.

* docs(agglayer): simplify the fee policy wording

* docs(agglayer): note that a priced-in margin delays repricing

* docs(agglayer): quantify the default pricing margin

The default NetworkNotePricer margin is one extra verification cycle,
roughly 6% of the fee, so a schedule built with it is not far from needing
a reprice when the base fee rises.

* docs(agglayer): document the bridge-faucet schedule coupling

The bridge funds MINT/BURN sponsorships sized by the faucet's schedule and
is reimbursed via its own CLAIM/B2AGG prices, so faucet repricing must be
matched on the bridge. Nothing enforces this; it is an operator rule.

* docs(agglayer): correct the schedule-coupling consequence

A faucet entry repriced past the bridge's own CLAIM/B2AGG entry does not
merely drain the vault: the AtMostCollectedFees assertion aborts every
claim and bridge-out. Also document the bridge-first repricing order and
that the bridge's CLAIM/B2AGG entries must never be zeroed.

* docs(agglayer): state the schedule-coupling invariant instead of one order

Bridge-first repricing is only safe upward; the invariant is that the
bridge's CLAIM/B2AGG entries never sit below the faucet's MINT/BURN
entries, so raise the bridge first and lower the faucet first. Zeroing
the bridge entries halts claims outright rather than draining.

* docs(agglayer): state the full schedule-coupling rule

The solvency rule includes the bridge's own consumption fee, which is what
NetworkNotePricer deploys, applies to every registered faucet, and holds
during registration as well as repricing. Also note that raising an entry
strands in-flight notes until a top-up sponsorship is added.

* docs(agglayer): trim fee administration spec

* fix(fees): price config notes without losing recovery

* docs(fees): correct the repricing recovery story

Drop the zero-reset claim and state the real sender-side constraint:
standard auth components size a config note's sponsorship from the
target's pre-transaction estimate (fee::pay_fee), so recovering from an
excessively high entry requires fronting the previous fee, and an entry
no sender can fund freezes fee administration. Also generalize the
charged-the-new-value rule to every note of a repriced root and note
that raising a fee leaves already-created notes under-sponsored until an
extra FEE_SPONSORSHIP tops them up.

* fix(agglayer): drop the unused allow_all burn policy from the faucet

Registering BurnAllowAll as an allowed policy let the ADMIN role open
burns in two steps under Authority::RbacControlled: widen the note
allowlist with FAUCET_POLICY_CONFIG, then activate the registered
policy. No AggLayer flow opens burns - bridge-out burns through the
owner-gated receive_and_burn - so remove the registration and the
redundant explicit component instead of documenting the escalation.
The faucet code commitment changes.

* chore: condense the AggLayer changelog, state the faucet ADMIN rotation limit

One changelog entry for the whole PR. The SPEC trust model and the
faucet builder docs now state that the faucet does not allowlist
RBAC_CONFIG: its ADMIN cannot be rotated directly, and losing the key
freezes the faucet's authority-gated configuration.

* chore(agglayer): tidy the fee test fixtures and docs

Use the mock chain's native fee faucet in the zero-fee fixture, record
why the priced fixtures cannot move next to the zero-fee ones, drop a
stale doc reference to a deleted scenario, and add the missing section
header in fee_policy.rs.

* test(agglayer): pin the output-note counts in the fee-enabled E2E cases

find_output_note returns the first match by script root, so nothing
pinned the total note count after the assertions were relaxed. Assert
the exact per-case counts (feature note alone fee-free; plus the
FEE_SPONSORSHIP and TX_FEE notes fee-enabled) so a stray extra note
fails loudly.

* docs(agglayer): note the inert FEE_SPONSORSHIP schedule entry

Fee collection prices sponsorship notes at zero without consulting the
policy, so the scheduled FEE_SPONSORSHIP entry is never read; it exists
only to keep the schedule covering the whole allowlist.

* docs(agglayer): tighten the fee administration and faucet ADMIN caveats

The full mechanics live in the CONSTANT_FEE_POLICY_CONFIG note rustdoc;
the SPEC states the outcomes and points there.

* docs(fees): compress the config-note operational notes

* docs(agglayer): rewrap the faucet allowlist doc paragraph

* Update crates/miden-agglayer/src/lib.rs

Co-authored-by: Marti <marti@miden.team>

* Update crates/miden-agglayer/src/lib.rs

Co-authored-by: Marti <marti@miden.team>

* fix(fees): drop the sponsorship note from constant fee schedules

A fee schedule maps a note script root to the price charged for consuming it.
A FEE_SPONSORSHIP note funds those prices rather than carrying one, and fee
collection never consults the policy for it: collect_sponsored_fees records a
required fee of zero for a sponsorship input, and is_network_note keys off the
NetworkAccountTarget attachment, which a sponsorship note never carries.

Unifying the AggLayer note-set accessors pulled the root into the schedule as a
side effect. Express the rule once as FeeSponsorshipNote::feature_notes and
price only those.

* docs(agglayer): disambiguate ADMIN and trim SPEC change narration

Each faucet installs its own role set, so both accounts have a built-in ADMIN.
State that once in the administration section and qualify the ambiguous uses.

Drop the config-note text that narrated how pricing changed during review in
favour of what the design does now.

* docs(agglayer): restore the AuthNetworkAccount link definition

The applied review suggestion removed the link-reference definition along with
the paragraph above it, breaking cargo doc under -D warnings.

* chore: trim the AggLayer changelog entry

* docs(agglayer): say the bridge accepts three other standard notes

* docs(agglayer): plainer wording in the allowlist and builder docs

Say the bridge accepts three other standard notes rather than opting into
standards notes, and allowed rather than sanctioned input notes. Reword the
faucet's sponsorship-sizing note into two plain sentences.

Drop the prose and inline comments restating that AuthNetworkAccount adds its
own defaults, and the orphaned link definitions they leave behind.

* docs(fees): simplify the config note's operational notes

Drop the redundant RBAC comment in build.rs, which the component-order comment
below it already covers.

* docs(agglayer): drop the duplicate issue link from the trust model table

* docs(agglayer): name the components the faucet shares with the bridge

* chore: move the AggLayer entry to the v0.16.0 changelog section

* refactor(tx): drop the AggLayer fee policy helpers from NetworkNotePricer

Callers pass the account's allowed_notes to basic_constant_fee_policy_manager
directly, keeping the pricer agnostic about account types.

* refactor(agglayer): clean up bridge note pricing

---------

Co-authored-by: zeapoz <zeapo@pm.me>
Co-authored-by: Marti <marti@miden.team>
…3581)

* feat(agglayer): configure priced fee policies at deployment

* docs: document AggLayer constant fee policies

* refactor(agglayer): add fee policy account builders

* refactor(agglayer): streamline fee policy builders

* test(agglayer): clarify fee manager names

* refactor(agglayer): simplify testing helper imports

* test(agglayer): cover bridge flows with fees enabled

* refactor(tests): unify AggLayer fee policy setup

* fix: address fee policy deployment review

Make the fee policy manager a required argument of the AggLayer account
builders instead of an optional setter whose absence panicked in
`build()`, and expose the faucet's asset callback flag on the builder.

The bridge-in claim-to-P2ID test regained the callback-enabled faucet it
lost when it moved to the priced helper, and the bridge-out test keeps
pinning all 32 bundled Solidity MTF vectors.

* feat(agglayer): make deployed fee schedules repricable

Both AggLayer network accounts install the ConstantFeeManager and
allowlist CONSTANT_FEE_POLICY_CONFIG notes, so their ADMIN role can
reprice a schedule that was otherwise frozen at deployment. The bridge
sizes the sponsorship of every MINT and BURN note it creates from the
faucet's schedule, so leaving the faucet frozen would stall bridging
once the chain's verification base fee moved.

The faucet moves from Authority::OwnerControlled to RbacControlled to
make that reachable at all: with the bridge as its Ownable2Step owner,
every authority-gated procedure was gated on a sender nothing can
produce. Minting and burning are unaffected, since MintOwnerOnly and
BurnOwnerOnly check the owner slot directly rather than going through
Authority.

The config note is scheduled free rather than at its benchmarked cost.
Consuming one is the only route to set_note_fee, so pricing it would let
the schedule put the note that repairs it out of reach.

* docs(agglayer): specify fee schedule administration

Documents what the fee policy work changed: the deployed schedules and
how they are repriced, the faucet's move to RBAC and the resulting split
between owner-gated minting and ADMIN-gated configuration, and the
CONSTANT_FEE_POLICY_CONFIG note.

Also records the operational consequence of a priced schedule that was
previously undocumented: a note with a non-zero schedule entry can only
be consumed alongside FEE_SPONSORSHIP notes covering it, regardless of
the chain's own base fee, so every management note needs a sponsorship
funded with it.

Pins the faucet allowlist the way the bridge's already was, and covers
repricing a paused bridge.

* docs(agglayer): reword the SPEC term flagged by the spellchecker

* chore: condense the AggLayer fee policy changelog entries

* refactor(tests): deduplicate AggLayer fee-enabled test plumbing

Adds a find_output_note helper for the six copies of the
output-note-by-script-root predicate, returns Option<Note> from
add_fee_sponsorship so the fee axis stops being threaded through
if/else blocks, and uses the existing authenticated_input_notes
iterator overload to restore the builder chains.

The priced-account pin test now reuses build_managed_account instead
of rebuilding the same two fixtures verbatim.

* Update CHANGELOG.md



* refactor(agglayer): return AccountBuilder from the account builder helpers

Address review feedback on the deployment builder API:
- drop the AggLayerBridgeAccountBuilder and AggLayerFaucetAccountBuilder
  wrappers; AggLayerBridge::account_builder and AggLayerFaucet::account_builder
  now return the underlying AccountBuilder directly
- move the test-only helpers (zero_fee_policy_manager, faucet_account_builder,
  create_existing_agglayer_faucet) into miden_agglayer::testing

* refactor(agglayer): rename the note-set accessors

Address review feedback on the note-set naming: the former fee_policy_notes
returned the full set of notes the account actually accepts, so it becomes
allowed_notes, and the component-specific subsets become bridge_notes and
faucet_notes. Record the rename in the changelog and move this PR's entries
back under the unreleased v0.17.0 section, where the released v0.16.0 section
had absorbed them during the merge from next.

* refactor(agglayer): collapse the note-set accessors into allowed_notes

AuthNetworkAccount::new already extends any allowlist it is given with the
default network-account notes, so passing the full set to the builder is
idempotent and the bridge_notes/faucet_notes split served no purpose.

* refactor(agglayer): inline the account builders and drop the one-shot constructors

AggLayerBridge::account_builder and AggLayerFaucet::account_builder now hold
the building logic directly; the faucet builder takes the initial supply so
test fixtures no longer need a separate pass-through, and the unused
create_bridge_account / create_agglayer_faucet wrappers are gone.

* docs(agglayer): explain the zero-priced fee config note and flag #2724

The zero schedule entry only forgoes enforced reimbursement: a voluntary
sponsorship still funds a repricing transaction, and the pricer still
computes the config note's real cost. Also document the price-then-allowlist
ordering for new roots and mark the faucet ownership-rotation question as
tracked by #2724.

* test(agglayer): prove a sponsored repricing note reimburses the bridge

* docs(agglayer): correct the faucet ownership claim - transfer is owner-gated

The SPEC and builder docs claimed the faucet ADMIN can retarget the
Ownable2Step owner. It cannot: transfer_ownership asserts the note sender is
the current owner (the bridge), never consulting Authority, and the bridge
has no flow that authors such a note. Rotation stays unreachable; #2724
tracks removing the dead procedures.

* docs(agglayer): simplify the fee policy wording

* docs(agglayer): note that a priced-in margin delays repricing

* docs(agglayer): quantify the default pricing margin

The default NetworkNotePricer margin is one extra verification cycle,
roughly 6% of the fee, so a schedule built with it is not far from needing
a reprice when the base fee rises.

* docs(agglayer): document the bridge-faucet schedule coupling

The bridge funds MINT/BURN sponsorships sized by the faucet's schedule and
is reimbursed via its own CLAIM/B2AGG prices, so faucet repricing must be
matched on the bridge. Nothing enforces this; it is an operator rule.

* docs(agglayer): correct the schedule-coupling consequence

A faucet entry repriced past the bridge's own CLAIM/B2AGG entry does not
merely drain the vault: the AtMostCollectedFees assertion aborts every
claim and bridge-out. Also document the bridge-first repricing order and
that the bridge's CLAIM/B2AGG entries must never be zeroed.

* docs(agglayer): state the schedule-coupling invariant instead of one order

Bridge-first repricing is only safe upward; the invariant is that the
bridge's CLAIM/B2AGG entries never sit below the faucet's MINT/BURN
entries, so raise the bridge first and lower the faucet first. Zeroing
the bridge entries halts claims outright rather than draining.

* docs(agglayer): state the full schedule-coupling rule

The solvency rule includes the bridge's own consumption fee, which is what
NetworkNotePricer deploys, applies to every registered faucet, and holds
during registration as well as repricing. Also note that raising an entry
strands in-flight notes until a top-up sponsorship is added.

* docs(agglayer): trim fee administration spec

* fix(fees): price config notes without losing recovery

* docs(fees): correct the repricing recovery story

Drop the zero-reset claim and state the real sender-side constraint:
standard auth components size a config note's sponsorship from the
target's pre-transaction estimate (fee::pay_fee), so recovering from an
excessively high entry requires fronting the previous fee, and an entry
no sender can fund freezes fee administration. Also generalize the
charged-the-new-value rule to every note of a repriced root and note
that raising a fee leaves already-created notes under-sponsored until an
extra FEE_SPONSORSHIP tops them up.

* fix(agglayer): drop the unused allow_all burn policy from the faucet

Registering BurnAllowAll as an allowed policy let the ADMIN role open
burns in two steps under Authority::RbacControlled: widen the note
allowlist with FAUCET_POLICY_CONFIG, then activate the registered
policy. No AggLayer flow opens burns - bridge-out burns through the
owner-gated receive_and_burn - so remove the registration and the
redundant explicit component instead of documenting the escalation.
The faucet code commitment changes.

* chore: condense the AggLayer changelog, state the faucet ADMIN rotation limit

One changelog entry for the whole PR. The SPEC trust model and the
faucet builder docs now state that the faucet does not allowlist
RBAC_CONFIG: its ADMIN cannot be rotated directly, and losing the key
freezes the faucet's authority-gated configuration.

* chore(agglayer): tidy the fee test fixtures and docs

Use the mock chain's native fee faucet in the zero-fee fixture, record
why the priced fixtures cannot move next to the zero-fee ones, drop a
stale doc reference to a deleted scenario, and add the missing section
header in fee_policy.rs.

* test(agglayer): pin the output-note counts in the fee-enabled E2E cases

find_output_note returns the first match by script root, so nothing
pinned the total note count after the assertions were relaxed. Assert
the exact per-case counts (feature note alone fee-free; plus the
FEE_SPONSORSHIP and TX_FEE notes fee-enabled) so a stray extra note
fails loudly.

* docs(agglayer): note the inert FEE_SPONSORSHIP schedule entry

Fee collection prices sponsorship notes at zero without consulting the
policy, so the scheduled FEE_SPONSORSHIP entry is never read; it exists
only to keep the schedule covering the whole allowlist.

* docs(agglayer): tighten the fee administration and faucet ADMIN caveats

The full mechanics live in the CONSTANT_FEE_POLICY_CONFIG note rustdoc;
the SPEC states the outcomes and points there.

* docs(fees): compress the config-note operational notes

* docs(agglayer): rewrap the faucet allowlist doc paragraph

* Update crates/miden-agglayer/src/lib.rs



* Update crates/miden-agglayer/src/lib.rs



* fix(fees): drop the sponsorship note from constant fee schedules

A fee schedule maps a note script root to the price charged for consuming it.
A FEE_SPONSORSHIP note funds those prices rather than carrying one, and fee
collection never consults the policy for it: collect_sponsored_fees records a
required fee of zero for a sponsorship input, and is_network_note keys off the
NetworkAccountTarget attachment, which a sponsorship note never carries.

Unifying the AggLayer note-set accessors pulled the root into the schedule as a
side effect. Express the rule once as FeeSponsorshipNote::feature_notes and
price only those.

* docs(agglayer): disambiguate ADMIN and trim SPEC change narration

Each faucet installs its own role set, so both accounts have a built-in ADMIN.
State that once in the administration section and qualify the ambiguous uses.

Drop the config-note text that narrated how pricing changed during review in
favour of what the design does now.

* docs(agglayer): restore the AuthNetworkAccount link definition

The applied review suggestion removed the link-reference definition along with
the paragraph above it, breaking cargo doc under -D warnings.

* chore: trim the AggLayer changelog entry

* docs(agglayer): say the bridge accepts three other standard notes

* docs(agglayer): plainer wording in the allowlist and builder docs

Say the bridge accepts three other standard notes rather than opting into
standards notes, and allowed rather than sanctioned input notes. Reword the
faucet's sponsorship-sizing note into two plain sentences.

Drop the prose and inline comments restating that AuthNetworkAccount adds its
own defaults, and the orphaned link definitions they leave behind.

* docs(fees): simplify the config note's operational notes

Drop the redundant RBAC comment in build.rs, which the component-order comment
below it already covers.

* docs(agglayer): drop the duplicate issue link from the trust model table

* docs(agglayer): name the components the faucet shares with the bridge

* chore: move the AggLayer entry to the v0.16.0 changelog section

* refactor(tx): drop the AggLayer fee policy helpers from NetworkNotePricer

Callers pass the account's allowed_notes to basic_constant_fee_policy_manager
directly, keeping the pricer agnostic about account types.

* refactor(agglayer): clean up bridge note pricing

---------

Co-authored-by: Alexander John Lee <77119221+partylikeits1983@users.noreply.github.com>
Co-authored-by: zeapoz <zeapo@pm.me>
…3576)

* chore: rename value_into_amount API for consistency

* chore: add changelog

* chore: structure the changelog
* fix(protocol): validate private note attachments

* test(protocol): clarify attachment mismatch assertions

* test(protocol): simplify mismatch assertions
* refactor(agglayer): construct fee policy managers internally

* chore: link AggLayer changelog to follow-up PR

* refactor(agglayer): inline fee policy manager construction
…a single constructor (#3548)

* refactor(protocol): consolidate `MastForestScript` instantation into a
single constructor

* chore: update builder methods to use `mut self`

---------

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
* fix: assert procedure belongs to foreign account

* chore: add changelog

* Apply suggestions from code review

Co-authored-by: Alexander John Lee <77119221+partylikeits1983@users.noreply.github.com>

---------

Co-authored-by: Marti <marti@miden.team>
Co-authored-by: Alexander John Lee <77119221+partylikeits1983@users.noreply.github.com>
…es (#3500)

* document AuthControlled in authority-gated config notes

* changelog

* apply suggestions

---------

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
* feat: sort account procedures at construction

* chore: add changelog

* chore: address review comments

* chore: bring back proc count validation in proc builder
…3567)

* feat: validate proc uniqueness and sorting in tx kernel

* chore: add changelog

* chore: address review comments
* feat(miden-tx): let NetworkNotePricer take supplied note costs

The pricer's cost lookup was hard-wired to the standard and agglayer
tables, so an account with note families outside those tables — or with
table-known script roots that measure differently on its own code — had
to re-implement the pricing formula. The builder now accepts note_costs,
a map consulted before the built-in tables, and the private test-only
lookup hook is folded into it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: changelog entry for the pricer note-cost map

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(changelog): deduplicate the v0.16.0 section

The changelog commit had inserted a second `## v0.16.0` header along with
entries belonging to other PRs, splitting the release notes into two
v0.16.0 sections. Keep the single existing section and add only this PR's
`note_costs` entry to its Features list.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(miden-tx): let note costs be supplied individually or as an iterator

Switch `note_costs` to a `#[builder(field)]` and expose `note_cost` (single
entry) and `note_costs` (iterator) builder extensions, following the SwapNote
builder pattern, so callers can set costs one at a time as well as in bulk.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
Bump the workspace version 0.16.0-rc.4 -> 0.16.0-rc.5 (workspace.package and the
path-dependency pins), refresh Cargo.lock, and date the v0.16.0 changelog section.

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
…ture (#3617)

* feat(agglayer): expose bridge storage readers outside the testing feature

Production callers need these accessors to inspect GER registration, LET state, and hash chains without enabling the testing feature.

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: link the changelog entry to the pull request

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
PhilippGackstatter and others added 30 commits August 19, 2026 15:58
* chore: remove stale doc references, rename procedure

* chore: consistent field and getter name

* chore: correct stale note version 0 ref
* feat: enforce max delta ops in vault delta

* feat: enforce max num added assets in kernel

* chore: add changelog

* chore: address review comments

* chore: simplify vault delta

* chore: address review comments

---------

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
* fix(protocol): reject empty asset id in input_note::remove_asset

* chore: add changelog entry

* chore: re-trigger CI

* Update crates/miden-protocol/asm/kernels/transaction-core/src/input_note.masm

Co-authored-by: zeapoz <zeapo@pm.me>

* chore: fix build

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
Co-authored-by: zeapoz <zeapo@pm.me>
Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
Co-authored-by: Bobbin Threadbare <bobbinth@protonmail.com>
)

* fix(standards): assert fungible composition in receive_and_burn

* changelog

* remove redundant comments

* apply suggestions

* remove redundant comment

---------

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
…der (#3606)

* fix(protocol): clear input-note slot on empty fungible removal remainder

* chore: add changelog entry

* chore: re-trigger CI

* Apply suggestions from code review

Co-authored-by: Marti <marcin.gorny.94@protonmail.com>

* test(protocol): add regression test for non-canonical fungible remove_asset

Adds a scenario to test_remove_asset_fails covering audit finding L-03
(#3591): removing a fungible asset with a value whose amount limb matches
the stored amount but whose upper limbs are non-zero must now fail with
ERR_FUNGIBLE_ASSET_VALUE_MOST_SIGNIFICANT_ELEMENTS_MUST_BE_ZERO instead
of leaving a dangling (ASSET_ID, EMPTY_WORD) slot behind.

Verified the scenario fails against the pre-fix kernel and passes with
the fix.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Update crates/miden-testing/src/kernel_tests/tx/test_input_note.rs

* Apply suggestion from @mmagician

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
* fix(standards): bind the non-fungible MINT note to its faucet

* changelog

* address review comments on non-fungible MINT note

* refactor(standards): bind the non-fungible MINT note via its stored ASSET_ID

* chore: regenerate the note consumption cost tables

* refactor(standards): use asset::load in the non-fungible MINT note

---------

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
* fix(protocol): verify faucet callback root against account code

* chore: add changelog entry

* chore: re-trigger CI

* Update CHANGELOG.md

Co-authored-by: zeapoz <zeapo@pm.me>

* test(protocol): import generated faucet callback error constant

Replace the locally redefined ERR_FAUCET_CALLBACK_PROC_ROOT_NOT_PART_OF_ACCOUNT_CODE
MasmError with the constant generated from callbacks.masm by the build script, so
the test and kernel share a single source of truth for the error string.

ERR_ACCOUNT_BLOCKED stays defined locally: it mirrors the test-only BLOCK_LIST_MASM
component, not a kernel error, so it is not build-generated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore: refresh cost tables

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
Co-authored-by: zeapoz <zeapo@pm.me>
Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
Co-authored-by: Bobbin Threadbare <bobbinth@protonmail.com>
…dures (#3610)

* refactor(protocol): use native accessors in native-only account procedures

* Update crates/miden-protocol/asm/kernels/transaction-core/src/account.masm

* Apply suggestion from @mmagician

* fix(protocol): move num_storage_slots instead of duplicating it in find_storage_slot

Addresses review feedback on the end-pointer construction in
find_storage_slot: swap the slot count to the top and consume it
directly via mul, instead of duplicating it with dup.1 and dropping
the leftover copy afterwards. Same public interface, fewer cycles.

* Apply suggestion from @mmagician

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
…icy (#3547)

* fix(standards): enable asset callbacks on faucets with a transfer policy

* changelog and remove comments

* merge

* test(standards): share the faucet policy-manager fixtures

---------

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
* feat(standards): enforce FPI expiration limits

* refactor(standards): drop the @fpi attribute pending defined semantics

* refactor(standards): remove expiration deltas from the policy manager

Expiration deltas are policy-owned per review feedback on #3512: the
dispatchers deliberately set none, and each transfer policy applies its
own. Documented the contract - including that the dispatcher's own
policy-root and pause-flag reads are unbounded when the active policy
sets no delta, pending the protocol-wide backstop discussed in #3504 -
on the dispatchers and on TransferPolicy::custom. Narrowed the
CHANGELOG entry to the procedures actually covered and moved it from
the released v0.16.0 section into v0.17.0, where this lands.

* refactor(standards): replace expiration helper with fpi::apply_default_expiration_delta

Per review feedback on #3512: the nonzero check duplicated the kernel's
own validation in tx::update_expiration_block_delta, so the helper is
now a parameterless one-liner that call sites invoke without pushing
the delta themselves. Documented the expiration side effect on the four
procedures that apply it and added the module to the changelog.

* feat(standards): apply default expiration delta in remaining standard policies

Per review feedback on #3512: min_burn_amount reads the mutable minimum
burn amount and the owner-only mint/burn policies read the mutable
Ownable2Step owner slot, so their check_policy procedures now apply the
default expiration delta like the allowlist/blocklist policies do. The
allow-all policies read no state and stay unbounded.

* refactor(standards): align expiration docs and deduplicate test assertions

Review polish: document the policy-owned expiration contract (including
the unbounded dispatcher reads and the #3504 backstop pointer) on the
mint/burn dispatchers, the Mint/BurnPolicy types, and their custom
constructors to match the transfer path; mark the unbounded config
getters (get_fee_policy, get_min_burn_amount) as deliberate pending
#3504; correct the get_fee_asset_id rationale (the fee asset slot has
no setter); add the missing stack trackers after the new call sites;
and replace eight copy-pasted test assertions with a shared
track_caller helper that mirrors DEFAULT_EXPIRATION_BLOCK_DELTA.

* docs(standards): remove stale expiration references

* refactor(standards): rename FPI expiration helper

* refactor(standards): narrow FPI expiration scope

* docs: consolidate FPI expiration changelog entry

* docs: simplify FPI expiration changelog entry

* refactor(testing): import expiration assertion helper

* refactor(testing): simplify expiration assertion helper

* docs(standards): trim transfer expiration rationale
…depth (#3645)

* fix(standards): return get_schema_commitment at the required stack depth

* chore: fix changelog PR reference

---------

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
…cetPolicyConfig scripts (#3563)

* feat(protocol): bound note storage loading in the OwnerConfig and FaucetPolicyConfig scripts

* changelog

* remove redundant comments

* fix: address review comments on active_note storage procedures

* fix: use get_bounded_storage in note scripts with a bounded storage layout

---------

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
…el_proc` (#3646)

* chore: make only exec_kernel_proc syscall invokable

* chore: add changelog

* chore: entrypoint -> dispatcher

* chore: update stale entrypoint refs
…3641)

* fix(protocol): verify input-note storage item count in the prologue

* refactor(protocol): name the note storage preimage local offset

Addresses review: promote the magic 0 in locaddr.0 to the
PROCESS_NOTE_STORAGE_PREIMAGE_LOC constant.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(protocol): reword "advised" item count to count from the advice map

Addresses review: "advised" is not used as an adjective in this
codebase; refer to the item count from the advice map instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(protocol): add stack state comment before pipe_elements_preimage_to_memory

Addresses review: document the operand stack state right before the
call to pipe_elements_preimage_to_memory.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(protocol): refer to procedure locals instead of scratch memory

Addresses review: "scratch buffer"/"scratch memory" is not used in
this codebase; refer to memory locals / the preimage buffer instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Apply suggestions from code review

Co-authored-by: Marti <marcin.gorny.94@protonmail.com>

* docs(protocol): note that push_mapvaln also pushes the element count

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
… in `mint_and_send` (#3660)

* refactor(standards): drop redundant dupw/dropw around loc_storew_le in mint_and_send

* changelog

* Update CHANGELOG.md

---------

Co-authored-by: Philipp Gackstatter <PhilippGackstatter@users.noreply.github.com>
…3666)

* fix(standards): reject zero-amount mints in fungible mint_and_send

* changelog

* drop redundant comments
* fix(protocol): validate storage slot type at account creation

* chore: add changelog entry

* chore: re-trigger CI

* Update crates/miden-protocol/asm/kernels/transaction-core/src/account.masm

Co-authored-by: zeapoz <zeapo@pm.me>

* refactor(protocol): validate slot types inside the storage validation loop

Merge the separate validate_storage_slot_types pass into the main
validate_storage loop so storage is validated in a single pass over the
slots, per review feedback.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(protocol): read only native account state in validate_storage

validate_storage mixed the two accessor families: the slot count and the
slot IDs resolved through the active account, while the slot type was read
from the native account. Only the native account's storage is validated this
way, so take every read from the native account.

get_native_slot_id already existed and is identical to get_slot_id apart from
the accessor, and validate_storage was get_slot_id's only caller, so drop the
duplicate.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Apply suggestion from @mmagician

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
Co-authored-by: zeapoz <zeapo@pm.me>
Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
Co-authored-by: Bobbin Threadbare <bobbinth@protonmail.com>
…ation (#3609)

* fix(protocol): assert reserved account state elements are zero at creation

* chore: add changelog entry

* test: collapse header reserved-element assertion into assert_matches if-guard

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test: collapse storage-slot reserved-element assertion into assert_matches if-guard

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(protocol): read the new reserved-element accessors from the native account

Both accessors introduced here resolve through the active account, but their
only callers validate a new native account: validate_new_account for the
account header word and validate_storage for the slot records. Read them from
the native account instead, so neither can be pointed at a foreign account.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
…ccount` (#3657)

* refactor(protocol): read only native account state in validate_new_account

validate_new_account read the account ID, nonce and vault root through the
active account, even though it only ever validates the native account. The
native variants of all three already exist, so switch to them and leave the
active accessors for the procedures that genuinely serve foreign accounts.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Update crates/miden-protocol/asm/kernels/transaction-core/src/prologue.masm

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
… assets (#3650)

* docs(standards): document that note scripts claim only remaining note assets

Standard note scripts move the assets remaining in a note at consumption
time and do not compare them against the note's initial assets info. Per
the discussion in #3601 this is intentional (it enables authorized
deductions such as fees), so document the behavior where notes claim
their assets.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(standards): drop PSWAP-specific warnings, deferred to follow-up fix

The PSWAP offered-amount drain is being fixed directly in a follow-up PR
rather than documented as accepted behavior, so remove the PSWAP hazard
warnings from this docs change. The neutral remaining-vs-initial wording
is kept consistent with the rest of the standards pass, and the SWAP note
(whose loss is consumer-side and not being changed) stays documented here.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Apply suggestions from code review

Co-authored-by: Marti <marcin.gorny.94@protonmail.com>

* Update CHANGELOG.md

Co-authored-by: zeapoz <zeapo@pm.me>

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
Co-authored-by: zeapoz <zeapo@pm.me>
…asset (#3652)

* fix(standards): price PSWAP fills against the note's initial offered asset

The PSWAP note script priced a fill against the offered asset *remaining* in
the note at consumption time rather than the amount the creator funded. A
consumer whose own account exposes an indexed-removal procedure could, via an
earlier helper note in the same transaction, drain most of the offered asset
out of the PSWAP note into their own vault before the PSWAP script ran; the
single-asset assert still passed on the partially-removed slot, so the fill was
priced against the residue and the creator's remainder note absorbed the loss.

Bind the offered amount to the note's initial assets, which the prologue records
at note creation and which removals never affect. `load_offered_asset` now
fetches the note's initial assets, asserts exactly one, and asserts the single
remaining offered asset equals the single initial one word-for-word (asset ID
and value), aborting with the new ERR_PSWAP_OFFERED_ASSET_ALTERED otherwise. Any
pre-removal from a PSWAP note thus aborts the whole transaction. Both the fill
(execute_pswap) and reclaim (handle_reclaim) paths go through this procedure.

This changes the compiled PSWAP note-script MAST root and therefore PSWAP note
recipients/IDs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(standards): trim pswap fix comments

Reduce the inline comments added with the offered-asset binding to match
the surrounding file, and drop the counterfactual/pre-fix narration from
the doc comments and the regression test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Apply suggestions from code review

Co-authored-by: Marti <marcin.gorny.94@protonmail.com>

* refactor(standards): name load_offered_asset local offsets

Replace the bare locaddr.0 / locaddr.8 in load_offered_asset with named
OFFERED_REMAINING_ASSET_PTR / OFFERED_INITIAL_ASSET_PTR constants, matching
the per-proc local-offset convention used elsewhere in the file.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Apply suggestion from @mmagician

* Apply suggestions from code review

Co-authored-by: zeapoz <zeapo@pm.me>
Co-authored-by: Philipp Gackstatter <PhilippGackstatter@users.noreply.github.com>

* fix(standards): use helper_note_id instead of the moved helper_note in PSWAP drain test

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
Co-authored-by: zeapoz <zeapo@pm.me>
Co-authored-by: Philipp Gackstatter <PhilippGackstatter@users.noreply.github.com>
* chore: make exec_kernel_proc reusable across kernels

* chore: add changelog

* fix: memory.rs table

---------

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
* fix(agglayer): make faucet roles rotatable

* test(agglayer): cover faucet role rotation

* test(agglayer): focus faucet RBAC integration coverage
* feat(agglayer): add fee manager roles

* test(agglayer): avoid panic paths in fee role tests

* test(agglayer): cover fee manager role rotation

* refactor(agglayer): clarify fee role fixtures
Export standalone Poseidon2 permutation rows alongside the existing
transaction trace measurements and validate the complete generated
scenario set.

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
…tack padding (#3668)

* fix(standards): stop the MINT note scripts assuming caller-provided stack padding

* changelog

---------

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
* feat(agglayer): add pauser role

* refactor(agglayer): clarify pauser fixtures
* chore: remove account_id::validate re-export

* feat: add version to asset ID

* chore: add changelog

* Update docs/src/asset.md

Co-authored-by: zeapoz <zeapo@pm.me>

* chore: optimize composition extraction

---------

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
Co-authored-by: zeapoz <zeapo@pm.me>
* feat: add version to `Account`

* chore: add changelog

* chore: move version offset to the top

* chore: remove stale panic reference, add header test

* chore: add version field to header, serialize version

* chore: make format

* Revert "chore: add version field to header, serialize version"

This reverts commit f2829d9.
…3696)

* feat: expand note version to 6 bits

* feat: reduce block header version to 8 bits, remove param

* chore: add changelog
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants