Skip to content

Tracking PR for v0.17.0 release - #3518

Open
bobbinth wants to merge 123 commits into
mainfrom
next
Open

Tracking PR for v0.17.0 release#3518
bobbinth wants to merge 123 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>
igamigo and others added 27 commits August 28, 2026 14:51
* refactor: fee sponsorship note tryfrom

* chore: changelog

* fix: scope asset type

* chore: simplify comment

* chore: destructure inner struct

* chore: simplify tests

* chore: remove comment

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

* chore: remove unnecessary comment

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

---------

Co-authored-by: Marti <marti@miden.team>
* fix: reject multi-word PSWAP attachments in get_current_depth

* changelog
* feat(protocol): add validated BatchAccountUpdate constructor

* feat(protocol): add validated ProvenBatch constructor

* feat(protocol): add validating constructor for BlockAccountUpdate

* feat(protocol): add validated BlockBody constructor

* feat(protocol): add BlockProof constructor

* refactor(protocol): extract account detail validation

* refactor(protocol): add explicit validator for BatchAccountUpdate and BlockAccountUpdate

This allows ProvenBatch::new() and BlockBody::new() to avoid cloning
account updates just to validate those.

* fix(protocol): reject notes created and consumed in batch

* fix(protocol): validate full-state block account updates

* fix(protocol): validate merged batch account updates

* refactor(protocol): restrict unchecked constructors

* docs: add validated constructors changelog entry

* fix: broken link in documentation

* refactor: derive proven batch account update keys

* fix(protocol): make validate methods non-public

* fix(protocol): do not derive Default for BlockProof

* fix(protocol): make ProvenBatch::new_unchecked() public

* fix(protocol): validate transaction headers

* fix(protocol): validate proven batch consistency

* fix(protocol): suppress BlockProof default lint

* fix(protocol/proven_batch): import instead of fully qualified type name

* refactor(protocol/proven_batch): remove account update validation from constructor

* fix(protocol): validate block body transaction notes

* refactor(protocol): use storage patch builder in batch tests

* fix(testing): keep private account state caller-owned

* refactor(protocol/proven_batch): remove redundant checks from constructor

* perf(protocol): avoid collecting batch account updates

* fix(protocol): distinguish future note dependencies

* refactor(protocol): add output note header accessor

* refactor(protocol): trust validated block account updates

* fix(protocol): report streamed account count as lower bound

* docs(testing): clarify mock transaction account inputs

* chore(protocol): add some newlines

* refactor(protocol): remove constructor note aggregation

* Update CHANGELOG.md

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

---------

Co-authored-by: Alexander John Lee <77119221+partylikeits1983@users.noreply.github.com>
* fix(agglayer): allow faucet deregistration while paused

* Update CHANGELOG.md

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

---------

Co-authored-by: zeapoz <zeapo@pm.me>
* fix(standards): bound role symbol validation to a 4-bit exponent

`role_symbol::validate_encoding` computed its `ALPHABET_LEN^(num_chars + 1)`
upper bound with a bare `exp`, which the assembler lowers to a 64-row `EXPACC`
sequence. Sixty-four bits do not pin down a field element: `e` and `e + Q` both
fit, so a prover may decompose `e + Q`, pass the terminal-zero check, and land
on `ALPHABET_LEN^(e + 1)` as the bound. That admits a role symbol carrying a
character digit past the length it announces, which is exactly what the
procedure exists to reject.

The assertion above the exponentiation already caps `num_chars` at
`MAX_LENGTH = 12`, so the exponent is at most 13 and four bits carry it.
`exp.u4` commits exactly four rows, which makes the decomposition unique and
costs 60 fewer cycles than the bare `exp`.

Also covers the top of the bound's range: `ALPHABET_LEN^13 + 12` announces the
longest encodable length while carrying a digit past it, so only the upper
bound rejects it. The existing non-canonical cases are all caught by the length
assertion instead, leaving the widest exponent untested.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015bLUPBgD8T6Edt2141yrvQ

* chore: point the changelog entry at this PR

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015bLUPBgD8T6Edt2141yrvQ

* chore: drop the explanatory comments from the diff

The reasoning about the exponent width belongs in the PR description, not
inline next to a one-token change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015bLUPBgD8T6Edt2141yrvQ

* chore: reword the changelog entry

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015bLUPBgD8T6Edt2141yrvQ

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
* fix(agglayer): preserve token registry ownership

* test(agglayer): extract USDC fixtures

* Update crates/miden-agglayer/asm/agglayer/bridge/bridge_config.masm

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

* Update CHANGELOG.md

Co-authored-by: Andrey Khmuro <andrey@polygon.technology>

---------

Co-authored-by: Marti <marti@miden.team>
Co-authored-by: Andrey Khmuro <andrey@polygon.technology>
* chore: bump Cargo version to 1.97

* chore: bump to 1.98 rather than 1.97

1.98 is the current stable (released 2026-08-20) and, like 1.97, carries
the `cargo publish --workspace` deadlock fix from rust-lang/cargo#17071
that the release job needs.

Going one release further adds the `chunks_exact_to_as_chunks` lint on
top of the ones 1.97 reports, so `AccountStorageHeader::try_from_elements`
and the attachment parser move to `as_chunks`. Both call sites already
guard the length, so the behaviour is unchanged - and the array chunks
make the fixed-width indexing that follows statically checked.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015bLUPBgD8T6Edt2141yrvQ

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
* fix(standards): assert the guardian is not an approver in the guarded multisig auth script

* fix changelog entries

* extract the approver public key read into a get_approver_pub_key helper

Signed-off-by: onurinanc <e191322@metu.edu.tr>

---------

Signed-off-by: onurinanc <e191322@metu.edu.tr>
Co-authored-by: Marti <marti@miden.team>
* fix(standards): reject fee-only network account transactions

* fix(standards): count output notes as network account actions

* fix(standards): align network action check with kernel

* fix(standards): preserve network sponsorship actions

* fix(standards): preserve new network account nonce handling

* refactor(standards): simplify network account effect check

* chore(standards): rename network account helper section

* Update CHANGELOG.md

Co-authored-by: Andrey Khmuro <andrey@polygon.technology>

* docs(standards): clarify network account auth docs

---------

Co-authored-by: Andrey Khmuro <andrey@polygon.technology>
* chore: update Miden dependencies to 0.30.0

* fix: reject incomplete proofs before verification

* chore: changelog

* refactor: use upstream program executor

* refactor: use advice stack iterator helper

* refactor: simplify advice input updates

* refactor: configure batch and block provers

* fix: return transaction verification outcomes

* fix: reject unsettled transaction proofs

* fix: reject deferred batch deserialization

* chore: deduplicate changelog

* fix: use Poseidon2 prover defaults

* fix: reject precompiles in batch and block proofs

* chore: track precompile helper adoption

* fix: name precompile proof errors

* fix: validate proven proof states

* fix: validate transaction precompile state
* fix(standards): bound the PSWAP lineage depth increment to u32

* fix(standards): validate the PSWAP attachment and drop the zero-depth assumption

* test(standards): cover the PSWAP depth guards and relative lineage reconstruction

* changelog

* changelog

* fix comments

* fix comments
* fix(standards): reject non-public config notes

* changelog

* docs(standards): document the note type config note scripts accept

* deduplicate comments

* fix(standards): reject non-public config notes

* fix comments

* refactor(standards): move the config notes into note::config

* docs(testing): trim the config note rejection test comments

* changelog
* feat: add miden-objects crate with canonical Protobuf encodings

* refactor(proto): reshuffle protobuf files

* fix: add ExecutionProof wrapper

* fix: add MastForest wrapper

* fix: cargo shear

* fix: extract generic PublicKey

* fix: extract generic Signature

* fix: remove redundant checks from conversion code

* fix: fix conversion compile errors after rebase

* chore: update CHANGELOG

* fix: fix compile errors after rebase

* chore: allow duplicate protobuf build dependencies

* chore: remove schema tests

* fix(objects): adapt conversions to validated constructors

* refactor(objects): consolidate protobuf primitive types

* test(objects): cover missing protobuf block numbers

* refactor(objects): align protobuf messages with domain types

* test(objects): cover block body conversion validation

* fix(objects): make account conversions lossless

* test(objects): cover invalid account nonce conversion

* perf(account): expose ordered storage patch iteration

* test(account): make storage patch order expectation explicit

* fix(objects): address protobuf conversion clippy warnings

* refactor(objects): align account witness protobuf with domain type

* test(objects): decouple account witness error assertion

* test(objects): remove redundant account witness fixture update

* fix(objects): adapt block protobuf after rebase

* feat(objects): version account header protobuf

* feat(objects): version note metadata protobuf

* feat(objects): version block header protobuf

* feat(objects): add PartialSmt protobuf conversions

* refactor(objects): clarify storage slot type conversion

* refactor(objects): simplify protobuf decoding

* fix(objects): complete protobuf type elision

* test(objects): clarify invalid partial smt cases

* refactor: clarify feature check package list

* fix(objects): preserve note attachments error context

* refactor(objects): clarify protobuf primitive variants

* refactor(objects): structure protobuf asset identifiers

* refactor(objects): align protobuf note transactions

* fix(objects): remove redundant asset test clones

* fix(objects): remove legacy protobuf asset schema

* refactor(objects): add protobuf account versions

* refactor(objects): flatten protobuf block version

* refactor(objects): flatten protobuf note version

* refactor(objects): add protobuf asset version

* fix(objects): adapt partial SMT protobuf to miden-crypto 0.30

* fix(objects): update execution proof test fixtures

* fix(objects): update partial SMT error assertions

* style(objects): format partial SMT imports

* fix(objects): preserve partial SMT depth boundaries

* fix(objects): keep note type enum consistent with upstream type
* feat(protocol): expose transaction input protobuf parts

* feat(objects): add account config protobufs

* feat(objects): add transaction args protobufs

* feat(objects): add transaction inputs protobuf

* fix(protocol): satisfy transaction input lint

* docs: add transaction inputs protobuf changelog

* refactor(objects): clean up protobuf conversions

* test(objects): clean up protobuf conversion tests

* docs: correct transaction inputs changelog

* fix: remove seen_ids in PartialVault::try_from_parts()

* fix: invalid felt test

* fix: use assert_matches! in tests

* fix: clippy

* Revert "fix: remove seen_ids in PartialVault::try_from_parts()"

This reverts commit d934eb9.

* fix(objects): update protobuf conversions for dependency changes

* fix: VM upgrade compilation fixes

---------

Co-authored-by: Codex (Opus) <noreply@anthropic.com>
* fix(standards): reject delay-only multisig procedure policies

* changelog

* fix comments

---------

Co-authored-by: Marti <marti@miden.team>
* chore: keep MASM inline comments to what the code does

Extends rule 6 of the masm-inline-comments skill: an inline comment is one
line about what the next block does or which invariant it relies on, not
design rationale, PR-review reasoning, or a justification of step ordering,
which belong in the procedure's doc comment. Prompted by review on #3798,
where such prose had to be trimmed by hand.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KkQzFtRjyDwQ7iVtRbsHsn

* Apply suggestion from @zeapoz

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

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
Co-authored-by: zeapoz <zeapo@pm.me>
A reviewer rewrote the descriptions of the fee-stack port PRs, and later
updates must build on those live bodies instead of re-amending the original
drafts. The skill spells out the procedure: fetch the live text right before
editing, treat every difference as a deliberate human edit, and make only
targeted corrections that keep the person's structure and omissions.


Claude-Session: https://claude.ai/code/session_01KkQzFtRjyDwQ7iVtRbsHsn

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

* fix(standards): bound transfer policy dispatch to the reference block

* test(standards): pin the dispatcher expiration limit on both transfer callbacks

* docs(standards): describe the dispatcher expiration limit on transfer policies

* changelog

* remove redundant comments

* test(standards): update transfer policy fixture callbacks

* chore: update note cost tables

---------

Co-authored-by: Alexander John Lee <77119221+partylikeits1983@users.noreply.github.com>
Co-authored-by: riemann <aleqvids@gmail.com>
* docs: clarify FPI expiration requirements

* Update crates/miden-standards/asm/standards/expiration.masm

* Update crates/miden-standards/src/account/policies/transfer/mod.rs

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

* docs: address FPI expiration review comments

---------

Co-authored-by: Marti <marti@miden.team>
* chore: update Miden VM dependencies to 0.32.0

* chore: use released Miden VM dependencies

* chore: Changelog
#3808)

* fix(standards): pin the fee payment to the native asset at par

`fee::pay_fee` built the TX_FEE note from a caller-supplied conversion
info word and paid `ceil(fee_amount * rate_num / rate_den)` of the named
faucet's asset, checking neither the faucet nor the rate. Nothing
downstream re-checks the fee note either - the transaction epilogue and
the batch and block kernels contain no fee logic - so the authentication
procedure is the only place the paid amount is decided, and any
authorized transaction could move an arbitrary amount of an arbitrary
fungible asset out of the vault as a fee.

The conversion has nothing to convert: the computed fee is always
denominated in the chain's single native fee asset (`ProtocolConfig`,
verified against the reference block), and `verification_base_fee` is a
per-network constant copied from the parent block, so there is no
dynamic pricing either. Every production call site already commits
`FeeConversionInfo::one_to_one`.

`pay_fee` now asserts that the committed conversion info equals
`native_conversion_info`, which pins the payment faucet and the rate
together and makes the paid amount exactly the computed fee.

`convert_amount` stays public and keeps its coverage, moved to direct
invocation from a transaction script now that `pay_fee` only ever calls
it at 1/1.

Closes #3763.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0186Lb3N8KP4N75jFtWab3X6

* docs(standards): trim the fee comments

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0186Lb3N8KP4N75jFtWab3X6

* Apply batched suggestions from code review

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

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
* let user fungible faucets hold the native fee asset

* unit-test the user fungible faucet factories

* prove a user faucet pays its own fee end to end

* scope the network-faucet wallet note to steady state

* drop the fee-asset tests and inline commentary

* Apply suggestion from @mmagician

---------

Co-authored-by: Marti <marti@miden.team>
@bobbinth
bobbinth marked this pull request as ready for review September 5, 2026 15:53
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.