Skip to content
Draft
Show file tree
Hide file tree
Changes from 61 commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
0bf1295
initial integration
onurinanc Mar 10, 2026
ae87735
update signer management to the current version
onurinanc Mar 10, 2026
a9ccc01
refactor common procedures
onurinanc Mar 10, 2026
3553e86
refactor compute tx threshold
onurinanc Mar 10, 2026
5f35fde
before the timelock guard
onurinanc Mar 11, 2026
dd915b5
add new tests
onurinanc Mar 12, 2026
d1890f7
rstest
onurinanc Mar 12, 2026
7efc3bb
add tx expiration delta and timestamp and remove epoch
onurinanc Mar 13, 2026
173cb2a
add modules
onurinanc Mar 13, 2026
fac9d7c
rename timelock controller
onurinanc Mar 16, 2026
94deee4
rename guard -> controller
onurinanc Mar 16, 2026
66a91a0
add get_price test stub
onurinanc Mar 16, 2026
87f52cb
add tier validations and <= assertions
onurinanc Mar 16, 2026
bff4a6a
fix tier thresholds logic
onurinanc Mar 16, 2026
8909f66
add procedure policies
onurinanc Mar 19, 2026
95edc8e
refactor procedure_roots -> procedure_policies
onurinanc Mar 19, 2026
1d7e0e8
move procedure_policies to multisig
onurinanc Mar 19, 2026
4223de9
cleanup tests
onurinanc Mar 19, 2026
145ad07
refactor AuthMultisigConfig
onurinanc Mar 19, 2026
2c727d3
remove redundant tests
onurinanc Mar 23, 2026
f4d297b
cleanup
onurinanc Mar 23, 2026
c406cb6
integrate oracle
onurinanc Mar 23, 2026
9758f58
refactor oracle
onurinanc Mar 23, 2026
a1afd25
merge
onurinanc Mar 23, 2026
0e6d2e0
procedure_policies -> procedure_thresholds
onurinanc Mar 27, 2026
e95c470
Merge remote-tracking branch 'upstream/next' into onur-auth-multisig-…
onurinanc Mar 27, 2026
f933e48
refactor multisig smart
onurinanc Mar 30, 2026
8db09b8
merge next
onurinanc Apr 1, 2026
a56f487
add next version of procedure policies
onurinanc Apr 1, 2026
477ffe2
multisig next
onurinanc Apr 1, 2026
413908b
fix proc
onurinanc Apr 1, 2026
6a0c37e
fix
onurinanc Apr 1, 2026
0564472
refactor multisig
onurinanc Apr 1, 2026
e242ed8
fix
onurinanc Apr 1, 2026
18ec223
fix comments
onurinanc Apr 1, 2026
76808aa
refactor
onurinanc Apr 2, 2026
a0170ba
cleanup multisig.masm
onurinanc Apr 3, 2026
6639732
remove redundant tests
onurinanc Apr 3, 2026
2087bec
refactor mock chain
onurinanc Apr 3, 2026
301e14f
fmt
onurinanc Apr 3, 2026
ecc7c0e
change folder location
onurinanc Apr 3, 2026
a4c68d8
fix timelock_controller
onurinanc Apr 3, 2026
7cd88e7
add masm documentation
onurinanc Apr 3, 2026
2589218
simplify masm
onurinanc Apr 3, 2026
636c32a
remove redundant helper
onurinanc Apr 3, 2026
e62526c
add finalize timelock helpers
onurinanc Apr 3, 2026
08a253e
fix
onurinanc Apr 3, 2026
8d82028
add timelock controller
onurinanc Apr 3, 2026
004d34a
update spending limits
onurinanc Apr 8, 2026
77cb6f8
resolve guardian conflicts
onurinanc Apr 8, 2026
5dc1902
fmt
onurinanc Apr 8, 2026
ed2b1ca
remove locals
onurinanc Apr 8, 2026
6e939e5
fix spending limit window
onurinanc Apr 10, 2026
8a3a070
add masm conventions
onurinanc Apr 10, 2026
589cb29
add untracked policy for get price
onurinanc Apr 10, 2026
8ffeb0a
add documentation
onurinanc Apr 11, 2026
9dad95b
initial merge basic and network accounts
onurinanc May 7, 2026
d817aa7
clippy
onurinanc May 8, 2026
7d84b08
changelog
onurinanc May 8, 2026
df4dc5a
merge next
onurinanc May 8, 2026
b09c85f
refactor storage slots
onurinanc May 8, 2026
449fcd6
Merge branch 'next' into merge-basic-network-faucets
onurinanc May 11, 2026
7176fe4
apply review fixes
onurinanc May 11, 2026
adf50b1
Merge branch 'next' into merge-basic-network-faucets
onurinanc May 12, 2026
8f3f2a2
apply review fixes
onurinanc May 12, 2026
8b880de
Merge remote-tracking branch 'origin/merge-basic-network-faucets' int…
onurinanc May 12, 2026
b175c0c
merge next
onurinanc May 12, 2026
bf4a12d
fmt
onurinanc May 12, 2026
c270965
merge next
onurinanc May 12, 2026
7b0e3fd
fix documentation
onurinanc May 12, 2026
e453e95
Merge pull request #2 from onurinanc/pr-2890
onurinanc May 13, 2026
3692fc3
Merge branch '0xMiden:next' into next
onurinanc May 15, 2026
8271ed4
Merge branch '0xMiden:next' into next
onurinanc May 15, 2026
43d7ca3
merge
onurinanc May 21, 2026
1dc15d6
Merge branch '0xMiden:next' into next
onurinanc May 21, 2026
904ee12
migration
onurinanc May 22, 2026
3834ade
add compositions
onurinanc May 22, 2026
be351e1
merge next
onurinanc May 22, 2026
aa24fed
clippy
onurinanc May 22, 2026
b21e888
Merge remote-tracking branch 'origin/next' into onur-auth-multisig-smart
onurinanc Jun 3, 2026
de4e418
merge next
onurinanc Jun 3, 2026
472bf97
rename timelock controller -> delayed execution
onurinanc Jun 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
- [BREAKING] Removed unused `payback_attachment` from `SwapNoteStorage` and `attachment` from `MintNoteStorage` ([#2789](https://github.com/0xMiden/protocol/pull/2789)).
- Automatically enable `concurrent` feature in `miden-tx` for `std` context ([#2791](https://github.com/0xMiden/protocol/pull/2791)).
- Added foundations for `AuthMultisigSmart` ([#2806](https://github.com/0xMiden/protocol/pull/2806)).
- Extended `AuthMultisigSmart` with spending-limit tiers, oracle-priced amount conversion, a timelock-controlled propose/cancel/execute flow, and `AuthMultisigSmartPresets` opinionated policy bundles ([#2973](https://github.com/0xMiden/protocol/pull/2973)).
- Added `AuthNetworkAccount` auth component that rejects transactions which execute a tx script or consume input notes outside of a fixed allowlist of note script roots ([#2817](https://github.com/0xMiden/protocol/pull/2817)).
- Added standardized `NetworkAccountNoteAllowlist` slot for detecting network accounts ([#2883](https://github.com/0xMiden/protocol/pull/2883)).
- Added trace row counts to `bench-tx.json` ([#2794](https://github.com/0xMiden/protocol/pull/2794)).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,26 @@

use miden::standards::auth::multisig
use miden::standards::auth::multisig_smart
use miden::standards::auth::multisig_smart::oracle
use miden::standards::auth::multisig_smart::spending_limits
use miden::standards::auth::multisig_smart::timelock_controller

pub use multisig::get_threshold_and_num_approvers
pub use multisig::get_signer_at
pub use multisig::is_signer
pub use multisig_smart::set_procedure_policy
pub use multisig_smart::update_signers_and_threshold
pub use timelock_controller::update_timelock_controller
pub use timelock_controller::propose_transaction
pub use timelock_controller::cancel_transaction_proposal
pub use timelock_controller::cancel_and_propose_new_transaction
pub use timelock_controller::execute_proposed_transaction

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Afaict, transaction proposal and execution lives in timelock_controller because this relates to the idea of "delayed" execution, right? This connection doesn't click for me that much, so I wonder if we should rename this module. Maybe miden::standards::auth::multisig_smart::delayed_execution?

pub use spending_limits::update_spending_window_policy
pub use spending_limits::update_spending_limits
pub use spending_limits::update_threshold_config
pub use oracle::update_get_price_untracked_policy
pub use oracle::update_oracle_config_and_proc_root


#! Authenticate a transaction using multisig smart-policy rules.
#!
Expand Down
127 changes: 93 additions & 34 deletions crates/miden-standards/asm/standards/auth/multisig_smart/mod.masm
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use miden::standards::auth::multisig
use miden::standards::auth::multisig::APPROVER_PUBLIC_KEYS_SLOT
use miden::standards::auth::multisig::APPROVER_SCHEME_ID_SLOT
use miden::standards::auth::multisig::THRESHOLD_CONFIG_SLOT
use miden::standards::auth::multisig_smart::spending_limits
use miden::standards::auth::multisig_smart::timelock_controller
use miden::standards::auth::signature
use miden::standards::auth::tx_policy

Expand Down Expand Up @@ -59,6 +61,8 @@ const ERR_INVALID_NOTE_RESTRICTIONS = "procedure policy note restrictions must b

const ERR_INSUFFICIENT_SIGNATURES = "insufficient number of signatures"

const ERR_EXECUTE_PATH_MISMATCH = "execute path must match delay requirement"

# LOCAL ADDRESSES (set_procedure_policy)
# =================================================================================================

Expand Down Expand Up @@ -408,40 +412,35 @@ end
#! Enforces the procedure-policy for the current transaction:
#! - asserts each called procedure supports the active execution mode,
#! - asserts the union of note restrictions against the transaction's input/output notes,
#! - returns the effective threshold required by the called procedure policies.
#! - returns the effective threshold required by the called procedure policies and
#! whether any policy required the delayed-execution mode.
#!
#! Always uses IMMEDIATE_EXECUTION_MODE; procedures whose policies require the delayed mode
#! panic via [`compute_called_proc_policy`] because this component has no timelock.
#! The active execution mode is read from [`timelock_controller::is_execute_path`]: when
#! the timelock controller's `PENDING_EXECUTE` slot is set this transaction is on the
#! delayed-execute path (mode = 1); otherwise it is on the immediate path (mode = 0).
#!
#! Inputs: [default_threshold]
#! Outputs: [policy_threshold]
#! Outputs: [policy_threshold, policy_requires_delay]
#!
#! Where:
#! - default_threshold is forwarded to [`compute_called_proc_policy`] as the per-procedure
#! contribution for any called procedure without an explicit policy.
#! - policy_requires_delay is 1 when any called procedure's policy explicitly requires the
#! delayed execution mode (used downstream to enforce [`ERR_EXECUTE_PATH_MISMATCH`]).
#!
#! Invocation: exec
#!
#! NOTE: This procedure is a temporary form. Once the TimelockedAccount feature lands, the
#! hardcoded IMMEDIATE_EXECUTION_MODE push will be replaced with a call to
#! `timelock_controller::execution_mode`, and the procedure will also expose
#! `policy_requires_delay` for downstream enforcement.
proc enforce_procedure_policy(default_threshold: u32)
push.IMMEDIATE_EXECUTION_MODE
exec.timelock_controller::is_execute_path
# => [execution_mode, default_threshold]

exec.compute_called_proc_policy
# => [policy_threshold, policy_requires_delay, note_restrictions]

# policy_requires_delay is always 0 on IMMEDIATE_EXECUTION_MODE; drop it.
swap drop
# => [policy_threshold, note_restrictions]

swap
# => [note_restrictions, policy_threshold]
movup.2
# => [note_restrictions, policy_threshold, policy_requires_delay]

exec.enforce_note_restrictions
# => [policy_threshold]
# => [policy_threshold, policy_requires_delay]
end

#! Asserts that all configured smart per-procedure policies are valid for num_approvers.
Expand Down Expand Up @@ -747,25 +746,41 @@ end
#! Locals:
#! 0: policy_threshold
#! 1: default_threshold
#! 2: policy_requires_delay
#! 3: spending_threshold
#! 4: spending_requires_delay
#! 5: num_verified_signatures
#!
#! Flow:
#! 1. Compute spending policy (amount/tier-derived threshold + requires_delay flag).
#! 2. Build the tx summary commitment used for signing and timelock proposals.
#! 3. Enforce per-procedure policy (note restrictions + policy threshold + delay flag).
#! 4. Verify approver signatures.
#! 5. Combine the policy threshold with the spending threshold via `u32max`, fall back to
#! `default_threshold` when both are zero, and assert `num_verified_signatures` meets it.
#! 6. After signature verification, enforce that the active execute-path matches whether any
#! consumed policy (procedure or spending) required the delayed mode. Running this check
#! only after verification lets a caller still produce the TX_SUMMARY_COMMITMENT needed for
#! a propose/execute round-trip from an unauthorized dry-run.
#! 7. Finalize any pending timelock propose/cancel/execute slots against the verified sig count
#! and the union of `policy_requires_delay`/`spending_requires_delay`.
#!
#! Invocation: call
#!
#! NOTE: This procedure is a temporary form covering signer verification and
#! per-procedure policy enforcement. The following sections will be added:
#! - Spending Limits + Amount-Based Thresholds: a prologue that calls
#! `exec.spending_limits::compute_spending_policy` to derive a spending-derived threshold and
#! `spending_requires_delay` flag, and combines it via `u32max` with `policy_threshold` before
#! the final `compute_tx_threshold` fallback.
#! - TimelockedAccount: after signature verification, assert the execute-path vs.
#! `policy_requires_delay`/`spending_requires_delay` consistency (restoring
#! `ERR_EXECUTE_PATH_MISMATCH`), then call
#! `exec.timelock_controller::finalize_timelock_proposals` to advance any pending
#! propose/cancel/execute state.
@locals(2)
@locals(6)
pub proc auth_tx(salt: word)
exec.native_account::incr_nonce drop
# => [SALT]

# ------ Computing spending policy ------
exec.spending_limits::compute_spending_policy
# => [spending_threshold, spending_requires_delay, SALT]

loc_store.3
# => [spending_requires_delay, SALT]

loc_store.4
# => [SALT]

# ------ Computing transaction summary ------
exec.auth::create_tx_summary
# => [ACCOUNT_DELTA_COMMITMENT, INPUT_NOTES_COMMITMENT, OUTPUT_NOTES_COMMITMENT, SALT]
Expand All @@ -787,9 +802,12 @@ pub proc auth_tx(salt: word)

# ------ Enforcing procedure policy (consumes default_threshold) ------
exec.enforce_procedure_policy
# => [policy_threshold, num_of_approvers, TX_SUMMARY_COMMITMENT]
# => [policy_threshold, policy_requires_delay, num_of_approvers, TX_SUMMARY_COMMITMENT]

loc_store.0
# => [policy_requires_delay, num_of_approvers, TX_SUMMARY_COMMITMENT]

loc_store.2
# => [num_of_approvers, TX_SUMMARY_COMMITMENT]

# ------ Verifying approver signatures ------
Expand All @@ -798,12 +816,22 @@ pub proc auth_tx(salt: word)
exec.::miden::standards::auth::signature::verify_signatures
# => [num_verified_signatures, TX_SUMMARY_COMMITMENT]

dup loc_store.5
# => [num_verified_signatures, TX_SUMMARY_COMMITMENT]

# ------ Computing final transaction threshold ------
# If no non-auth procedure was called, `policy_threshold` is 0 and `compute_tx_threshold`
# falls back to `default_threshold`; otherwise it returns the policy max directly.
# The per-procedure pass (`compute_called_proc_policy`) has already folded `default_threshold`
# into every called procedure that lacked an explicit policy, so `policy_threshold` carries
# the procedure-side contribution. Spending limits add an independent amount-derived bound;
# combine the two via `u32max`. When both are zero (no called procedures and no spending),
# `compute_tx_threshold` falls back to `default_threshold`.
loc_load.0
loc_load.3 u32max
# => [policy_or_spending_threshold, num_verified_signatures, TX_SUMMARY_COMMITMENT]

# compute_tx_threshold expects default_threshold on top, policy_threshold underneath.
loc_load.1
# => [default_threshold, policy_threshold, num_verified_signatures, TX_SUMMARY_COMMITMENT]
# => [default_threshold, policy_or_spending_threshold, num_verified_signatures, TX_SUMMARY_COMMITMENT]

exec.compute_tx_threshold

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: We're computing part of the threshold inline here and part of it in compute_tx_threshold. To make this easier to follow, I'd also move the u32max logic into compute_tx_threshold.

# => [transaction_threshold, num_verified_signatures, TX_SUMMARY_COMMITMENT]
Expand All @@ -815,4 +843,35 @@ pub proc auth_tx(salt: word)
emit.AUTH_UNAUTHORIZED_EVENT
push.0 assert.err=ERR_INSUFFICIENT_SIGNATURES
end

# ------ Enforcing execute-path consistency ------
# If a *procedure* policy demands the delayed execution mode, the transaction must already be
# on the execute path (proposed earlier, now being executed). Spending limits use their own
# `requires_delay` flag to decide whether to advance timelock proposals (below) but do not
# by themselves veto an immediate-mode transaction — that distinction belongs to the policy
# layer and is consistent with the pre-foundation behavior we are preserving here.
loc_load.2
# => [policy_requires_delay, TX_SUMMARY_COMMITMENT]

exec.timelock_controller::is_execute_path
# => [is_execute_path, policy_requires_delay, TX_SUMMARY_COMMITMENT]

# is_valid = NOT(policy_requires_delay) OR is_execute_path
swap not or
# => [is_valid_execute_path, TX_SUMMARY_COMMITMENT]

assert.err=ERR_EXECUTE_PATH_MISMATCH
# => [TX_SUMMARY_COMMITMENT]

# ------ Finalizing timelock proposals ------
# The timelock controller consumes the union of policy- and spending-derived delay flags so
# that high-spending transactions still advance any pending propose/cancel/execute slots.
loc_load.2 loc_load.4 or
# => [requires_delay, TX_SUMMARY_COMMITMENT]

loc_load.5
# => [num_verified_signatures, requires_delay, TX_SUMMARY_COMMITMENT]

exec.timelock_controller::finalize_timelock_proposals
# => [TX_SUMMARY_COMMITMENT]
end
Loading
Loading